From 7229a1935fff089be50f0efcd52d0e76869361be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 1 Jan 2022 13:14:53 +0100 Subject: [PATCH] some details about shuffle of words and multizetas --- src/sage/combinat/words/shuffle_product.py | 80 +++++++--------------- src/sage/modular/multiple_zeta.py | 14 ++-- 2 files changed, 31 insertions(+), 63 deletions(-) diff --git a/src/sage/combinat/words/shuffle_product.py b/src/sage/combinat/words/shuffle_product.py index 23d199ec75f..101e7ca695c 100644 --- a/src/sage/combinat/words/shuffle_product.py +++ b/src/sage/combinat/words/shuffle_product.py @@ -125,7 +125,6 @@ def __contains__(self, x): sage: x*w in w.shuffle(x) True """ - from sage.combinat.words.word import Word if not isinstance(x, Word_class): return False if x.length() != self._w1.length() + self._w2.length(): @@ -177,86 +176,57 @@ def cardinality(self): len_w2 = self._w2.length() return binomial(len_w1 + len_w2, len_w1) - def _proc(self, vect): + def __iter__(self): """ - Return the shuffle of ``w1`` with ``w2`` with 01-vector - ``vect``. - - The 01-vector of a shuffle is a list of 0s and 1s whose - length is the sum of the lengths of ``w1`` and ``w2``, - and whose `k`-th entry is `1` if the `k`-th letter of - the shuffle is taken from ``w1`` and `0` if it is taken - from ``w2``. + Return an iterator for the words in the + shuffle product of ``w1`` and ``w2``. EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 sage: w, u = map(Words("abcd"), ["ab", "cd"]) sage: S = ShuffleProduct_w1w2(w,u) - sage: S._proc([0,1,0,1]) - word: cadb - sage: S._proc([1,1,0,0]) - word: abcd + sage: S.list() #indirect test + [word: abcd, word: acbd, word: acdb, word: cabd, + word: cadb, word: cdab] sage: I = Composition([1, 1]) sage: J = Composition([2]) sage: S = ShuffleProduct_w1w2(I, J) - sage: S._proc([1,0,1]) - [1, 2, 1] + sage: next(iter(S)) + [1, 1, 2] TESTS: - Sage is no longer confused by a too-restrictive parent - of `I` when shuffling two compositions `I` and `J` - (cf. :trac:`15131`):: + Sage is no longer confused by a too-restrictive parent of `I` + when shuffling compositions `I` and `J` (cf. :trac:`15131`):: sage: I = Compositions(2)([1, 1]) sage: J = Composition([2]) sage: S = ShuffleProduct_w1w2(I, J) - sage: S._proc([1,0,1]) - [1, 2, 1] sage: S.list() [[1, 1, 2], [1, 2, 1], [2, 1, 1]] """ - i1 = -1 - i2 = -1 - res = [] - for v in vect: - if v == 1: - i1 += 1 - res.append(self._w1[i1]) - else: - i2 += 1 - res.append(self._w2[i2]) + n1 = len(self._w1) + n2 = len(self._w2) + w1_parent = self._w1.parent() + use_w1_parent = True try: - return self._w1.parent()(res, check=self._check) + w1_parent(list(self._w1) + list(self._w2), check=self._check) except (ValueError, TypeError): - # Special situation: the parent of w1 is too - # restrictive to be cast on res. + use_w1_parent = False if isinstance(self._w1, Composition): - return Composition(res) + large_parent = Composition elif isinstance(self._w1, Word_class): - return Word(res) - return res - - def __iter__(self): - """ - Return an iterator for the words in the - shuffle product of ``w1`` and ``w2``. - - EXAMPLES:: - - sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 - sage: w, u = map(Words("abcd"), ["ab", "cd"]) - sage: S = ShuffleProduct_w1w2(w,u) - sage: S.list() #indirect test - [word: abcd, word: acbd, word: acdb, word: cabd, - word: cadb, word: cdab] - """ - n1 = len(self._w1) - n2 = len(self._w2) + large_parent = Word for iv in IntegerVectors(n1, n1 + n2, max_part=1): - yield self._proc(iv) + it1 = iter(self._w1) + it2 = iter(self._w2) + w = [next(it1) if v else next(it2) for v in iv] + if use_w1_parent: + yield w1_parent(w, check=self._check) + else: + yield large_parent(w) class ShuffleProduct_shifted(ShuffleProduct_w1w2): diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 561ddccd5cd..ebe48c205f0 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -1005,11 +1005,10 @@ def _element_constructor_(self, x): W = self.basis().keys() if isinstance(x, list): x = tuple(x) - return self.monomial(W(x, check=False)) + return self._monomial(W(x, check=False)) elif isinstance(parent(x), Multizetas_iterated): return x.composition() - else: - raise TypeError('invalid input for building a multizeta value') + raise TypeError('invalid input for building a multizeta value') def algebra_generators(self, n): """ @@ -1544,8 +1543,7 @@ def product_on_basis(self, w1, w2): sage: M.product_on_basis(y,x) I(10110) + 3*I(11010) + 6*I(11100) """ - B = self.basis() - return sum(B[u] for u in shuffle(w1, w2, False)) + return self.sum(self._monomial(u) for u in shuffle(w1, w2, False)) def half_product_on_basis(self, w1, w2): r""" @@ -1914,7 +1912,7 @@ def _element_constructor_(self, x): W = self.basis().keys() if isinstance(x, list): x = tuple(x) - return self.monomial(W(x, check=False)) + return self._monomial(W(x, check=False)) P = x.parent() if isinstance(P, Multizetas_iterated): @@ -2188,7 +2186,7 @@ def _element_constructor_(self, x): if w[0] == w[-1] or (len(w) >= 4 and all(x == w[1] for x in w[2:-1])): return self.zero() - return self.monomial(w) + return self._monomial(w) def dual_on_basis(self, w): """ @@ -2257,7 +2255,7 @@ def reversal_on_basis(self, w): if w[0] == 0 and w[-1] == 1: return self(w) W = self.basis().keys() - image = self.monomial(W(list(reversed(w)), check=False)) + image = self._monomial(W(list(reversed(w)), check=False)) return -image if len(w) % 2 else image @lazy_attribute