Skip to content

Commit

Permalink
Trac #33102: some details in shuffle and multizeta
Browse files Browse the repository at this point in the history
trying to make the shuffle simpler and the product of MZV slightly
faster

URL: https://trac.sagemath.org/33102
Reported by: chapoton
Ticket author(s): Frédéric Chapoton
Reviewer(s): David Coudert
  • Loading branch information
Release Manager committed Feb 12, 2022
2 parents 09de266 + 7229a19 commit d4466d8
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 63 deletions.
80 changes: 25 additions & 55 deletions src/sage/combinat/words/shuffle_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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):
Expand Down
14 changes: 6 additions & 8 deletions src/sage/modular/multiple_zeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit d4466d8

Please sign in to comment.