Skip to content

Commit 1ad688e

Browse files
author
Release Manager
committed
Trac #32962: some details in Dyck words
mostly micro-optimisations URL: https://trac.sagemath.org/32962 Reported by: chapoton Ticket author(s): Frédéric Chapoton Reviewer(s): Samuel Lelièvre
2 parents 0ed9608 + 8a08e2e commit 1ad688e

File tree

1 file changed

+54
-39
lines changed

1 file changed

+54
-39
lines changed

src/sage/combinat/dyck_word.py

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
# https://www.gnu.org/licenses/
7979
# ****************************************************************************
8080
from __future__ import annotations
81+
from typing import Iterator
8182

8283
from .combinat import CombinatorialElement, catalan_number
8384
from sage.combinat.combinatorial_map import combinatorial_map
@@ -141,10 +142,9 @@ def replace_parens(x):
141142
"""
142143
if x == '(':
143144
return open_symbol
144-
elif x == ')':
145+
if x == ')':
145146
return close_symbol
146-
else:
147-
raise ValueError
147+
raise ValueError
148148

149149

150150
def replace_symbols(x):
@@ -185,10 +185,9 @@ def replace_symbols(x):
185185
"""
186186
if x == open_symbol:
187187
return '('
188-
elif x == close_symbol:
188+
if x == close_symbol:
189189
return ')'
190-
else:
191-
raise ValueError
190+
raise ValueError
192191

193192

194193
class DyckWord(CombinatorialElement):
@@ -605,7 +604,7 @@ def __str__(self) -> str:
605604
sage: print(DyckWord([1, 1, 0, 0]))
606605
(())
607606
"""
608-
return "".join(map(replace_symbols, [x for x in self]))
607+
return "".join(replace_symbols(x) for x in self)
609608

610609
def to_path_string(self, unicode=False) -> str:
611610
r"""
@@ -1756,7 +1755,27 @@ def tamari_interval(self, other):
17561755
from sage.combinat.interval_posets import TamariIntervalPosets
17571756
return TamariIntervalPosets.from_dyck_words(self, other)
17581757

1759-
def to_area_sequence(self) -> list:
1758+
def _area_sequence_iter(self) -> Iterator[int]:
1759+
"""
1760+
Return an iterator producing the area sequence.
1761+
1762+
.. SEEALSO:: :meth:`to_area_sequence`
1763+
1764+
EXAMPLES::
1765+
1766+
sage: d = DyckWord([1, 0, 1, 0])
1767+
sage: [a for a in d._area_sequence_iter()]
1768+
[0, 0]
1769+
"""
1770+
a = 0
1771+
for move in self:
1772+
if move == open_symbol:
1773+
yield a
1774+
a += 1
1775+
else:
1776+
a -= 1
1777+
1778+
def to_area_sequence(self) -> list[int]:
17601779
r"""
17611780
Return the area sequence of the Dyck word ``self``.
17621781
@@ -1806,15 +1825,7 @@ def to_area_sequence(self) -> list:
18061825
sage: DyckWord([1,1,0,1,0,0,1,1,0,1,0,1,0,0]).to_area_sequence()
18071826
[0, 1, 1, 0, 1, 1, 1]
18081827
"""
1809-
seq = []
1810-
a = 0
1811-
for move in self:
1812-
if move == open_symbol:
1813-
seq.append(a)
1814-
a += 1
1815-
else:
1816-
a -= 1
1817-
return seq
1828+
return list(self._area_sequence_iter())
18181829

18191830

