From 9243555ff352beb0a4c1db6fed65a7cba9c83aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Mon, 24 Feb 2025 15:13:45 +0000 Subject: [PATCH 01/15] Implement a bijection between Knutson-Tao puzzles and LR tableaux --- src/sage/combinat/knutson_tao_puzzles.py | 192 ++++++++++++++++++++--- src/sage/combinat/partition.py | 112 +++++++++++++ src/sage/combinat/skew_tableau.py | 172 ++++++++++++++++++++ 3 files changed, 456 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 7e226bffee3..02be4ee859d 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -9,8 +9,11 @@ Acknowledgements ---------------- -This code was written during Sage Days 45 at ICERM with Franco Saliola, Anne Schilling, and Avinash Dalal in discussions with Allen Knutson. -The code was tested afterwards by Liz Beazley and Ed Richmond. +The initial version of this code was written during Sage Days 45 at ICERM. + +- Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (Initial version, 2013) +- Elizabeth Beazley, Ed Richmond (Testing, 2013) +- Álvaro Gutiérrez (added .to_LRtableaux(), 2025) .. TODO:: @@ -21,10 +24,6 @@ - we should also have a 3-step puzzle pieces constructor, taken from p22 of :arxiv:`math/0610538` - - - implement the bijection from puzzles to tableaux; see for example - R. Vakil, A geometric Littlewood-Richardson rule, :arxiv:`math/0302294` - or K. Purbhoo, Puzzles, Tableaux and Mosaics, :arxiv:`0705.1184`. """ # **************************************************************************** # Copyright (C) 2013 Franco Saliola , @@ -32,7 +31,8 @@ # 2013 Avinash Dalal, # 2013 Anne Schilling, # 2013 Elizabeth Beazley, -# 2013 Ed Richmond +# 2013 Ed Richmond, +# 2025 Álvaro Gutiérrez # # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ @@ -1260,7 +1260,6 @@ def copy(self): EXAMPLES:: - sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, PuzzleFilling sage: piece = DeltaPiece('0','1','0') sage: P = PuzzleFilling('0101','0101'); P @@ -1313,6 +1312,30 @@ def __repr__(self): from pprint import pformat return pformat(self._squares) + def __eq__(self, other): + r""" + TESTS:: + + sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: solns = ps('0101','1001') + sage: all(sol == sol for sol in solns) + True + """ + return self._squares == other._squares + + def __lt__(self, other): + r""" + TESTS:: + + sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: solns = ps('0101','1001') + sage: sorted(solns) == sorted(solns, key=str) + True + """ + return str(self) < str(other) + def __iter__(self): r""" Iterator. @@ -1464,6 +1487,137 @@ def tikzlabels(color, k, d, i, label1, label2, label3): return s + def to_LRtableau(self): + r""" + Creates a skew Littlewood--Richardson tableau from a puzzle. + + We follow the bijection given in [Purbhoo07]_. A similar but different + bijection is given in [Vakil03]_. + + .. WARNING:: + + This method only works for the classical cohomology puzzle pieces. + + REFERENCES: + + .. [Purbhoo07] K. Purbhoo, Puzzles, Tableaux and Mosaics, :arxiv:`0705.1184` + + .. [Vakil03] R. Vakil, A geometric Littlewood-Richardson rule, :arxiv:`0302294` + + OUTPUT: + + - a LR skew tableau + + EXAMPLES:: + + sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: solns = ps('010101','010101') + sage: [puzzle.to_LRtableau() for puzzle in sorted(solns)] + [[[None, 1, 1], [None, 2], [None]], + [[None, None, 1], [None, 2], [1]], + [[None, None, 1], [None, 1], [2]], + [[None, None, None], [1, 1], [2]]] + sage: # Example similar to Figure 9 in Purbhoo07 + ....: ps = KnutsonTaoPuzzleSolver('H') + ....: solns = ps('00000010001000010100', '00000000100010010100') + ....: puzzle = solns[168] + ....: tab = puzzle.to_LRtableau(); tab.pp() + . . . . . . . . . . 1 1 1 1 + . . . . . . . 1 1 1 2 2 2 + . . . . . 1 1 2 2 3 3 + . . 1 2 2 3 4 4 + """ + from sage.combinat.partition import abacus_to_partition + from sage.combinat.skew_tableau import SkewTableau + + k = sum(int(i) for i in self._ne_labels) + lam = abacus_to_partition(self.south_labels()) + [0]*k + tab = [] + for i in range(self._n): + row = [] + if self._ne_labels[i] == '1': + k -= 1 + row += [None] * lam[k] + row += self._ne_to_south_path(i+1) + tab.insert(0, row) + while [] in tab: + tab.remove([]) + return SkewTableau(tab) + + def _ne_to_south_path(self, coord): + r""" + Returns the content row of the LR skew tableau corresponding to ``coord``. + + This method traces out a path from ``coord`` to its "mirror" coordinate. + If ``coord`` specifies the `i`-th 1 from the top on the north-east border + of the puzzle, then its mirror is the `i`-th 1 from the west on the south + border. The algorithm records the content numbers of the traced horizontal + rhombi. See [Purbhoo07]_. + + .. WARNING:: + + This method only works for the classical cohomology puzzle pieces. + + REFERENCES: + + .. [Purbhoo07] K. Purbhoo, Puzzles, Tableaux and Mosaics, :arxiv:`0705.1184` + + INPUT: + + - ``coord`` -- north-east boundary position counting from the top whose label is 1 + + OUTPUT: + + - a list of numbers giving the content of one row in the LR tableau + + TESTS:: + + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: solns = ps('0101011','0101101') + sage: puzzle = sorted(solns)[4] + sage: puzzle[(1,1)] + 0/1\10 + sage: puzzle._ne_to_south_path(4) + [1, 1] + sage: puzzle._ne_to_south_path(3) + Traceback (most recent call last): + ... + AssertionError: the coordinate needs to be a coordinate of a 1 on the north-east boundary + + """ + assert self._ne_labels[coord-1] == '1', "the coordinate needs to be a coordinate of a 1 on the north-east boundary" + + i = coord + j = self._n + moving = "west" + LR_list = [] + while j != 0: + if moving == "west": + if j-i == 0: + current_piece = self[(i,j)] + else: + current_piece = self[(i,j)].north_piece() + current_labels = current_piece.border() + if current_labels == ('1', '1', '1'): + moving = "south" + LR_list = [i+1 for i in LR_list] + elif current_labels == ('0', '10', '1'): + i = i-1 + j = j-1 + LR_list.insert(0, 0) + elif moving == "south": + if j-i < 1: + break + current_piece = self[(i,j)].south_piece() + current_labels = current_piece.border() + if current_labels == ('1', '1', '1'): + moving = "west" + j = j-1 + assert j > 0, "something went wrong and the path escaped the puzzle" + + return LR_list + class KnutsonTaoPuzzleSolver(UniqueRepresentation): r""" @@ -1601,14 +1755,13 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: solns = ps('0101', '0101') sage: view(solns[0], viewer='pdf') # not tested - Below are examples of using each of the currently supported puzzles. Cohomology of the Grassmannian:: sage: ps = KnutsonTaoPuzzleSolver("H") sage: solns = ps('0101', '0101') - sage: sorted(solns, key=str) + sage: sorted(solns) [{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (1, 3): 0/\0 0\/0, @@ -1633,7 +1786,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: ps = KnutsonTaoPuzzleSolver("HT") sage: solns = ps('0101', '0101') - sage: sorted(solns, key=str) + sage: sorted(solns) [{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (1, 3): 0/\0 0\/0, @@ -1667,7 +1820,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: ps = KnutsonTaoPuzzleSolver("K") sage: solns = ps('0101', '0101') - sage: sorted(solns, key=str) + sage: sorted(solns) [{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (1, 3): 0/\0 0\/0, @@ -1701,7 +1854,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: ps = KnutsonTaoPuzzleSolver("H2step") sage: solns = ps('01201', '01021') - sage: sorted(solns, key=str) + sage: sorted(solns) [{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (1, 3): 2/\0 0\/2, @@ -1750,7 +1903,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: ps = KnutsonTaoPuzzleSolver("HT2step") sage: solns = ps('10212', '12012') - sage: sorted(solns, key=str) + sage: sorted(solns) [{(1, 1): 1/1\1, (1, 2): 0/\(21)0 1\/2, (1, 3): 2/\1 (21)0\/0, @@ -1893,7 +2046,6 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (4, 5): 2/\1 1\/2, (5, 5): 2/2\2}] - Belkale-Kumar puzzles (the following example is Figure 2 of [KnutsonPurbhoo10]_):: sage: ps = KnutsonTaoPuzzleSolver('BK', 3) @@ -2236,7 +2388,7 @@ def structure_constants(self, lamda, mu, nu=None): sage: ps = KnutsonTaoPuzzleSolver('HT') sage: cp = ps.structure_constants('0101', '0101') - sage: sorted(cp.items(), key=str) + sage: sorted(cp.items()) [(('0', '1', '0', '1'), y2 - y3), (('0', '1', '1', '0'), 1), (('1', '0', '0', '1'), 1)] @@ -2245,17 +2397,17 @@ def structure_constants(self, lamda, mu, nu=None): sage: ps = KnutsonTaoPuzzleSolver('K') sage: cp = ps.structure_constants('0101', '0101') - sage: sorted(cp.items(), key=str) + sage: sorted(cp.items()) [(('0', '1', '1', '0'), 1), (('1', '0', '0', '1'), 1), (('1', '0', '1', '0'), -1)] Two-step:: sage: ps = KnutsonTaoPuzzleSolver('H2step') sage: cp = ps.structure_constants('01122', '01122') - sage: sorted(cp.items(), key=str) + sage: sorted(cp.items()) [(('0', '1', '1', '2', '2'), 1)] sage: cp = ps.structure_constants('01201', '01021') - sage: sorted(cp.items(), key=str) + sage: sorted(cp.items()) [(('0', '2', '1', '1', '0'), 1), (('1', '2', '0', '0', '1'), 1), (('2', '0', '1', '0', '1'), 1)] @@ -2264,7 +2416,7 @@ def structure_constants(self, lamda, mu, nu=None): sage: ps = KnutsonTaoPuzzleSolver('HT2step') sage: cp = ps.structure_constants('10212', '12012') - sage: sorted(cp.items(), key=str) + sage: sorted(cp.items()) [(('1', '2', '0', '1', '2'), y1*y2 - y2*y3 - y1*y4 + y3*y4), (('1', '2', '0', '2', '1'), y1 - y3), (('1', '2', '1', '0', '2'), y2 - y4), diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index dd2ef6fe63e..8d856ba9c65 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -62,6 +62,8 @@ - Matthew Lancellotti (2018-09-14): Added a bunch of "k" methods to Partition. +- Álvaro Gutiérrez (2025-02-24): added functionality to translate to and from abaci + EXAMPLES: There are `5` partitions of the integer `4`:: @@ -274,6 +276,7 @@ """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen , +# 2025 Álvaro Gutiérrez # # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ @@ -5809,6 +5812,62 @@ def tabloid_module(self, base_ring=None): R = SymmetricGroupAlgebra(base_ring, sum(self)) return TabloidModule(R, self) + def to_abacus(self, size=0, ones=0): + r""" + Return an abacus from a partition. + + This is the inverse to :func:`.abacus_to_partition`. + + An abacus is a function `w : \mathbb{Z} \to \{0,1\}` such that + `w(n) = 0` for `n \ll 0` and `w(n) = 1` for `n \gg 0`. It is usually + represented with an infinite tuple, e.g. `(...,0,0,0,1,0,0,1,0,1,1,...)`. + Here, we use finite tuples, and assume everything to the left is a 0 + and everything to the right is a 1. + + A partition determines an abacus via the following interpretation: + read the outline of the Young diagram of the partition, with English + convention. For each vertical step, record a 1; for each horizontal + step record a 0. The resulting word is the corresponding abacus. + + Additionally, if ``size`` is given, the abacus will be of length at least + ``size`` (by padding with 0s on the right). The number of 1s in the abacus + will be at least ``ones``. + + INPUT: + + - ``size``, ``ones`` -- Integer (optional. Default: 0) + + OUTPUT: + + - a string of 0s and 1s. + + EXAMPLES:: + + sage: Partition([3,2,1]).to_abacus() + '010101' + sage: Partition([3,2,1]).to_abacus(size=10) + '0101010000' + sage: Partition([3,3]).to_abacus() + '00011' + sage: Partition([]).to_abacus(size=6) + '000000' + sage: Partition([]).to_abacus(ones=2) + '11' + sage: Partition([2,2]).to_abacus(size=4) + '0011' + sage: Partition([2,2]).to_abacus(size=5) + '00110' + sage: Partition([2,2]).to_abacus(size=5, ones=3) + '10011' + + """ + L = max(ones,len(self)) + lam = list(self)+[0]*(L+1-len(self)) + abacus = [1] * L + for i in range(L): + abacus = abacus[:(L-i-1)] + [0]*(lam[i]-lam[i+1]) + abacus[(L-i-1):] + return ''.join(map(str, abacus + [0]*(size-len(abacus)))) + ############## # Partitions # @@ -9665,6 +9724,59 @@ def _an_element_(self): """ return self.element_class(self, Partitions_n._an_element_(self).conjugate()) +################################################################## + + +def abacus_to_partition(abacus): + r""" + Returns a partition from an abacus. + + An abacus is a function `w : \mathbb{Z} \to \{0,1\}` such that + `w(n) = 0` for `n \ll 0` and `w(n) = 1` for `n \gg 0`. It is usually + represented with an infinite tuple, e.g. `(...,0,0,0,1,0,0,1,0,1,1,...)`. + Here, we use finite tuples, and assume everything to the left is a 0 + and everything to the right is a 1. + + An abacus determines a partition, via the following interpretation: + a 1 in the abacus encodes a vertical line, and a 0 encodes a + horizontal one. Reading from left to right, the abacus spells the + outline of the Young diagram. + + This is the inverse to :meth:`Partition.to_abacus`. + + INPUT: + + - ``abacus`` -- a tuple, a list or a string of 1's and 0's + + OUTPUT: + + - a Partition + + EXAMPLES:: + + sage: from sage.combinat.partition import abacus_to_partition + sage: abacus_to_partition('010101') + [3, 2, 1] + sage: abacus_to_partition([1,1,0,0,0]) + [] + sage: abacus_to_partition((0,0,0,1,1)) + [3, 3] + sage: abacus_to_partition(('1','1','1','0','0','0')) + [] + sage: abacus_to_partition(['0','0','0','1','1','1']) + [3, 3, 3] + """ + part = [] + n = len(abacus) + k = 0 + for i in range(0,n): + if abacus[i] == '1' or abacus[i] == 1: + k += 1 + part.insert(0, i+1-k) + elif abacus[i] != '0' and abacus[i] != 0: + raise ValueError('an abacus should be a tuple, list or string of 0s and 1s') + return Partition(part) + ######################################################################### diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 2d35efc2363..3bb74988f6c 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -7,11 +7,13 @@ - Travis Scrimshaw, Arthur Lubovsky (2013-02-11): Factored out ``CombinatorialClass`` - Trevor K. Karn (2022-08-03): added ``backward_slide`` +- Álvaro Gutiérrez (2025-02-24): added ``to_KTpuzzle`` """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2013 Travis Scrimshaw # Copyright (C) 2013 Arthur Lubovsky +# Copyright (C) 2025 Álvaro Gutiérrez # # Distributed under the terms of the GNU General Public License (GPL) # @@ -1844,6 +1846,176 @@ def is_k_tableau(self, k) -> bool: return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) + def is_LR(self): + r""" + Checks whether ``self`` is a Littlewood--Richardson tableau. + + A Littlewood--Richardson tableau (LR tableau) is a semistandard skew tableau whose + (row reading) word is Yamanouchi. + + EXAMPLES:: + + sage: SkewTableau([[None,1],[1,2]]).is_LR() + True + sage: SkewTableau([[None,1],[2,1]]).is_LR() + False + sage: SkewTableau([[None,1],[2,2]]).is_LR() + False + + """ + return self.is_semistandard() and self.to_word().is_yamanouchi() + + def to_KTpuzzle(self, size=None): + r""" + Takes a Littlewood--Richardson tableau and returns a Knutson--Tao puzzle. + + + INPUT: + + - ``tableau`` -- a Littlewood--Richardson SkewTableau + + - ``size`` -- the size of the output Knutson--Tao puzzle (optional) + + TESTS:: + + sage: # Example from Purbhoo07 + sage: tab = SkewTableau([ + ....: [None]*10 + [1]*4, + ....: [None]*8 + [1]*2 + [2]*3, + ....: [None]*5 + [1]*2 + [2]*2 + [3]*2, + ....: [None] + [1]*2 + [2]*2 + [3] + [4]*2]) + sage: puzzle = tab.to_KTpuzzle(20) + sage: puzzle[(5,10)] + 1/\0 0\/1 + sage: ''.join(puzzle.south_labels()) + '01000010001001000000' + sage: # puzzle.plot() # not tested + + EXAMPLES:: + + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: puzzle = ps('01010','01001')[0] + sage: tab = puzzle.to_LRtableau(); tab + [[None, 1, 1], [2]] + sage: puzzle2 = tab.to_KTpuzzle() + sage: puzzle == puzzle2 + True + """ + assert self.is_LR(), "this method only applies to Littlewood-Richardson tableaux" + + from sage.combinat.partition import abacus_to_partition + from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces, KnutsonTaoPuzzleSolver, PuzzleFilling + + # Extract border of puzzle from tableau + + tab_w = self.weight() + tab_out = self.outer_shape() + tab_inn = self.inner_shape() + L = len(self) + + if size is None: + size = max(tab_w[0] + L, tab_out[0] + L) + assert size >= max(tab_w[0] + L, tab_out[0] + L), "the puzzle size inputted is too small" + + n = size + + lam = Partition(tab_w).to_abacus(size=size, ones=L)[::-1] + mu = [(n - L) - r for r in tab_out][::-1] + mu = Partition(mu).to_abacus(size=size, ones=L)[::-1] + nu = Partition(tab_inn).to_abacus(size=size, ones=L) + + # Initialize puzzle + + puzzle = PuzzleFilling(lam, mu) + + # Find the locations of 1-triangles (blue by default in the plot) + + chosenCols = [i+1 for i in range(n) if nu[i] == '1'] + chosenRows = [i+1 for i in range(n) if lam[i] == '1'] + delta_blue_positions = [] + nabla_blue_positions = [] + for col in range(L): + propagationRow = [] + propagationCol = [] + for row in range(col+1): + i = chosenRows[row] + j = chosenCols[col-row] + + delta_blue_positions.append((j, i)) + + k = self[L-col+row-1].count(row+1) + nabla_blue_positions.append((j+k, i+k+1)) + + propagationCol.insert(0, j+k) + propagationRow.insert(0, i+k+1) + chosenRows = sorted(propagationRow) + chosenRows[col+1:] + chosenCols = sorted(propagationCol) + chosenCols[col+1:] + + # Create a dictionary of boundaries + # (not all boundaries are in the dictionary) + + D = {(i,j) : {} for i in range(1,n+1) for j in range(i,n+1)} + for (i,j) in delta_blue_positions: + D[(i,j)]['north_west'] = '1' + D[(i,j)]['north_east'] = '1' + (a, b) = (i, j) + while ((a-1, b) not in nabla_blue_positions and a > 1): + a -= 1 + D[(a,b)]['north_east'] = '0' + D[(a,b)]['north_west'] = '1' + D[(a,b)]['south_east'] = '1' + D[(a,b)]['south_west'] = '0' + (a, b) = (i, j) + while ((a, b) not in nabla_blue_positions and b > a): + b -= 1 + D[(a,b)]['north_west'] = '0' + D[(a,b)]['north_east'] = '10' + for (i,j) in nabla_blue_positions: + if (i,j) in D.keys(): + D[(i,j)]['south_west'] = '1' + D[(i,j)]['south_east'] = '1' + (a, b) = (i, j) + while ((a, b-1) not in delta_blue_positions and a > 0): + a -= 1 + b -= 1 + D[(a,b)]['south_east'] = '10' + D[(a,b)]['south_west'] = '1' + D[(a+1,b)]['north_east'] = '1' + D[(a+1,b)]['north_west'] = '10' + for i in range(n): + D[(1,i+1)]['north_west'] = lam[i] + D[(i+1,i+1)]['south'] = nu[i] + D[(i+1,n)]['north_east'] = mu[i] + + # Now fill piece by piece + # (like KnutsonTaoPuzzleSolver._fill_puzzle_by_pieces + # but with the extra constraints given by the above) + + all_pieces = H_grassmannian_pieces() + dirs = ('north_east', 'north_west', 'south_east', 'south_west') + rhombi = sorted(all_pieces.rhombus_pieces(), key=lambda p : ''.join(p[dir] for dir in dirs)) + # the sorting guarantees that the 0/\0 0\/0 piece is always + # inserted if possible. + dirs = ('north_east', 'north_west', 'south') + triangles = sorted(all_pieces.delta_pieces(), key=lambda p : ''.join(p[dir] for dir in dirs)) + + for (i,j) in D.keys(): + candidates = [] + if i == j: + pieces = triangles + dirs = ('north_east', 'north_west', 'south') + else: + pieces = rhombi + dirs = ('north_east', 'north_west', 'south_east', 'south_west') + # Check what pieces have the desired boundaries + for piece in pieces: + if all(piece[dir] == D[(i,j)][dir] for dir in dirs if dir in D[(i,j)].keys()): + candidates.append(piece) + # Place the smallest possible piece (the one with most 0s) + puzzle._squares[(i,j)] = candidates[0] + + return puzzle + def _label_skew(list_of_cells, sk): """ From 1658e2256bd22b72fe61662b46c0e34bd7a92b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Mon, 24 Feb 2025 16:08:34 +0000 Subject: [PATCH 02/15] Clean-up headers of Partitions, Knutson-Tao_tableau, Skew_Tableau --- src/sage/combinat/knutson_tao_puzzles.py | 16 +++++++++------- src/sage/combinat/partition.py | 5 ++++- src/sage/combinat/skew_tableau.py | 20 ++++++++------------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 02be4ee859d..da6da7ac521 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -6,14 +6,12 @@ north-east and north-west sides of the puzzle boundary; the output is the list of the fillings of the puzzle with the specified pieces. -Acknowledgements ----------------- -The initial version of this code was written during Sage Days 45 at ICERM. +AUTHORS: -- Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (Initial version, 2013) -- Elizabeth Beazley, Ed Richmond (Testing, 2013) -- Álvaro Gutiérrez (added .to_LRtableaux(), 2025) +- Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (2013): initial version at Sage Days 45, ICERM +- Elizabeth Beazley, Ed Richmond (2013): testing +- Álvaro Gutiérrez (2025-02-24): added ``.to_LRtableaux()`` .. TODO:: @@ -34,9 +32,13 @@ # 2013 Ed Richmond, # 2025 Álvaro Gutiérrez # -# Distributed under the terms of the GNU General Public License (GPL) +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** + from __future__ import annotations from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 8d856ba9c65..3879cb0101a 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -278,7 +278,10 @@ # Copyright (C) 2007 Mike Hansen , # 2025 Álvaro Gutiérrez # -# Distributed under the terms of the GNU General Public License (GPL) +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 3bb74988f6c..8b1b253c570 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -8,22 +8,18 @@ Factored out ``CombinatorialClass`` - Trevor K. Karn (2022-08-03): added ``backward_slide`` - Álvaro Gutiérrez (2025-02-24): added ``to_KTpuzzle`` + """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen , -# Copyright (C) 2013 Travis Scrimshaw -# Copyright (C) 2013 Arthur Lubovsky -# Copyright (C) 2025 Álvaro Gutiérrez -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# The full text of the GPL is available at: +# 2013 Travis Scrimshaw +# 2013 Arthur Lubovsky +# 2025 Álvaro Gutiérrez # +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** From 16793a56ae7e4b3b163a5656a30c6d18f136f5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Mon, 24 Feb 2025 16:10:05 +0000 Subject: [PATCH 03/15] Change `lamda` to `lam` to make spell-checker happy --- src/sage/combinat/knutson_tao_puzzles.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index da6da7ac521..dcf7783dc26 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -2137,7 +2137,7 @@ def __classcall_private__(cls, puzzle_pieces, max_letter=None): raise ValueError("max_letter needs to be specified") return super().__classcall__(cls, puzzle_pieces) - def __call__(self, lamda, mu, algorithm='strips'): + def __call__(self, lam, mu, algorithm='strips'): r""" TESTS:: @@ -2166,11 +2166,11 @@ def __call__(self, lamda, mu, algorithm='strips'): (3, 4): 0/\0 1\/10, (4, 4): 10/0\1}] """ - lamda, mu = tuple(lamda), tuple(mu) + lam, mu = tuple(lam), tuple(mu) if algorithm == 'pieces': - return list(self._fill_puzzle_by_pieces(lamda, mu)) + return list(self._fill_puzzle_by_pieces(lam, mu)) elif algorithm == 'strips': - return list(self._fill_puzzle_by_strips(lamda, mu)) + return list(self._fill_puzzle_by_strips(lam, mu)) solutions = __call__ @@ -2272,7 +2272,7 @@ def _fill_strip(self, nw_labels, ne_label, pieces, final_pieces=None): output.append(partial_filling + [piece]) return output - def _fill_puzzle_by_pieces(self, lamda, mu): + def _fill_puzzle_by_pieces(self, lam, mu): r""" Fill puzzle pieces for given outer labels ``lambda`` and ``mu``. @@ -2283,7 +2283,7 @@ def _fill_puzzle_by_pieces(self, lamda, mu): sage: list(ps._fill_puzzle_by_pieces('0', '0')) [{(1, 1): 0/0\0}] """ - queue = [PuzzleFilling(lamda, mu)] + queue = [PuzzleFilling(lam, mu)] while queue: PP = queue.pop() ne_label = PP.north_east_label_of_kink() @@ -2300,7 +2300,7 @@ def _fill_puzzle_by_pieces(self, lamda, mu): else: queue.append(PPcopy) - def _fill_puzzle_by_strips(self, lamda, mu): + def _fill_puzzle_by_strips(self, lam, mu): r""" Fill puzzle pieces by strips for given outer labels ``lambda`` and ``mu``. @@ -2313,7 +2313,7 @@ def _fill_puzzle_by_strips(self, lamda, mu): sage: list(ps._fill_puzzle_by_strips('01', '01')) [{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (2, 2): 1/1\1}] """ - queue = [PuzzleFilling(lamda, mu)] + queue = [PuzzleFilling(lam, mu)] while queue: PP = queue.pop() i, _ = PP.kink_coordinates() @@ -2323,7 +2323,7 @@ def _fill_puzzle_by_strips(self, lamda, mu): nw_labels = PP._nw_labels else: nw_labels = tuple(PP._squares[i - 1, k]['south_east'] - for k in range(i, len(lamda) + 1)) + for k in range(i, len(lam) + 1)) # grab ne labels ne_label = PP._ne_labels[i - 1] @@ -2357,7 +2357,7 @@ def plot(self, puzzles): m = len([gg.axes(False) for gg in g]) return graphics_array(g, (m + 3) / 4, 4) - def structure_constants(self, lamda, mu, nu=None): + def structure_constants(self, lam, mu, nu=None): r""" Compute cohomology structure coefficients from puzzles. @@ -2428,9 +2428,9 @@ def structure_constants(self, lamda, mu, nu=None): (('2', '1', '1', '0', '2'), 1)] """ from collections import defaultdict - R = PolynomialRing(Integers(), 'y', len(lamda) + 1) + R = PolynomialRing(Integers(), 'y', len(lam) + 1) z = defaultdict(R.zero) - for p in self(lamda, mu): + for p in self(lam, mu): z[p.south_labels()] += p.contribution() if nu is None: return dict(z) From bc04fd84bf183d535c44d3ae484a9577f6b08e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 25 Feb 2025 06:39:48 +0000 Subject: [PATCH 04/15] Clean up implementation to improve consistency in output The previous implementation iterated over sets, which caused inconsistent output; this was solved by adding 'UniqueRepresentation' as a parent for one class and by sorting outputs in many doctests. The new code iterates over tuples. --- src/sage/combinat/knutson_tao_puzzles.py | 586 +++++++++++------------ 1 file changed, 279 insertions(+), 307 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index dcf7783dc26..e3adfd54e0c 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -12,6 +12,7 @@ - Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (2013): initial version at Sage Days 45, ICERM - Elizabeth Beazley, Ed Richmond (2013): testing - Álvaro Gutiérrez (2025-02-24): added ``.to_LRtableaux()`` +- Julian Rüth (2025-02-24): clean up code .. TODO:: @@ -31,6 +32,7 @@ # 2013 Elizabeth Beazley, # 2013 Ed Richmond, # 2025 Álvaro Gutiérrez +# 2025 Julian Rüth # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -636,14 +638,23 @@ class PuzzlePieces: sage: pieces.add_piece(NablaPiece('1','1','1'), rotations=60) sage: pieces.add_piece(NablaPiece('1','0','10'), rotations=60) sage: pieces - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) + The user can obtain the list of valid rhombi pieces as follows:: - sage: sorted([p for p in pieces.rhombus_pieces()], key=str) - [0/\0 0\/0, 0/\0 1\/10, 0/\10 10\/0, 0/\10 1\/1, 1/\0 0\/1, - 1/\1 10\/0, 1/\1 1\/1, 10/\1 0\/0, 10/\1 1\/10] + sage: pieces.rhombus_pieces() + (0/\0 0\/0, + 10/\1 0\/0, + 1/\1 1\/1, + 0/\10 1\/1, + 1/\1 10\/0, + 0/\10 10\/0, + 1/\0 0\/1, + 0/\0 1\/10, + 10/\1 1\/10) + """ def __init__(self, forbidden_border_labels=None): @@ -658,16 +669,16 @@ def __init__(self, forbidden_border_labels=None): sage: forbidden_border_labels = ['10'] sage: pieces = PuzzlePieces(forbidden_border_labels) sage: pieces - Nablas : [] - Deltas : [] + Nablas : () + Deltas : () sage: PuzzlePieces('10') Traceback (most recent call last): ... TypeError: Input must be a list """ - self._nabla_pieces = set() - self._delta_pieces = set() + self._nabla_pieces = {} + self._delta_pieces = {} if forbidden_border_labels is None: forbidden_border_labels = [] if not isinstance(forbidden_border_labels, list): @@ -723,33 +734,33 @@ def add_piece(self, piece, rotations=120): sage: delta = DeltaPiece('a','b','c') sage: pieces = PuzzlePieces() sage: pieces - Nablas : [] - Deltas : [] + Nablas : () + Deltas : () sage: pieces.add_piece(delta) sage: pieces - Nablas : [] - Deltas : [a/c\b, b/a\c, c/b\a] + Nablas : () + Deltas : (b/a\c, a/c\b, c/b\a) sage: pieces = PuzzlePieces() sage: pieces.add_piece(delta,rotations=0) sage: pieces - Nablas : [] - Deltas : [b/a\c] + Nablas : () + Deltas : (b/a\c,) sage: pieces = PuzzlePieces() sage: pieces.add_piece(delta,rotations=60) sage: pieces - Nablas : [a\b/c, b\c/a, c\a/b] - Deltas : [a/c\b, b/a\c, c/b\a] + Nablas : (c\a/b, b\c/a, a\b/c) + Deltas : (b/a\c, a/c\b, c/b\a) """ if isinstance(piece, NablaPiece): pieces_list = self._nabla_pieces else: pieces_list = self._delta_pieces - pieces_list.add(piece) + pieces_list[piece] = True if rotations == 120: - pieces_list.add(piece.clockwise_rotation()) - pieces_list.add(piece.clockwise_rotation().clockwise_rotation()) + pieces_list[piece.clockwise_rotation()] = True + pieces_list[piece.clockwise_rotation().clockwise_rotation()] = True elif rotations == 180: self.add_piece(piece.half_turn_rotation(), rotations=0) elif rotations == 60: @@ -791,8 +802,8 @@ def add_T_piece(self, label1, label2): sage: pieces = PuzzlePieces() sage: pieces.add_T_piece('1','3') sage: pieces - Nablas : [3\T1|3/1] - Deltas : [1/T1|3\3] + Nablas : (3\T1|3/1,) + Deltas : (1/T1|3\3,) sage: pieces._forbidden_border_labels ['T1|3'] """ @@ -808,11 +819,12 @@ def __repr__(self) -> str: sage: delta = DeltaPiece('a','b','c') sage: pieces.add_piece(delta,rotations=60) sage: pieces - Nablas : [a\b/c, b\c/a, c\a/b] - Deltas : [a/c\b, b/a\c, c/b\a] + Nablas : (c\a/b, b\c/a, a\b/c) + Deltas : (b/a\c, a/c\b, c/b\a) + """ - s = "Nablas : %s\n" % sorted(self._nabla_pieces, key=str) - s += "Deltas : %s" % sorted(self._delta_pieces, key=str) + s = f"Nablas : {self.nabla_pieces()}\n" + s += f"Deltas : {self.delta_pieces()}" return s def delta_pieces(self): @@ -825,10 +837,11 @@ def delta_pieces(self): sage: pieces = PuzzlePieces() sage: delta = DeltaPiece('a','b','c') sage: pieces.add_piece(delta,rotations=60) - sage: sorted([p for p in pieces.delta_pieces()], key=str) - [a/c\b, b/a\c, c/b\a] + sage: pieces.delta_pieces() + (b/a\c, a/c\b, c/b\a) + """ - return self._delta_pieces + return tuple(self._delta_pieces) def nabla_pieces(self): r""" @@ -840,12 +853,13 @@ def nabla_pieces(self): sage: pieces = PuzzlePieces() sage: delta = DeltaPiece('a','b','c') sage: pieces.add_piece(delta,rotations=60) - sage: sorted([p for p in pieces.nabla_pieces()], key=str) - [a\b/c, b\c/a, c\a/b] + sage: pieces.nabla_pieces() + (c\a/b, b\c/a, a\b/c) + """ - return self._nabla_pieces + return tuple(self._nabla_pieces) - def rhombus_pieces(self) -> set: + def rhombus_pieces(self) -> tuple: r""" Return a set of all allowable rhombus pieces. @@ -858,15 +872,16 @@ def rhombus_pieces(self) -> set: sage: pieces = PuzzlePieces() sage: delta = DeltaPiece('a','b','c') sage: pieces.add_piece(delta,rotations=60) - sage: sorted([p for p in pieces.rhombus_pieces()], key=str) - [a/\b b\/a, b/\c c\/b, c/\a a\/c] + sage: pieces.rhombus_pieces() + (b/\c c\/b, a/\b b\/a, c/\a a\/c) + """ - rhombi = set() + rhombi = {} for nabla in self._nabla_pieces: for delta in self._delta_pieces: if delta['south'] == nabla['north']: - rhombi.add(RhombusPiece(delta, nabla)) - return rhombi + rhombi[RhombusPiece(delta, nabla)] = True + return tuple(rhombi) def boundary_deltas(self) -> tuple: r""" @@ -878,8 +893,8 @@ def boundary_deltas(self) -> tuple: sage: pieces = PuzzlePieces(['a']) sage: delta = DeltaPiece('a','b','c') sage: pieces.add_piece(delta,rotations=60) - sage: sorted([p for p in pieces.boundary_deltas()], key=str) - [a/c\b, c/b\a] + sage: pieces.boundary_deltas() + (a/c\b, c/b\a) """ return tuple(delta for delta in self.delta_pieces() if delta['south'] not in self._forbidden_border_labels) @@ -899,8 +914,8 @@ def H_grassmannian_pieces(): sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces sage: H_grassmannian_pieces() - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) """ forbidden_border_labels = ['10'] pieces = PuzzlePieces(forbidden_border_labels) @@ -923,8 +938,8 @@ def HT_grassmannian_pieces(): sage: from sage.combinat.knutson_tao_puzzles import HT_grassmannian_pieces sage: HT_grassmannian_pieces() - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1, 1\T0|1/0] - Deltas : [0/0\0, 0/1\10, 0/T0|1\1, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10, 1\T0|1/0) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1, 0/T0|1\1) """ pieces = H_grassmannian_pieces() pieces.add_T_piece('0', '1') @@ -943,8 +958,8 @@ def K_grassmannian_pieces(): sage: from sage.combinat.knutson_tao_puzzles import K_grassmannian_pieces sage: K_grassmannian_pieces() - Nablas : [0\0/0, 0\10/1, 0\K/1, 10\1/0, 1\0/10, 1\0/K, 1\1/1, K\1/0] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1, K/K\K] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10, 1\0/K, K\1/0, 0\K/1) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1, K/K\K) """ pieces = H_grassmannian_pieces() pieces.add_forbidden_label('K') @@ -967,10 +982,8 @@ def H_two_step_pieces(): sage: from sage.combinat.knutson_tao_puzzles import H_two_step_pieces sage: H_two_step_pieces() - Nablas : [(21)0\21/0, 0\(21)0/21, 0\0/0, 0\10/1, 0\20/2, 10\1/0, 10\2(10)/2, 1\0/10, 1\1/1, 1\21/2, - 2(10)\2/10, 20\2/0, 21\0/(21)0, 21\2/1, 2\0/20, 2\1/21, 2\10/2(10), 2\2/2] - Deltas : [(21)0/0\21, 0/0\0, 0/1\10, 0/21\(21)0, 0/2\20, 1/10\0, 1/1\1, 1/2\21, 10/0\1, 10/2\2(10), - 2(10)/10\2, 2/2(10)\10, 2/20\0, 2/21\1, 2/2\2, 20/0\2, 21/(21)0\0, 21/1\2] + Nablas : (0\0/0, 1\1/1, 2\2/2, 0\10/1, 1\0/10, 10\1/0, 0\20/2, 2\0/20, 20\2/0, 1\21/2, 2\1/21, 21\2/1, 0\(21)0/21, 21\0/(21)0, (21)0\21/0, 10\2(10)/2, 2\10/2(10), 2(10)\2/10) + Deltas : (0/0\0, 1/1\1, 2/2\2, 1/10\0, 10/0\1, 0/1\10, 2/20\0, 20/0\2, 0/2\20, 2/21\1, 21/1\2, 1/2\21, 21/(21)0\0, (21)0/0\21, 0/21\(21)0, 2/2(10)\10, 2(10)/10\2, 10/2\2(10)) """ forbidden_border_labels = ['10', '20', '21', '(21)0', '2(10)'] pieces = PuzzlePieces(forbidden_border_labels) @@ -998,12 +1011,8 @@ def HT_two_step_pieces(): sage: from sage.combinat.knutson_tao_puzzles import HT_two_step_pieces sage: HT_two_step_pieces() - Nablas : [(21)0\21/0, 0\(21)0/21, 0\0/0, 0\10/1, 0\20/2, 10\1/0, 10\2(10)/2, - 1\0/10, 1\1/1, 1\21/2, 1\T0|1/0, 2(10)\2/10, 20\2/0, 21\0/(21)0, 21\2/1, 21\T0|21/0, - 21\T10|21/10, 2\0/20, 2\1/21, 2\10/2(10), 2\2/2, 2\T0|2/0, 2\T10|2/10, 2\T1|2/1] - Deltas : [(21)0/0\21, 0/0\0, 0/1\10, 0/21\(21)0, 0/2\20, 0/T0|1\1, 0/T0|21\21, 0/T0|2\2, - 1/10\0, 1/1\1, 1/2\21, 1/T1|2\2, 10/0\1, 10/2\2(10), 10/T10|21\21, 10/T10|2\2, 2(10)/10\2, - 2/2(10)\10, 2/20\0, 2/21\1, 2/2\2, 20/0\2, 21/(21)0\0, 21/1\2] + Nablas : (0\0/0, 1\1/1, 2\2/2, 0\10/1, 1\0/10, 10\1/0, 0\20/2, 2\0/20, 20\2/0, 1\21/2, 2\1/21, 21\2/1, 0\(21)0/21, 21\0/(21)0, (21)0\21/0, 10\2(10)/2, 2\10/2(10), 2(10)\2/10, 1\T0|1/0, 2\T0|2/0, 2\T1|2/1, 2\T10|2/10, 21\T0|21/0, 21\T10|21/10) + Deltas : (0/0\0, 1/1\1, 2/2\2, 1/10\0, 10/0\1, 0/1\10, 2/20\0, 20/0\2, 0/2\20, 2/21\1, 21/1\2, 1/2\21, 21/(21)0\0, (21)0/0\21, 0/21\(21)0, 2/2(10)\10, 2(10)/10\2, 10/2\2(10), 0/T0|1\1, 0/T0|2\2, 1/T1|2\2, 10/T10|2\2, 0/T0|21\21, 10/T10|21\21) """ pieces = H_two_step_pieces() for label1, label2 in (('0', '1'), ('0', '2'), ('1', '2'), @@ -1044,8 +1053,8 @@ def BK_pieces(max_letter): sage: from sage.combinat.knutson_tao_puzzles import BK_pieces sage: BK_pieces(3) - Nablas : [1\1/1, 1\2(1)/2, 1\3(1)/3, 2(1)\2/1, 2\1/2(1), 2\2/2, 2\3(2)/3, 3(1)\3/1, 3(2)\3/2, 3\1/3(1), 3\2/3(2), 3\3/3] - Deltas : [1/1\1, 1/2\2(1), 1/3\3(1), 2(1)/1\2, 2/2(1)\1, 2/2\2, 2/3\3(2), 3(1)/1\3, 3(2)/2\3, 3/3(1)\1, 3/3(2)\2, 3/3\3] + Nablas : (1\1/1, 2\2/2, 1\2(1)/2, 2\1/2(1), 2(1)\2/1, 3\3/3, 1\3(1)/3, 3\1/3(1), 3(1)\3/1, 2\3(2)/3, 3\2/3(2), 3(2)\3/2) + Deltas : (1/1\1, 2/2\2, 2/2(1)\1, 2(1)/1\2, 1/2\2(1), 3/3\3, 3/3(1)\1, 3(1)/1\3, 1/3\3(1), 3/3(2)\2, 3(2)/2\3, 2/3\3(2)) """ forbidden_border_labels = ['%s(%s)' % (i, j) for i in range(1, max_letter + 1) @@ -1287,7 +1296,7 @@ def contribution(self): sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver("HT") sage: puzzles = ps('0101','1001') - sage: sorted([p.contribution() for p in puzzles], key=str) + sage: [p.contribution() for p in puzzles] [1, y1 - y3] """ R = PolynomialRing(Integers(), 'y', self._n + 1) @@ -1320,24 +1329,13 @@ def __eq__(self, other): sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver("H") - sage: solns = ps('0101','1001') - sage: all(sol == sol for sol in solns) + sage: ps('0101','1001') == ps('0101','1001') True + sage: ps('0110','1001') == ps('0101','1001') + False """ return self._squares == other._squares - def __lt__(self, other): - r""" - TESTS:: - - sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver - sage: ps = KnutsonTaoPuzzleSolver("H") - sage: solns = ps('0101','1001') - sage: sorted(solns) == sorted(solns, key=str) - True - """ - return str(self) < str(other) - def __iter__(self): r""" Iterator. @@ -1515,11 +1513,11 @@ def to_LRtableau(self): sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver("H") sage: solns = ps('010101','010101') - sage: [puzzle.to_LRtableau() for puzzle in sorted(solns)] - [[[None, 1, 1], [None, 2], [None]], - [[None, None, 1], [None, 2], [1]], + sage: [puzzle.to_LRtableau() for puzzle in solns] + [[[None, None, None], [1, 1], [2]], [[None, None, 1], [None, 1], [2]], - [[None, None, None], [1, 1], [2]]] + [[None, None, 1], [None, 2], [1]], + [[None, 1, 1], [None, 2], [None]]] sage: # Example similar to Figure 9 in Purbhoo07 ....: ps = KnutsonTaoPuzzleSolver('H') ....: solns = ps('00000010001000010100', '00000000100010010100') @@ -1577,11 +1575,11 @@ def _ne_to_south_path(self, coord): sage: ps = KnutsonTaoPuzzleSolver("H") sage: solns = ps('0101011','0101101') - sage: puzzle = sorted(solns)[4] + sage: puzzle = solns[4] sage: puzzle[(1,1)] - 0/1\10 + 0/0\0 sage: puzzle._ne_to_south_path(4) - [1, 1] + [2] sage: puzzle._ne_to_south_path(3) Traceback (most recent call last): ... @@ -1621,7 +1619,7 @@ def _ne_to_south_path(self, coord): return LR_list -class KnutsonTaoPuzzleSolver(UniqueRepresentation): +class KnutsonTaoPuzzleSolver(): r""" Return puzzle solver function used to create all puzzles with given boundary conditions. @@ -1655,8 +1653,8 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces sage: H_grassmannian_pieces() - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) In the string representation, the nabla pieces are depicted as ``c\a/b``, where `a` is the label of the north edge, `b` is the label @@ -1667,15 +1665,15 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: KnutsonTaoPuzzleSolver(H_grassmannian_pieces()) Knutson-Tao puzzle solver with pieces: - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) The following shorthand to create the above puzzle solver is also supported:: sage: KnutsonTaoPuzzleSolver('H') Knutson-Tao puzzle solver with pieces: - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) The solver will compute all fillings of the puzzle with the given puzzle pieces. The user specifies the labels of north-east and @@ -1695,18 +1693,8 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: solns = ps('0101', '0101') sage: len(solns) 2 - sage: solns.sort(key=str) sage: solns - [{(1, 1): 0/0\0, - (1, 2): 1/\0 0\/1, - (1, 3): 0/\0 0\/0, - (1, 4): 1/\0 0\/1, - (2, 2): 1/1\1, - (2, 3): 0/\10 1\/1, - (2, 4): 1/\1 10\/0, - (3, 3): 1/1\1, - (3, 4): 0/\0 1\/10, - (4, 4): 10/0\1}, {(1, 1): 0/1\10, + [{(1, 1): 0/1\10, (1, 2): 1/\1 10\/0, (1, 3): 0/\0 1\/10, (1, 4): 1/\0 0\/1, @@ -1715,7 +1703,17 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (2, 4): 1/\1 1\/1, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, - (4, 4): 1/1\1}] + (4, 4): 1/1\1}, + {(1, 1): 0/0\0, + (1, 2): 1/\0 0\/1, + (1, 3): 0/\0 0\/0, + (1, 4): 1/\0 0\/1, + (2, 2): 1/1\1, + (2, 3): 0/\10 1\/1, + (2, 4): 1/\1 10\/0, + (3, 3): 1/1\1, + (3, 4): 0/\0 1\/10, + (4, 4): 10/0\1}] The pieces in a puzzle filling are indexed by pairs of nonnegative integers `(i, j)` with `1 \leq i \leq j \leq n`, where `n` is the @@ -1724,7 +1722,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: f = solns[0] sage: [f[i, i] for i in range(1,5)] - [0/0\0, 1/1\1, 1/1\1, 10/0\1] + [0/1\10, 0/0\0, 0/0\0, 1/1\1] The pieces indexed by `(i, j)` for `j > i` are a pair consisting of a delta piece and nabla piece glued together along the south edge and @@ -1732,7 +1730,7 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): sage: f = solns[0] sage: f[1, 2] - 1/\0 0\/1 + 1/\1 10\/0 There are various methods and options to display puzzle solutions. A single puzzle can be displayed using the plot method of the puzzle:: @@ -1762,18 +1760,8 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): Cohomology of the Grassmannian:: sage: ps = KnutsonTaoPuzzleSolver("H") - sage: solns = ps('0101', '0101') - sage: sorted(solns) - [{(1, 1): 0/0\0, - (1, 2): 1/\0 0\/1, - (1, 3): 0/\0 0\/0, - (1, 4): 1/\0 0\/1, - (2, 2): 1/1\1, - (2, 3): 0/\10 1\/1, - (2, 4): 1/\1 10\/0, - (3, 3): 1/1\1, - (3, 4): 0/\0 1\/10, - (4, 4): 10/0\1}, {(1, 1): 0/1\10, + sage: ps('0101', '0101') + [{(1, 1): 0/1\10, (1, 2): 1/\1 10\/0, (1, 3): 0/\0 1\/10, (1, 4): 1/\0 0\/1, @@ -1782,23 +1770,33 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (2, 4): 1/\1 1\/1, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, - (4, 4): 1/1\1}] + (4, 4): 1/1\1}, + {(1, 1): 0/0\0, + (1, 2): 1/\0 0\/1, + (1, 3): 0/\0 0\/0, + (1, 4): 1/\0 0\/1, + (2, 2): 1/1\1, + (2, 3): 0/\10 1\/1, + (2, 4): 1/\1 10\/0, + (3, 3): 1/1\1, + (3, 4): 0/\0 1\/10, + (4, 4): 10/0\1}] Equivariant puzzles:: sage: ps = KnutsonTaoPuzzleSolver("HT") - sage: solns = ps('0101', '0101') - sage: sorted(solns) - [{(1, 1): 0/0\0, - (1, 2): 1/\0 0\/1, - (1, 3): 0/\0 0\/0, + sage: ps('0101', '0101') + [{(1, 1): 0/1\10, + (1, 2): 1/\1 10\/0, + (1, 3): 0/\0 1\/10, (1, 4): 1/\0 0\/1, - (2, 2): 1/1\1, - (2, 3): 0/\1 1\/0, + (2, 2): 0/0\0, + (2, 3): 10/\1 0\/0, (2, 4): 1/\1 1\/1, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, - (4, 4): 1/1\1}, {(1, 1): 0/0\0, + (4, 4): 1/1\1}, + {(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (1, 3): 0/\0 0\/0, (1, 4): 1/\0 0\/1, @@ -1807,12 +1805,13 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (2, 4): 1/\1 10\/0, (3, 3): 1/1\1, (3, 4): 0/\0 1\/10, - (4, 4): 10/0\1}, {(1, 1): 0/1\10, - (1, 2): 1/\1 10\/0, - (1, 3): 0/\0 1\/10, + (4, 4): 10/0\1}, + {(1, 1): 0/0\0, + (1, 2): 1/\0 0\/1, + (1, 3): 0/\0 0\/0, (1, 4): 1/\0 0\/1, - (2, 2): 0/0\0, - (2, 3): 10/\1 0\/0, + (2, 2): 1/1\1, + (2, 3): 0/\1 1\/0, (2, 4): 1/\1 1\/1, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, @@ -1821,18 +1820,18 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): K-Theory puzzles:: sage: ps = KnutsonTaoPuzzleSolver("K") - sage: solns = ps('0101', '0101') - sage: sorted(solns) - [{(1, 1): 0/0\0, - (1, 2): 1/\0 0\/1, - (1, 3): 0/\0 0\/0, + sage: ps('0101', '0101') + [{(1, 1): 0/1\10, + (1, 2): 1/\1 10\/0, + (1, 3): 0/\0 1\/K, (1, 4): 1/\0 0\/1, - (2, 2): 1/1\1, - (2, 3): 0/\10 1\/1, - (2, 4): 1/\1 10\/0, + (2, 2): 0/0\0, + (2, 3): K/\K 0\/1, + (2, 4): 1/\1 K\/0, (3, 3): 1/1\1, (3, 4): 0/\0 1\/10, - (4, 4): 10/0\1}, {(1, 1): 0/1\10, + (4, 4): 10/0\1}, + {(1, 1): 0/1\10, (1, 2): 1/\1 10\/0, (1, 3): 0/\0 1\/10, (1, 4): 1/\0 0\/1, @@ -1841,13 +1840,14 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (2, 4): 1/\1 1\/1, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, - (4, 4): 1/1\1}, {(1, 1): 0/1\10, - (1, 2): 1/\1 10\/0, - (1, 3): 0/\0 1\/K, + (4, 4): 1/1\1}, + {(1, 1): 0/0\0, + (1, 2): 1/\0 0\/1, + (1, 3): 0/\0 0\/0, (1, 4): 1/\0 0\/1, - (2, 2): 0/0\0, - (2, 3): K/\K 0\/1, - (2, 4): 1/\1 K\/0, + (2, 2): 1/1\1, + (2, 3): 0/\10 1\/1, + (2, 4): 1/\1 10\/0, (3, 3): 1/1\1, (3, 4): 0/\0 1\/10, (4, 4): 10/0\1}] @@ -1855,23 +1855,23 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): Two-step puzzles:: sage: ps = KnutsonTaoPuzzleSolver("H2step") - sage: solns = ps('01201', '01021') - sage: sorted(solns) - [{(1, 1): 0/0\0, - (1, 2): 1/\0 0\/1, - (1, 3): 2/\0 0\/2, - (1, 4): 0/\0 0\/0, + sage: ps('01201', '01021') + [{(1, 1): 0/2\20, + (1, 2): 1/\21 20\/0, + (1, 3): 2/\2 21\/1, + (1, 4): 0/\0 2\/20, (1, 5): 1/\0 0\/1, - (2, 2): 1/2\21, - (2, 3): 2/\2 21\/1, - (2, 4): 0/\10 2\/21, - (2, 5): 1/\1 10\/0, + (2, 2): 0/0\0, + (2, 3): 1/\0 0\/1, + (2, 4): 20/\2 0\/0, + (2, 5): 1/\1 2\/21, (3, 3): 1/1\1, - (3, 4): 21/\2 1\/1, - (3, 5): 0/\0 2\/20, - (4, 4): 1/1\1, - (4, 5): 20/\2 1\/10, - (5, 5): 10/0\1}, {(1, 1): 0/1\10, + (3, 4): 0/\0 1\/10, + (3, 5): 21/\0 0\/21, + (4, 4): 10/0\1, + (4, 5): 21/\2 1\/1, + (5, 5): 1/1\1}, + {(1, 1): 0/1\10, (1, 2): 1/\1 10\/0, (1, 3): 2/\1 1\/2, (1, 4): 0/\0 1\/10, @@ -1885,56 +1885,104 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (3, 5): 1/\0 2\/2(10), (4, 4): 0/0\0, (4, 5): 2(10)/\2 0\/1, - (5, 5): 1/1\1}, {(1, 1): 0/2\20, - (1, 2): 1/\21 20\/0, - (1, 3): 2/\2 21\/1, - (1, 4): 0/\0 2\/20, + (5, 5): 1/1\1}, + {(1, 1): 0/0\0, + (1, 2): 1/\0 0\/1, + (1, 3): 2/\0 0\/2, + (1, 4): 0/\0 0\/0, (1, 5): 1/\0 0\/1, - (2, 2): 0/0\0, - (2, 3): 1/\0 0\/1, - (2, 4): 20/\2 0\/0, - (2, 5): 1/\1 2\/21, + (2, 2): 1/2\21, + (2, 3): 2/\2 21\/1, + (2, 4): 0/\10 2\/21, + (2, 5): 1/\1 10\/0, (3, 3): 1/1\1, - (3, 4): 0/\0 1\/10, - (3, 5): 21/\0 0\/21, - (4, 4): 10/0\1, - (4, 5): 21/\2 1\/1, - (5, 5): 1/1\1}] + (3, 4): 21/\2 1\/1, + (3, 5): 0/\0 2\/20, + (4, 4): 1/1\1, + (4, 5): 20/\2 1\/10, + (5, 5): 10/0\1}] + Two-step equivariant puzzles:: sage: ps = KnutsonTaoPuzzleSolver("HT2step") - sage: solns = ps('10212', '12012') - sage: sorted(solns) - [{(1, 1): 1/1\1, - (1, 2): 0/\(21)0 1\/2, - (1, 3): 2/\1 (21)0\/0, - (1, 4): 1/\1 1\/1, + sage: ps('10212', '12012') + [{(1, 1): 1/2\21, + (1, 2): 0/\21 21\/0, + (1, 3): 2/\2 21\/1, + (1, 4): 1/\1 2\/21, (1, 5): 2/\1 1\/2, - (2, 2): 2/2\2, - (2, 3): 0/\2 2\/0, - (2, 4): 1/\2 2\/1, + (2, 2): 0/1\10, + (2, 3): 1/\1 10\/0, + (2, 4): 21/\2 1\/1, (2, 5): 2/\2 2\/2, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, (3, 5): 2/\0 0\/2, (4, 4): 1/1\1, (4, 5): 2/\1 1\/2, - (5, 5): 2/2\2}, {(1, 1): 1/1\1, - (1, 2): 0/\(21)0 1\/2, - (1, 3): 2/\1 (21)0\/0, - (1, 4): 1/\1 1\/1, + (5, 5): 2/2\2}, + {(1, 1): 1/2\21, + (1, 2): 0/\20 21\/1, + (1, 3): 2/\2 20\/0, + (1, 4): 1/\1 2\/21, (1, 5): 2/\1 1\/2, - (2, 2): 2/2\2, - (2, 3): 0/\2 2\/0, - (2, 4): 1/\21 2\/2, - (2, 5): 2/\2 21\/1, + (2, 2): 1/1\1, + (2, 3): 0/\10 1\/1, + (2, 4): 21/\2 10\/0, + (2, 5): 2/\2 2\/2, + (3, 3): 1/1\1, + (3, 4): 0/\0 1\/10, + (3, 5): 2/\0 0\/2, + (4, 4): 10/0\1, + (4, 5): 2/\1 1\/2, + (5, 5): 2/2\2}, + {(1, 1): 1/2\21, + (1, 2): 0/\20 21\/1, + (1, 3): 2/\2 20\/0, + (1, 4): 1/\1 2\/21, + (1, 5): 2/\1 1\/2, + (2, 2): 1/1\1, + (2, 3): 0/\1 1\/0, + (2, 4): 21/\2 1\/1, + (2, 5): 2/\2 2\/2, (3, 3): 0/0\0, - (3, 4): 2/\0 0\/2, - (3, 5): 1/\0 0\/1, + (3, 4): 1/\0 0\/1, + (3, 5): 2/\0 0\/2, + (4, 4): 1/1\1, + (4, 5): 2/\1 1\/2, + (5, 5): 2/2\2}, + {(1, 1): 1/1\1, + (1, 2): 0/\10 1\/1, + (1, 3): 2/\10 10\/2, + (1, 4): 1/\1 10\/0, + (1, 5): 2/\1 1\/2, + (2, 2): 1/2\21, + (2, 3): 2/\2 21\/1, + (2, 4): 0/\20 2\/2, + (2, 5): 2/\2 20\/0, + (3, 3): 1/1\1, + (3, 4): 2/\1 1\/2, + (3, 5): 0/\0 1\/10, (4, 4): 2/2\2, - (4, 5): 1/\1 2\/21, - (5, 5): 21/1\2}, {(1, 1): 1/1\1, + (4, 5): 10/\1 2\/20, + (5, 5): 20/0\2}, + {(1, 1): 1/1\1, + (1, 2): 0/\10 1\/1, + (1, 3): 2/\10 10\/2, + (1, 4): 1/\1 10\/0, + (1, 5): 2/\1 1\/2, + (2, 2): 1/2\21, + (2, 3): 2/\2 21\/1, + (2, 4): 0/\2 2\/0, + (2, 5): 2/\2 2\/2, + (3, 3): 1/1\1, + (3, 4): 0/\0 1\/10, + (3, 5): 2/\0 0\/2, + (4, 4): 10/0\1, + (4, 5): 2/\1 1\/2, + (5, 5): 2/2\2}, + {(1, 1): 1/1\1, (1, 2): 0/\(21)0 1\/2, (1, 3): 2/\1 (21)0\/0, (1, 4): 1/\1 1\/1, @@ -1948,13 +1996,29 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (3, 5): 1/\0 0\/1, (4, 4): 20/0\2, (4, 5): 1/\1 2\/21, - (5, 5): 21/1\2}, {(1, 1): 1/1\1, - (1, 2): 0/\1 1\/0, - (1, 3): 2/\1 1\/2, + (5, 5): 21/1\2}, + {(1, 1): 1/1\1, + (1, 2): 0/\(21)0 1\/2, + (1, 3): 2/\1 (21)0\/0, (1, 4): 1/\1 1\/1, (1, 5): 2/\1 1\/2, - (2, 2): 0/2\20, - (2, 3): 2/\2 20\/0, + (2, 2): 2/2\2, + (2, 3): 0/\2 2\/0, + (2, 4): 1/\21 2\/2, + (2, 5): 2/\2 21\/1, + (3, 3): 0/0\0, + (3, 4): 2/\0 0\/2, + (3, 5): 1/\0 0\/1, + (4, 4): 2/2\2, + (4, 5): 1/\1 2\/21, + (5, 5): 21/1\2}, + {(1, 1): 1/1\1, + (1, 2): 0/\(21)0 1\/2, + (1, 3): 2/\1 (21)0\/0, + (1, 4): 1/\1 1\/1, + (1, 5): 2/\1 1\/2, + (2, 2): 2/2\2, + (2, 3): 0/\2 2\/0, (2, 4): 1/\2 2\/1, (2, 5): 2/\2 2\/2, (3, 3): 0/0\0, @@ -1962,7 +2026,8 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (3, 5): 2/\0 0\/2, (4, 4): 1/1\1, (4, 5): 2/\1 1\/2, - (5, 5): 2/2\2}, {(1, 1): 1/1\1, + (5, 5): 2/2\2}, + {(1, 1): 1/1\1, (1, 2): 0/\1 1\/0, (1, 3): 2/\1 1\/2, (1, 4): 1/\1 1\/1, @@ -1976,70 +2041,15 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (3, 5): 1/\0 0\/1, (4, 4): 2/2\2, (4, 5): 1/\1 2\/21, - (5, 5): 21/1\2}, {(1, 1): 1/1\1, - (1, 2): 0/\10 1\/1, - (1, 3): 2/\10 10\/2, - (1, 4): 1/\1 10\/0, - (1, 5): 2/\1 1\/2, - (2, 2): 1/2\21, - (2, 3): 2/\2 21\/1, - (2, 4): 0/\2 2\/0, - (2, 5): 2/\2 2\/2, - (3, 3): 1/1\1, - (3, 4): 0/\0 1\/10, - (3, 5): 2/\0 0\/2, - (4, 4): 10/0\1, - (4, 5): 2/\1 1\/2, - (5, 5): 2/2\2}, {(1, 1): 1/1\1, - (1, 2): 0/\10 1\/1, - (1, 3): 2/\10 10\/2, - (1, 4): 1/\1 10\/0, - (1, 5): 2/\1 1\/2, - (2, 2): 1/2\21, - (2, 3): 2/\2 21\/1, - (2, 4): 0/\20 2\/2, - (2, 5): 2/\2 20\/0, - (3, 3): 1/1\1, - (3, 4): 2/\1 1\/2, - (3, 5): 0/\0 1\/10, - (4, 4): 2/2\2, - (4, 5): 10/\1 2\/20, - (5, 5): 20/0\2}, {(1, 1): 1/2\21, - (1, 2): 0/\20 21\/1, - (1, 3): 2/\2 20\/0, - (1, 4): 1/\1 2\/21, - (1, 5): 2/\1 1\/2, - (2, 2): 1/1\1, - (2, 3): 0/\1 1\/0, - (2, 4): 21/\2 1\/1, - (2, 5): 2/\2 2\/2, - (3, 3): 0/0\0, - (3, 4): 1/\0 0\/1, - (3, 5): 2/\0 0\/2, - (4, 4): 1/1\1, - (4, 5): 2/\1 1\/2, - (5, 5): 2/2\2}, {(1, 1): 1/2\21, - (1, 2): 0/\20 21\/1, - (1, 3): 2/\2 20\/0, - (1, 4): 1/\1 2\/21, - (1, 5): 2/\1 1\/2, - (2, 2): 1/1\1, - (2, 3): 0/\10 1\/1, - (2, 4): 21/\2 10\/0, - (2, 5): 2/\2 2\/2, - (3, 3): 1/1\1, - (3, 4): 0/\0 1\/10, - (3, 5): 2/\0 0\/2, - (4, 4): 10/0\1, - (4, 5): 2/\1 1\/2, - (5, 5): 2/2\2}, {(1, 1): 1/2\21, - (1, 2): 0/\21 21\/0, - (1, 3): 2/\2 21\/1, - (1, 4): 1/\1 2\/21, + (5, 5): 21/1\2}, + {(1, 1): 1/1\1, + (1, 2): 0/\1 1\/0, + (1, 3): 2/\1 1\/2, + (1, 4): 1/\1 1\/1, (1, 5): 2/\1 1\/2, - (2, 2): 0/1\10, - (2, 3): 1/\1 10\/0, - (2, 4): 21/\2 1\/1, + (2, 2): 0/2\20, + (2, 3): 2/\2 20\/0, + (2, 4): 1/\2 2\/1, (2, 5): 2/\2 2\/2, (3, 3): 0/0\0, (3, 4): 1/\0 0\/1, @@ -2074,50 +2084,9 @@ class KnutsonTaoPuzzleSolver(UniqueRepresentation): (5, 5): 2(1)/1\2}] """ - def __init__(self, puzzle_pieces): + def __init__(self, puzzle_pieces, max_letter=None): r""" Knutson-Tao puzzle solver. - - TESTS: - - Check that UniqueRepresentation works:: - - sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver, H_grassmannian_pieces - sage: ps = KnutsonTaoPuzzleSolver(H_grassmannian_pieces()) - sage: qs = KnutsonTaoPuzzleSolver("H") - sage: ps - Knutson-Tao puzzle solver with pieces: - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] - sage: qs - Knutson-Tao puzzle solver with pieces: - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] - sage: ps == qs - True - """ - self._puzzle_pieces = puzzle_pieces - self._rhombus_pieces = tuple(puzzle_pieces.rhombus_pieces()) - self._bottom_deltas = tuple(puzzle_pieces.boundary_deltas()) - - @staticmethod - def __classcall_private__(cls, puzzle_pieces, max_letter=None): - r""" - TESTS:: - - sage: from sage.combinat.knutson_tao_puzzles import * - sage: KnutsonTaoPuzzleSolver(H_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("H") # indirect doctest - True - sage: KnutsonTaoPuzzleSolver(HT_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("HT") - True - sage: KnutsonTaoPuzzleSolver(K_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("K") - True - sage: KnutsonTaoPuzzleSolver(H_two_step_pieces()) == KnutsonTaoPuzzleSolver("H2step") - True - sage: KnutsonTaoPuzzleSolver(HT_two_step_pieces()) == KnutsonTaoPuzzleSolver("HT2step") - True - sage: KnutsonTaoPuzzleSolver(BK_pieces(3)) == KnutsonTaoPuzzleSolver("BK",3) - True """ if isinstance(puzzle_pieces, str): if puzzle_pieces == "H": @@ -2135,7 +2104,9 @@ def __classcall_private__(cls, puzzle_pieces, max_letter=None): puzzle_pieces = BK_pieces(max_letter) else: raise ValueError("max_letter needs to be specified") - return super().__classcall__(cls, puzzle_pieces) + self._puzzle_pieces = puzzle_pieces + self._rhombus_pieces = puzzle_pieces.rhombus_pieces() + self._bottom_deltas = puzzle_pieces.boundary_deltas() def __call__(self, lam, mu, algorithm='strips'): r""" @@ -2181,8 +2152,8 @@ def __repr__(self) -> str: sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: KnutsonTaoPuzzleSolver('H') Knutson-Tao puzzle solver with pieces: - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) """ return "Knutson-Tao puzzle solver with pieces:\n%s" % self._puzzle_pieces @@ -2195,8 +2166,9 @@ def puzzle_pieces(self): sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver('H') sage: ps.puzzle_pieces() - Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1] - Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1] + Nablas : (0\0/0, 1\1/1, 10\1/0, 0\10/1, 1\0/10) + Deltas : (0/0\0, 1/1\1, 0/1\10, 1/10\0, 10/0\1) + """ return self._puzzle_pieces From 8e8fa580ab1c3cbabaa688bd3484d892f472e00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 25 Feb 2025 09:38:58 +0000 Subject: [PATCH 05/15] Removed redundancy in variable names --- src/sage/combinat/skew_tableau.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 8b1b253c570..a66a98bdecd 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1868,8 +1868,6 @@ def to_KTpuzzle(self, size=None): INPUT: - - ``tableau`` -- a Littlewood--Richardson SkewTableau - - ``size`` -- the size of the output Knutson--Tao puzzle (optional) TESTS:: @@ -1907,18 +1905,15 @@ def to_KTpuzzle(self, size=None): tab_w = self.weight() tab_out = self.outer_shape() tab_inn = self.inner_shape() - L = len(self) if size is None: - size = max(tab_w[0] + L, tab_out[0] + L) - assert size >= max(tab_w[0] + L, tab_out[0] + L), "the puzzle size inputted is too small" - - n = size + size = max(tab_w[0] + len(self), tab_out[0] + len(self)) + assert size >= max(tab_w[0] + len(self), tab_out[0] + len(self)), "the puzzle size inputted is too small" - lam = Partition(tab_w).to_abacus(size=size, ones=L)[::-1] - mu = [(n - L) - r for r in tab_out][::-1] - mu = Partition(mu).to_abacus(size=size, ones=L)[::-1] - nu = Partition(tab_inn).to_abacus(size=size, ones=L) + lam = Partition(tab_w).to_abacus(size=size, ones=len(self))[::-1] + mu = [(size - len(self)) - r for r in tab_out][::-1] + mu = Partition(mu).to_abacus(size=size, ones=len(self))[::-1] + nu = Partition(tab_inn).to_abacus(size=size, ones=len(self)) # Initialize puzzle @@ -1926,11 +1921,11 @@ def to_KTpuzzle(self, size=None): # Find the locations of 1-triangles (blue by default in the plot) - chosenCols = [i+1 for i in range(n) if nu[i] == '1'] - chosenRows = [i+1 for i in range(n) if lam[i] == '1'] + chosenCols = [i+1 for i in range(size) if nu[i] == '1'] + chosenRows = [i+1 for i in range(size) if lam[i] == '1'] delta_blue_positions = [] nabla_blue_positions = [] - for col in range(L): + for col in range(len(self)): propagationRow = [] propagationCol = [] for row in range(col+1): @@ -1939,7 +1934,7 @@ def to_KTpuzzle(self, size=None): delta_blue_positions.append((j, i)) - k = self[L-col+row-1].count(row+1) + k = self[len(self)-col+row-1].count(row+1) nabla_blue_positions.append((j+k, i+k+1)) propagationCol.insert(0, j+k) @@ -1950,7 +1945,7 @@ def to_KTpuzzle(self, size=None): # Create a dictionary of boundaries # (not all boundaries are in the dictionary) - D = {(i,j) : {} for i in range(1,n+1) for j in range(i,n+1)} + D = {(i,j) : {} for i in range(1,size+1) for j in range(i,size+1)} for (i,j) in delta_blue_positions: D[(i,j)]['north_west'] = '1' D[(i,j)]['north_east'] = '1' @@ -1978,10 +1973,10 @@ def to_KTpuzzle(self, size=None): D[(a,b)]['south_west'] = '1' D[(a+1,b)]['north_east'] = '1' D[(a+1,b)]['north_west'] = '10' - for i in range(n): + for i in range(size): D[(1,i+1)]['north_west'] = lam[i] D[(i+1,i+1)]['south'] = nu[i] - D[(i+1,n)]['north_east'] = mu[i] + D[(i+1,size)]['north_east'] = mu[i] # Now fill piece by piece # (like KnutsonTaoPuzzleSolver._fill_puzzle_by_pieces From 5667c764476c0a8ffac52ee03482bd9e545654e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 10:56:25 +0000 Subject: [PATCH 06/15] Changed names to remove acronyms --- src/sage/combinat/knutson_tao_puzzles.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index e3adfd54e0c..2115a0b54e0 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -11,7 +11,7 @@ - Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (2013): initial version at Sage Days 45, ICERM - Elizabeth Beazley, Ed Richmond (2013): testing -- Álvaro Gutiérrez (2025-02-24): added ``.to_LRtableaux()`` +- Álvaro Gutiérrez (2025-02-24): added ``to_littlewood_richarsdon_tableau`` - Julian Rüth (2025-02-24): clean up code .. TODO:: @@ -1487,7 +1487,7 @@ def tikzlabels(color, k, d, i, label1, label2, label3): return s - def to_LRtableau(self): + def to_littlewood_richarsdon_tableau(self): r""" Creates a skew Littlewood--Richardson tableau from a puzzle. @@ -1506,14 +1506,14 @@ def to_LRtableau(self): OUTPUT: - - a LR skew tableau + - a Littlewood--Richardson skew tableau EXAMPLES:: sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver("H") sage: solns = ps('010101','010101') - sage: [puzzle.to_LRtableau() for puzzle in solns] + sage: [puzzle.to_littlewood_richarsdon_tableau() for puzzle in solns] [[[None, None, None], [1, 1], [2]], [[None, None, 1], [None, 1], [2]], [[None, None, 1], [None, 2], [1]], @@ -1522,7 +1522,7 @@ def to_LRtableau(self): ....: ps = KnutsonTaoPuzzleSolver('H') ....: solns = ps('00000010001000010100', '00000000100010010100') ....: puzzle = solns[168] - ....: tab = puzzle.to_LRtableau(); tab.pp() + ....: tab = puzzle.to_littlewood_richarsdon_tableau(); tab.pp() . . . . . . . . . . 1 1 1 1 . . . . . . . 1 1 1 2 2 2 . . . . . 1 1 2 2 3 3 @@ -1547,7 +1547,7 @@ def to_LRtableau(self): def _ne_to_south_path(self, coord): r""" - Returns the content row of the LR skew tableau corresponding to ``coord``. + Return the content row of the Littlewood--Richardson skew tableau corresponding to ``coord``. This method traces out a path from ``coord`` to its "mirror" coordinate. If ``coord`` specifies the `i`-th 1 from the top on the north-east border @@ -1569,7 +1569,7 @@ def _ne_to_south_path(self, coord): OUTPUT: - - a list of numbers giving the content of one row in the LR tableau + - a list of numbers giving the content of one row in the Littlewood--Richardson tableau TESTS:: From 93cf2756176d70118b11ee26b525501b3e9c83e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 10:58:20 +0000 Subject: [PATCH 07/15] Corrected typo in docstrings --- src/sage/combinat/partition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 3879cb0101a..317962e99c0 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -9732,7 +9732,7 @@ def _an_element_(self): def abacus_to_partition(abacus): r""" - Returns a partition from an abacus. + Return a partition from an abacus. An abacus is a function `w : \mathbb{Z} \to \{0,1\}` such that `w(n) = 0` for `n \ll 0` and `w(n) = 1` for `n \gg 0`. It is usually From cacd93d888cb8cf943c922468e8210681ba2dba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 10:58:55 +0000 Subject: [PATCH 08/15] Changed names to remove acronyms --- src/sage/combinat/skew_tableau.py | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index a66a98bdecd..ec49715a8d0 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -7,7 +7,7 @@ - Travis Scrimshaw, Arthur Lubovsky (2013-02-11): Factored out ``CombinatorialClass`` - Trevor K. Karn (2022-08-03): added ``backward_slide`` -- Álvaro Gutiérrez (2025-02-24): added ``to_KTpuzzle`` +- Álvaro Gutiérrez (2025-02-24): added ``to_knutson_tao_puzzle`` """ # **************************************************************************** @@ -1842,26 +1842,26 @@ def is_k_tableau(self, k) -> bool: return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) - def is_LR(self): + def is_littlewood_richarsdon(self): r""" Checks whether ``self`` is a Littlewood--Richardson tableau. - A Littlewood--Richardson tableau (LR tableau) is a semistandard skew tableau whose + A Littlewood--Richardson tableau is a semistandard skew tableau whose (row reading) word is Yamanouchi. EXAMPLES:: - sage: SkewTableau([[None,1],[1,2]]).is_LR() + sage: SkewTableau([[None,1],[1,2]]).is_littlewood_richarsdon() True - sage: SkewTableau([[None,1],[2,1]]).is_LR() + sage: SkewTableau([[None,1],[2,1]]).is_littlewood_richarsdon() False - sage: SkewTableau([[None,1],[2,2]]).is_LR() + sage: SkewTableau([[None,1],[2,2]]).is_littlewood_richarsdon() False """ return self.is_semistandard() and self.to_word().is_yamanouchi() - def to_KTpuzzle(self, size=None): + def to_knutson_tao_puzzle(self, size=None): r""" Takes a Littlewood--Richardson tableau and returns a Knutson--Tao puzzle. @@ -1870,6 +1870,16 @@ def to_KTpuzzle(self, size=None): - ``size`` -- the size of the output Knutson--Tao puzzle (optional) + EXAMPLES:: + + sage: ps = KnutsonTaoPuzzleSolver("H") + sage: puzzle = ps('01010','01001')[0] + sage: tab = puzzle.to_littlewood_richarsdon_tableau(); tab + [[None, 1, 1], [2]] + sage: puzzle2 = tab.to_knutson_tao_puzzle() + sage: puzzle == puzzle2 + True + TESTS:: sage: # Example from Purbhoo07 @@ -1878,24 +1888,14 @@ def to_KTpuzzle(self, size=None): ....: [None]*8 + [1]*2 + [2]*3, ....: [None]*5 + [1]*2 + [2]*2 + [3]*2, ....: [None] + [1]*2 + [2]*2 + [3] + [4]*2]) - sage: puzzle = tab.to_KTpuzzle(20) + sage: puzzle = tab.to_knutson_tao_puzzle(20) sage: puzzle[(5,10)] 1/\0 0\/1 sage: ''.join(puzzle.south_labels()) '01000010001001000000' sage: # puzzle.plot() # not tested - - EXAMPLES:: - - sage: ps = KnutsonTaoPuzzleSolver("H") - sage: puzzle = ps('01010','01001')[0] - sage: tab = puzzle.to_LRtableau(); tab - [[None, 1, 1], [2]] - sage: puzzle2 = tab.to_KTpuzzle() - sage: puzzle == puzzle2 - True """ - assert self.is_LR(), "this method only applies to Littlewood-Richardson tableaux" + assert self.is_littlewood_richarsdon(), "this method only applies to Littlewood-Richardson tableaux" from sage.combinat.partition import abacus_to_partition from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces, KnutsonTaoPuzzleSolver, PuzzleFilling From 86b43050d9954fa1dd7673b36a9facbc175f78bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 11:12:38 +0000 Subject: [PATCH 09/15] Fix typo "richarSDon" to "richarDSon" --- src/sage/combinat/knutson_tao_puzzles.py | 8 ++++---- src/sage/combinat/skew_tableau.py | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 2115a0b54e0..7f33d0ca9a6 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -11,7 +11,7 @@ - Franco Saliola, Allen Knutson, Avinash Dalal, Anne Schilling (2013): initial version at Sage Days 45, ICERM - Elizabeth Beazley, Ed Richmond (2013): testing -- Álvaro Gutiérrez (2025-02-24): added ``to_littlewood_richarsdon_tableau`` +- Álvaro Gutiérrez (2025-02-24): added ``to_littlewood_richardson_tableau`` - Julian Rüth (2025-02-24): clean up code .. TODO:: @@ -1487,7 +1487,7 @@ def tikzlabels(color, k, d, i, label1, label2, label3): return s - def to_littlewood_richarsdon_tableau(self): + def to_littlewood_richardson_tableau(self): r""" Creates a skew Littlewood--Richardson tableau from a puzzle. @@ -1513,7 +1513,7 @@ def to_littlewood_richarsdon_tableau(self): sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver sage: ps = KnutsonTaoPuzzleSolver("H") sage: solns = ps('010101','010101') - sage: [puzzle.to_littlewood_richarsdon_tableau() for puzzle in solns] + sage: [puzzle.to_littlewood_richardson_tableau() for puzzle in solns] [[[None, None, None], [1, 1], [2]], [[None, None, 1], [None, 1], [2]], [[None, None, 1], [None, 2], [1]], @@ -1522,7 +1522,7 @@ def to_littlewood_richarsdon_tableau(self): ....: ps = KnutsonTaoPuzzleSolver('H') ....: solns = ps('00000010001000010100', '00000000100010010100') ....: puzzle = solns[168] - ....: tab = puzzle.to_littlewood_richarsdon_tableau(); tab.pp() + ....: tab = puzzle.to_littlewood_richardson_tableau(); tab.pp() . . . . . . . . . . 1 1 1 1 . . . . . . . 1 1 1 2 2 2 . . . . . 1 1 2 2 3 3 diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index ec49715a8d0..87d8c9f1cf2 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1842,7 +1842,7 @@ def is_k_tableau(self, k) -> bool: return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) - def is_littlewood_richarsdon(self): + def is_littlewood_richardson(self): r""" Checks whether ``self`` is a Littlewood--Richardson tableau. @@ -1851,11 +1851,11 @@ def is_littlewood_richarsdon(self): EXAMPLES:: - sage: SkewTableau([[None,1],[1,2]]).is_littlewood_richarsdon() + sage: SkewTableau([[None,1],[1,2]]).is_littlewood_richardson() True - sage: SkewTableau([[None,1],[2,1]]).is_littlewood_richarsdon() + sage: SkewTableau([[None,1],[2,1]]).is_littlewood_richardson() False - sage: SkewTableau([[None,1],[2,2]]).is_littlewood_richarsdon() + sage: SkewTableau([[None,1],[2,2]]).is_littlewood_richardson() False """ @@ -1874,7 +1874,7 @@ def to_knutson_tao_puzzle(self, size=None): sage: ps = KnutsonTaoPuzzleSolver("H") sage: puzzle = ps('01010','01001')[0] - sage: tab = puzzle.to_littlewood_richarsdon_tableau(); tab + sage: tab = puzzle.to_littlewood_richardson_tableau(); tab [[None, 1, 1], [2]] sage: puzzle2 = tab.to_knutson_tao_puzzle() sage: puzzle == puzzle2 @@ -1895,7 +1895,7 @@ def to_knutson_tao_puzzle(self, size=None): '01000010001001000000' sage: # puzzle.plot() # not tested """ - assert self.is_littlewood_richarsdon(), "this method only applies to Littlewood-Richardson tableaux" + assert self.is_littlewood_richardson(), "this method only applies to Littlewood-Richardson tableaux" from sage.combinat.partition import abacus_to_partition from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces, KnutsonTaoPuzzleSolver, PuzzleFilling From 0163476039593a232b0c93252f0c6d54a539e24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 14:17:32 +0000 Subject: [PATCH 10/15] Fix imperative docstrings --- src/sage/combinat/knutson_tao_puzzles.py | 2 +- src/sage/combinat/skew_tableau.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 7f33d0ca9a6..13f1d1d3982 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -1489,7 +1489,7 @@ def tikzlabels(color, k, d, i, label1, label2, label3): def to_littlewood_richardson_tableau(self): r""" - Creates a skew Littlewood--Richardson tableau from a puzzle. + Create a skew Littlewood--Richardson tableau from a puzzle. We follow the bijection given in [Purbhoo07]_. A similar but different bijection is given in [Vakil03]_. diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 87d8c9f1cf2..2af0d5ca563 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1844,7 +1844,7 @@ def is_k_tableau(self, k) -> bool: def is_littlewood_richardson(self): r""" - Checks whether ``self`` is a Littlewood--Richardson tableau. + Check whether ``self`` is a Littlewood--Richardson tableau. A Littlewood--Richardson tableau is a semistandard skew tableau whose (row reading) word is Yamanouchi. @@ -1863,7 +1863,7 @@ def is_littlewood_richardson(self): def to_knutson_tao_puzzle(self, size=None): r""" - Takes a Littlewood--Richardson tableau and returns a Knutson--Tao puzzle. + Take a Littlewood--Richardson tableau and return a Knutson--Tao puzzle. INPUT: From e571b211b1a5c8245d5206817f4aea9f40d4222a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 14:21:02 +0000 Subject: [PATCH 11/15] Fix docstring --- src/sage/combinat/skew_tableau.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 2af0d5ca563..6d8c8399aba 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1863,7 +1863,7 @@ def is_littlewood_richardson(self): def to_knutson_tao_puzzle(self, size=None): r""" - Take a Littlewood--Richardson tableau and return a Knutson--Tao puzzle. + Return a Knutson--Tao puzzle. INPUT: From 0b6a35783c81e26c21fe941c16b2ceebff61eb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 14:24:25 +0000 Subject: [PATCH 12/15] Improve readability of dosctrings --- src/sage/combinat/partition.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 317962e99c0..3e2180de392 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -5817,7 +5817,7 @@ def tabloid_module(self, base_ring=None): def to_abacus(self, size=0, ones=0): r""" - Return an abacus from a partition. + Return an abacus. This is the inverse to :func:`.abacus_to_partition`. @@ -5832,9 +5832,10 @@ def to_abacus(self, size=0, ones=0): convention. For each vertical step, record a 1; for each horizontal step record a 0. The resulting word is the corresponding abacus. - Additionally, if ``size`` is given, the abacus will be of length at least - ``size`` (by padding with 0s on the right). The number of 1s in the abacus - will be at least ``ones``. + The abacus will be of length at least ``size``, by padding with + 0s on the right if necessary. The number of 1s in + the abacus will be at least ``ones``, by padding with 1s on the + left if necessary. INPUT: From 155065d59c92d3d8df82a970c870c733db3420c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 14:47:24 +0000 Subject: [PATCH 13/15] Delete trailing whitespace --- src/sage/combinat/partition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 3e2180de392..9470cc9b4fa 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -5832,7 +5832,7 @@ def to_abacus(self, size=0, ones=0): convention. For each vertical step, record a 1; for each horizontal step record a 0. The resulting word is the corresponding abacus. - The abacus will be of length at least ``size``, by padding with + The abacus will be of length at least ``size``, by padding with 0s on the right if necessary. The number of 1s in the abacus will be at least ``ones``, by padding with 1s on the left if necessary. From d71676dd43385212e17d50651383db30c0e8d3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 16:55:04 +0000 Subject: [PATCH 14/15] Fix docstring formatting, clean up iteration over dicts --- src/sage/combinat/knutson_tao_puzzles.py | 1 - src/sage/combinat/partition.py | 13 ++++++++----- src/sage/combinat/skew_tableau.py | 18 ++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 13f1d1d3982..20524d89472 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -1584,7 +1584,6 @@ def _ne_to_south_path(self, coord): Traceback (most recent call last): ... AssertionError: the coordinate needs to be a coordinate of a 1 on the north-east boundary - """ assert self._ne_labels[coord-1] == '1', "the coordinate needs to be a coordinate of a 1 on the north-east boundary" diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 9470cc9b4fa..c898256e98b 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -5824,7 +5824,7 @@ def to_abacus(self, size=0, ones=0): An abacus is a function `w : \mathbb{Z} \to \{0,1\}` such that `w(n) = 0` for `n \ll 0` and `w(n) = 1` for `n \gg 0`. It is usually represented with an infinite tuple, e.g. `(...,0,0,0,1,0,0,1,0,1,1,...)`. - Here, we use finite tuples, and assume everything to the left is a 0 + Here we use finite tuples and assume everything to the left is a 0 and everything to the right is a 1. A partition determines an abacus via the following interpretation: @@ -5833,9 +5833,8 @@ def to_abacus(self, size=0, ones=0): step record a 0. The resulting word is the corresponding abacus. The abacus will be of length at least ``size``, by padding with - 0s on the right if necessary. The number of 1s in - the abacus will be at least ``ones``, by padding with 1s on the - left if necessary. + 0s on the right if necessary. The number of 1s in the abacus will + be at least ``ones``, by padding with 1s on the left if necessary. INPUT: @@ -9769,11 +9768,15 @@ def abacus_to_partition(abacus): [] sage: abacus_to_partition(['0','0','0','1','1','1']) [3, 3, 3] + sage: abacus_to_partition('--*-**') + Traceback (most recent call last): + ... + ValueError: an abacus should be a tuple, list or string of 0s and 1s """ part = [] n = len(abacus) k = 0 - for i in range(0,n): + for i in range(n): if abacus[i] == '1' or abacus[i] == 1: k += 1 part.insert(0, i+1-k) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 6d8c8399aba..e109717031a 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1857,7 +1857,6 @@ def is_littlewood_richardson(self): False sage: SkewTableau([[None,1],[2,2]]).is_littlewood_richardson() False - """ return self.is_semistandard() and self.to_word().is_yamanouchi() @@ -1865,7 +1864,6 @@ def to_knutson_tao_puzzle(self, size=None): r""" Return a Knutson--Tao puzzle. - INPUT: - ``size`` -- the size of the output Knutson--Tao puzzle (optional) @@ -1893,7 +1891,7 @@ def to_knutson_tao_puzzle(self, size=None): 1/\0 0\/1 sage: ''.join(puzzle.south_labels()) '01000010001001000000' - sage: # puzzle.plot() # not tested + sage: puzzle.plot() # not tested """ assert self.is_littlewood_richardson(), "this method only applies to Littlewood-Richardson tableaux" @@ -1946,26 +1944,26 @@ def to_knutson_tao_puzzle(self, size=None): # (not all boundaries are in the dictionary) D = {(i,j) : {} for i in range(1,size+1) for j in range(i,size+1)} - for (i,j) in delta_blue_positions: + for i,j in delta_blue_positions: D[(i,j)]['north_west'] = '1' D[(i,j)]['north_east'] = '1' - (a, b) = (i, j) + a, b = (i, j) while ((a-1, b) not in nabla_blue_positions and a > 1): a -= 1 D[(a,b)]['north_east'] = '0' D[(a,b)]['north_west'] = '1' D[(a,b)]['south_east'] = '1' D[(a,b)]['south_west'] = '0' - (a, b) = (i, j) + a, b = (i, j) while ((a, b) not in nabla_blue_positions and b > a): b -= 1 D[(a,b)]['north_west'] = '0' D[(a,b)]['north_east'] = '10' - for (i,j) in nabla_blue_positions: + for i,j in nabla_blue_positions: if (i,j) in D.keys(): D[(i,j)]['south_west'] = '1' D[(i,j)]['south_east'] = '1' - (a, b) = (i, j) + a, b = (i, j) while ((a, b-1) not in delta_blue_positions and a > 0): a -= 1 b -= 1 @@ -1990,7 +1988,7 @@ def to_knutson_tao_puzzle(self, size=None): dirs = ('north_east', 'north_west', 'south') triangles = sorted(all_pieces.delta_pieces(), key=lambda p : ''.join(p[dir] for dir in dirs)) - for (i,j) in D.keys(): + for i,j in D: candidates = [] if i == j: pieces = triangles @@ -2000,7 +1998,7 @@ def to_knutson_tao_puzzle(self, size=None): dirs = ('north_east', 'north_west', 'south_east', 'south_west') # Check what pieces have the desired boundaries for piece in pieces: - if all(piece[dir] == D[(i,j)][dir] for dir in dirs if dir in D[(i,j)].keys()): + if all(piece[dir] == D[(i,j)][dir] for dir in dirs if dir in D[(i,j)]): candidates.append(piece) # Place the smallest possible piece (the one with most 0s) puzzle._squares[(i,j)] = candidates[0] From 112b03571d337048032f049405bd6a1ec15382a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Guti=C3=A9rrez?= Date: Tue, 4 Mar 2025 16:59:13 +0000 Subject: [PATCH 15/15] Clean up code --- src/sage/combinat/skew_tableau.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index e109717031a..b09046e6d72 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1947,23 +1947,23 @@ def to_knutson_tao_puzzle(self, size=None): for i,j in delta_blue_positions: D[(i,j)]['north_west'] = '1' D[(i,j)]['north_east'] = '1' - a, b = (i, j) + a, b = i, j while ((a-1, b) not in nabla_blue_positions and a > 1): a -= 1 D[(a,b)]['north_east'] = '0' D[(a,b)]['north_west'] = '1' D[(a,b)]['south_east'] = '1' D[(a,b)]['south_west'] = '0' - a, b = (i, j) + a, b = i, j while ((a, b) not in nabla_blue_positions and b > a): b -= 1 D[(a,b)]['north_west'] = '0' D[(a,b)]['north_east'] = '10' - for i,j in nabla_blue_positions: - if (i,j) in D.keys(): + for i, j in nabla_blue_positions: + if (i,j) in D: D[(i,j)]['south_west'] = '1' D[(i,j)]['south_east'] = '1' - a, b = (i, j) + a, b = i, j while ((a, b-1) not in delta_blue_positions and a > 0): a -= 1 b -= 1 @@ -1988,7 +1988,7 @@ def to_knutson_tao_puzzle(self, size=None): dirs = ('north_east', 'north_west', 'south') triangles = sorted(all_pieces.delta_pieces(), key=lambda p : ''.join(p[dir] for dir in dirs)) - for i,j in D: + for i, j in D: candidates = [] if i == j: pieces = triangles