18201831
class DyckWord_complete(DyckWord):
@@ -1927,8 +1938,8 @@ def list_parking_functions(self):
19271938
sage: DyckWord([1,0,1,0,1,0]).list_parking_functions()
19281939
Standard permutations of 3
19291940
"""
1930-
alist = self.to_area_sequence()
1931-
return Permutations([i - alist[i] + 1 for i in range(len(alist))])
1941+
alist = self._area_sequence_iter()
1942+
return Permutations([i - ai + 1 for i, ai in enumerate(alist)])
19321943
# TODO: upon implementation of ParkingFunction class
19331944
# map(ParkingFunction, Permutations([i - alist[i]+1 for i in range(len(alist))]))
19341945

@@ -1956,9 +1967,9 @@ def reading_permutation(self) -> Permutation:
19561967
sage: DyckWord([1,0,1,1,0,0,1,0]).reading_permutation()
19571968
[3, 4, 2, 1]
19581969
"""
1959-
alist = self.to_area_sequence()
1960-
if not alist:
1970+
if not self:
19611971
return Permutation([]) # type: ignore
1972+
alist = self.to_area_sequence()
19621973
m = max(alist)
19631974
p1 = Word([m - alist[-i - 1]
19641975
for i in range(len(alist))]).standard_permutation()
@@ -2075,10 +2086,10 @@ def to_312_avoiding_permutation(self) -> Permutation:
20752086
True
20762087
"""
20772088
n = self.semilength()
2078-
area = self.to_area_sequence()
2089+
area = self._area_sequence_iter()
20792090
pi = Permutations(n).one()
2080-
for j in range(n):
2081-
for i in range(area[j]):
2091+
for j, aj in enumerate(area):
2092+
for i in range(aj):
20822093
pi = pi.apply_simple_reflection(j - i)
20832094
return pi
20842095

@@ -2793,9 +2804,9 @@ def area_dinv_to_bounce_area_map(self) -> DyckWord:
27932804
sage: DyckWord([1,0,1,0]).area_dinv_to_bounce_area_map()
27942805
[1, 1, 0, 0]
27952806
"""
2796-
a = self.to_area_sequence()
2797-
if not a:
2807+
if not self:
27982808
return self
2809+
a = self.to_area_sequence()
27992810
a.reverse()
28002811
image = []
28012812
for i in range(max(a), -2, -1):
@@ -2844,13 +2855,13 @@ def bounce_area_to_area_dinv_map(self) -> DyckWord:
28442855
sage: DyckWord([1,0,1,0]).bounce_area_to_area_dinv_map()
28452856
[1, 1, 0, 0]
28462857
"""
2847-
aseq = self.to_area_sequence()
2858+
aseq = self._area_sequence_iter()
28482859
out: list[int] = []
28492860
zeros: list[int] = []
2850-
for i in range(len(aseq)):
2851-
p = (zeros + [len(out)])[aseq[i]]
2861+
for ai in aseq:
2862+
p = (zeros + [len(out)])[ai]
28522863
out = [1] + out[p:] + [0] + out[:p]
2853-
zeros = [0] + [j + len(out) - p for j in zeros[:aseq[i]]]
2864+
zeros = [0] + [j + len(out) - p for j in zeros[:ai]]
28542865
return DyckWord(out) # type:ignore
28552866

28562867
def area(self) -> int:
@@ -3093,9 +3104,11 @@ def dinv(self, labeling=None) -> int:
30933104
"""
30943105
alist = self.to_area_sequence()
30953106
cnt = 0
3096-
for j in range(len(alist)):
3107+
for j, aj in enumerate(alist):
3108+
if labeling is not None:
3109+
lj = labeling[j]
30973110
for i in range(j):
3098-
if (alist[i] - alist[j] == 0 and (labeling is None or labeling[i] < labeling[j])) or (alist[i] - alist[j] == 1 and (labeling is None or labeling[i] > labeling[j])):
3111+
if (alist[i] == aj and (labeling is None or labeling[i] < lj)) or (alist[i] - aj == 1 and (labeling is None or labeling[i] > lj)):
30993112
cnt += 1
31003113
return cnt
31013114

@@ -3933,10 +3946,12 @@ def __iter__(self):
39333946

39343947
class height_poset(UniqueRepresentation, Parent):
39353948
r"""
3936-
The poset of complete Dyck words compared componentwise by
3937-
``heights``.
3949+
The poset of complete Dyck words compared componentwise by ``heights``.
3950+
39383951
This is, ``D`` is smaller than or equal to ``D'`` if it is
39393952
weakly below ``D'``.
3953+
3954+
This is implemented by comparison of area sequences.
39403955
"""
39413956
def __init__(self):
39423957
r"""
@@ -3974,7 +3989,7 @@ def le(self, dw1, dw2):
39743989
39753990
.. SEEALSO::
39763991
3977-
:meth:`heights<sage.combinat.dyck_word.DyckWord.heights>`
3992+
:meth:`~sage.combinat.dyck_word.DyckWord.to_area_sequence`
39783993
39793994
EXAMPLES::
39803995
@@ -3994,10 +4009,10 @@ def le(self, dw1, dw2):
39944009
True, False, False, False, False, True]
39954010
"""
39964011
if len(dw1) != len(dw2):
3997-
raise ValueError("Length mismatch: %s and %s" % (dw1, dw2))
3998-
sh = dw1.heights()
3999-
oh = dw2.heights()
4000-
return all(sh[i] <= oh[i] for i in range(len(dw1)))
4012+
raise ValueError(f"length mismatch: {dw1} and {dw2}")
4013+
ar1 = dw1._area_sequence_iter()
4014+
ar2 = dw2._area_sequence_iter()
4015+
return all(a1 <= a2 for a1, a2 in zip(ar1, ar2))
40014016

40024017

40034018
class CompleteDyckWords_size(CompleteDyckWords, DyckWords_size):

0 commit comments

Comments
 (0)