def __classcall_private__(cls, t, weight): r""" Implements the shortcut ``LittlewoodRichardsonTableau(t, weight)`` to ``LittlewoodRichardsonTableaux(shape , weight)(t)`` where ``shape`` is the shape of the tableau. TESTS:: sage: LR = LittlewoodRichardsonTableaux([3,2,1],[[2,1],[2,1]]) sage: t = LR([[1, 1, 3], [2, 3], [4]]) sage: t.check() sage: type(t) <class 'sage.combinat.lr_tableau.LittlewoodRichardsonTableaux_with_category.element_class'> sage: TestSuite(t).run() sage: from sage.combinat.lr_tableau import LittlewoodRichardsonTableau sage: LittlewoodRichardsonTableau([[1,1,3],[2,3],[4]], [[2,1],[2,1]]) [[1, 1, 3], [2, 3], [4]] """ if isinstance(t, cls): return t tab = SemistandardTableau(list(t)) shape = tab.shape() return LittlewoodRichardsonTableaux(shape, weight)(t)
def __classcall_private__(cls, t, weight): r""" Implements the shortcut ``LittlewoodRichardsonTableau(t, weight)`` to ``LittlewoodRichardsonTableaux(shape , weight)(t)`` where ``shape`` is the shape of the tableau. TESTS:: sage: LR = LittlewoodRichardsonTableaux([3,2,1],[[2,1],[2,1]]) sage: t = LR([[1, 1, 3], [2, 3], [4]]) sage: t.check() sage: type(t) <class 'sage.combinat.lr_tableau.LittlewoodRichardsonTableaux_with_category.element_class'> sage: TestSuite(t).run() sage: from sage.combinat.lr_tableau import LittlewoodRichardsonTableau sage: LittlewoodRichardsonTableau([[1,1,3],[2,3],[4]], [[2,1],[2,1]]) [[1, 1, 3], [2, 3], [4]] """ if isinstance(t, cls): return t tab = SemistandardTableau(list(t)) shape = tab.shape() return LittlewoodRichardsonTableaux(shape, weight)(t)
def to_semistandard_tableau(self): """ Return the semistandard tableau corresponding the monotone triangle corresponding to ``self``. EXAMPLES:: sage: A = AlternatingSignMatrices(3) sage: A([[0,0,1],[1,0,0],[0,1,0]]).to_semistandard_tableau() [[1, 1, 3], [2, 3], [3]] sage: t = A([[0,1,0],[1,-1,1],[0,1,0]]).to_semistandard_tableau(); t [[1, 1, 2], [2, 3], [3]] sage: parent(t) Semistandard tableaux """ from sage.combinat.tableau import SemistandardTableau, SemistandardTableaux mt = self.to_monotone_triangle() ssyt = [[0]*(len(mt) - j) for j in range(len(mt))] for i in range(len(mt)): for j in range(len(mt[i])): ssyt[i][j] = mt[j][-(i+1)] return SemistandardTableau(ssyt)
def hecke_insertion(obj1, obj2=None): """ Return the Hecke insertion of the pair ``[obj1, obj2]``. .. SEEALSO:: :func:`RSK` EXAMPLES:: sage: w = [5, 4, 1, 3, 4, 2, 5, 1, 2, 1, 4, 2, 4] sage: RSK(w, insertion='hecke') [[[1, 2, 4, 5], [2, 4, 5], [3, 5], [4], [5]], [[(1,), (4,), (5,), (7,)], [(2,), (9,), (11, 13)], [(3,), (12,)], [(6,)], [(8, 10)]]] """ if obj2 is None: obj2 = obj1 obj1 = range(1,len(obj2)+1) from sage.combinat.tableau import SemistandardTableau, Tableau from bisect import bisect_right p = [] #the "insertion" tableau q = [] #the "recording" tableau for i, x in izip(obj1, obj2): for j,r in enumerate(p): if r[-1] > x: #Figure out where to insert x into the row r. The #bisect command returns the position of the least #element of r greater than x. We will call it y. y_pos = bisect_right(r, x) y = r[y_pos] # Check to see if we can swap x for y if (y_pos == 0 or r[y_pos-1] < x) and (j == 0 or p[j-1][y_pos] < x): r[y_pos] = x x = y else: # We must have len(p[j-1]) > len(r), since x is coming # from the previous row. if r[-1] < x and (j == 0 or p[j-1][len(r)] < x): # We can add a box to the row r.append(x) q[j].append((i,)) # Values are always inserted to the right else: # We must append i to the bottom of this column l = len(r) - 1 while j < len(q) and len(q[j]) > l: j += 1 q[j-1][-1] = q[j-1][-1] + (i,) break else: #We made through all of the rows of p without breaking #so we need to add a new row to p and q. p.append([x]) q.append([(i,)]) return [SemistandardTableau(p), Tableau(q)]
def RSK(obj1=None, obj2=None, insertion='RSK', check_standard=False, **options): r""" Perform the Robinson-Schensted-Knuth (RSK) correspondence. The Robinson-Schensted-Knuth (RSK) correspondence (also known as the RSK algorithm) is most naturally stated as a bijection between generalized permutations (also known as two-line arrays, biwords, ...) and pairs of semi-standard Young tableaux `(P, Q)` of identical shape. The tableau `P` is known as the insertion tableau, and `Q` is known as the recording tableau. The basic operation is known as row insertion `P \leftarrow k` (where `P` is a given semi-standard Young tableau, and `k` is an integer). Row insertion is a recursive algorithm which starts by setting `k_0 = k`, and in its `i`-th step inserts the number `k_i` into the `i`-th row of `P` (we start counting the rows at `0`) by replacing the first integer greater than `k_i` in the row by `k_i` and defines `k_{i+1}` as the integer that has been replaced. If no integer greater than `k_i` exists in the `i`-th row, then `k_i` is simply appended to the row and the algorithm terminates at this point. Now the RSK algorithm, applied to a generalized permutation `p = ((j_0, k_0), (j_1, k_1), \ldots, (j_{\ell-1}, k_{\ell-1}))` (encoded as a lexicographically sorted list of pairs) starts by initializing two semi-standard tableaux `P_0` and `Q_0` as empty tableaux. For each nonnegative integer `t` starting at `0`, take the pair `(j_t, k_t)` from `p` and set `P_{t+1} = P_t \leftarrow k_t`, and define `Q_{t+1}` by adding a new box filled with `j_t` to the tableau `Q_t` at the same location the row insertion on `P_t` ended (that is to say, adding a new box with entry `j_t` such that `P_{t+1}` and `Q_{t+1}` have the same shape). The iterative process stops when `t` reaches the size of `p`, and the pair `(P_t, Q_t)` at this point is the image of `p` under the Robinson-Schensted-Knuth correspondence. This correspondence has been introduced in [Knu1970]_, where it has been referred to as "Construction A". For more information, see Chapter 7 in [Sta-EC2]_. We also note that integer matrices are in bijection with generalized permutations. Furthermore, we can convert any word `w` (and, in particular, any permutation) to a generalized permutation by considering the top line to be `(1, 2, \ldots, n)` where `n` is the length of `w`. The optional argument ``insertion`` allows to specify an alternative insertion procedure to be used instead of the standard Robinson-Schensted-Knuth insertion. If the input is a reduced word of a permutation (i.e., an element of a type-`A` Coxeter group), one can set ``insertion`` to ``'EG'``, which gives Edelman-Greene insertion, an algorithm defined in [EG1987]_ Definition 6.20 (where it is referred to as Coxeter-Knuth insertion). The Edelman-Greene insertion is similar to the standard row insertion except that if `k_i` and `k_i + 1` both exist in row `i`, we *only* set `k_{i+1} = k_i + 1` and continue. One can also perform a "Hecke RSK algorithm", defined using the Hecke insertion studied in [BKSTY06]_ (but using rows instead of columns). The algorithm proceeds similarly to the classical RSK algorithm. However, it is not clear in what generality it works; thus, following [BKSTY06]_, we shall assume that our biword `p` has top line `(1, 2, \ldots, n)` (or, at least, has its top line strictly increasing). The Hecke RSK algorithm returns a pair of an increasing tableau and a set-valued standard tableau. If `p = ((j_0, k_0), (j_1, k_1), \ldots, (j_{\ell-1}, k_{\ell-1}))`, then the algorithm recursively constructs pairs `(P_0, Q_0), (P_1, Q_1), \ldots, (P_\ell, Q_\ell)` of tableaux. The construction of `P_{t+1}` and `Q_{t+1}` from `P_t`, `Q_t`, `j_t` and `k_t` proceeds as follows: Set `i = j_t`, `x = k_t`, `P = P_t` and `Q = Q_t`. We are going to insert `x` into the increasing tableau `P` and update the set-valued "recording tableau" `Q` accordingly. As in the classical RSK algorithm, we first insert `x` into row `1` of `P`, then into row `2` of the resulting tableau, and so on, until the construction terminates. The details are different: Suppose we are inserting `x` into row `R` of `P`. If (Case 1) there exists an entry `y` in row `R` such that `x < y`, then let `y` be the minimal such entry. We replace this entry `y` with `x` if the result is still an increasing tableau; in either subcase, we then continue recursively, inserting `y` into the next row of `P`. If, on the other hand, (Case 2) no such `y` exists, then we append `x` to the end of `R` if the result is an increasing tableau (Subcase 2.1), and otherwise (Subcase 2.2) do nothing. Furthermore, in Subcase 2.1, we add the box that we have just filled with `x` in `P` to the shape of `Q`, and fill it with the one-element set `\{i\}`. In Subcase 2.2, we find the bottommost box of the column containing the rightmost box of row `R`, and add `i` to the entry of `Q` in this box (this entry is a set, since `Q` is a set-valued). In either subcase, we terminate the recursion, and set `P_{t+1} = P` and `Q_{t+1} = Q`. Notice that set-valued tableaux are encoded as tableaux whose entries are tuples of positive integers; each such tuple is strictly increasing and encodes a set (namely, the set of its entries). INPUT: - ``obj1, obj2`` -- Can be one of the following: - A word in an ordered alphabet - An integer matrix - Two lists of equal length representing a generalized permutation - Any object which has a method ``_rsk_iter()`` which returns an iterator over the object represented as generalized permutation or a pair of lists. - ``insertion`` -- (Default: ``'RSK'``) The following types of insertion are currently supported: - ``'RSK'`` -- Robinson-Schensted-Knuth - ``'EG'`` -- Edelman-Greene (only for reduced words of permutations/elements of a type-`A` Coxeter group) - ``'hecke'`` -- Hecke insertion (only guaranteed for generalized permutations whose top row is strictly increasing) - ``check_standard`` -- (Default: ``False``) Check if either of the resulting tableaux is a standard tableau, and if so, typecast it as such EXAMPLES: If we only give one line, we treat the top line as being `(1, 2, \ldots, n)`:: sage: RSK([3,3,2,4,1]) [[[1, 3, 4], [2], [3]], [[1, 2, 4], [3], [5]]] sage: RSK(Word([3,3,2,4,1])) [[[1, 3, 4], [2], [3]], [[1, 2, 4], [3], [5]]] sage: RSK(Word([2,3,3,2,1,3,2,3])) [[[1, 2, 2, 3, 3], [2, 3], [3]], [[1, 2, 3, 6, 8], [4, 7], [5]]] With a generalized permutation:: sage: RSK([1, 2, 2, 2], [2, 1, 1, 2]) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] sage: RSK(Word([1,1,3,4,4]), [1,4,2,1,3]) [[[1, 1, 3], [2], [4]], [[1, 1, 4], [3], [4]]] sage: RSK([1,3,3,4,4], Word([6,2,2,1,7])) [[[1, 2, 7], [2], [6]], [[1, 3, 4], [3], [4]]] If we give it a matrix:: sage: RSK(matrix([[0,1],[2,1]])) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] We can also give it something looking like a matrix:: sage: RSK([[0,1],[2,1]]) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] There are also variations of the insertion algorithm in RSK. Here we consider Edelman-Greene insertion:: sage: RSK([2,1,2,3,2], insertion='EG') [[[1, 2, 3], [2, 3]], [[1, 3, 4], [2, 5]]] We reproduce figure 6.4 in [EG1987]_:: sage: RSK([2,3,2,1,2,3], insertion='EG') [[[1, 2, 3], [2, 3], [3]], [[1, 2, 6], [3, 5], [4]]] Hecke insertion is also supported. We construct Example 2.1 in :arxiv:`0801.1319v2`:: sage: w = [5, 4, 1, 3, 4, 2, 5, 1, 2, 1, 4, 2, 4] sage: RSK(w, insertion='hecke') [[[1, 2, 4, 5], [2, 4, 5], [3, 5], [4], [5]], [[(1,), (4,), (5,), (7,)], [(2,), (9,), (11, 13)], [(3,), (12,)], [(6,)], [(8, 10)]]] There is also :func:`~sage.combinat.rsk.RSK_inverse` which performs the inverse of the bijection on a pair of semistandard tableaux. We note that the inverse function takes 2 separate tableaux as inputs, so to compose with :func:`~sage.combinat.rsk.RSK`, we need to use the python ``*`` on the output:: sage: RSK_inverse(*RSK([1, 2, 2, 2], [2, 1, 1, 2])) [[1, 2, 2, 2], [2, 1, 1, 2]] sage: P,Q = RSK([1, 2, 2, 2], [2, 1, 1, 2]) sage: RSK_inverse(P, Q) [[1, 2, 2, 2], [2, 1, 1, 2]] TESTS: Empty objects:: sage: RSK(Permutation([])) [[], []] sage: RSK(Word([])) [[], []] sage: RSK(matrix([[]])) [[], []] sage: RSK([], []) [[], []] sage: RSK([[]]) [[], []] sage: RSK(Word([]), insertion='EG') [[], []] sage: RSK(Word([]), insertion='hecke') [[], []] """ from sage.combinat.tableau import SemistandardTableau, StandardTableau if insertion == 'hecke': return hecke_insertion(obj1, obj2) if obj1 is None and obj2 is None: if 'matrix' in options: obj1 = matrix(options['matrix']) else: raise ValueError("invalid input") if is_Matrix(obj1): obj1 = obj1.rows() if len(obj1) == 0: return [StandardTableau([]), StandardTableau([])] if obj2 is None: try: itr = obj1._rsk_iter() except AttributeError: # If this is (something which looks like) a matrix # then build the generalized permutation try: t = [] b = [] for i, row in enumerate(obj1): for j, mult in enumerate(row): if mult > 0: t.extend([i+1]*mult) b.extend([j+1]*mult) itr = izip(t, b) except TypeError: itr = izip(range(1, len(obj1)+1), obj1) else: if len(obj1) != len(obj2): raise ValueError("the two arrays must be the same length") # Check it is a generalized permutation lt = 0 lb = 0 for t,b in izip(obj1, obj2): if t < lt or (lt == t and b < lb): raise ValueError("invalid generalized permutation") lt = t lb = b itr = izip(obj1, obj2) from bisect import bisect_right p = [] #the "insertion" tableau q = [] #the "recording" tableau use_EG = (insertion == 'EG') #For each x in self, insert x into the tableau p. lt = 0 lb = 0 for i, x in itr: for r, qr in izip(p,q): if r[-1] > x: #Figure out where to insert x into the row r. The #bisect command returns the position of the least #element of r greater than x. We will call it y. y_pos = bisect_right(r, x) if use_EG and r[y_pos] == x + 1 and y_pos > 0 and x == r[y_pos - 1]: #Special bump: Nothing to do except increment x by 1 x += 1 else: #Switch x and y x, r[y_pos] = r[y_pos], x else: break else: #We made through all of the rows of p without breaking #so we need to add a new row to p and q. r = []; p.append(r) qr = []; q.append(qr) r.append(x) qr.append(i) # Values are always inserted to the right if check_standard: try: P = StandardTableau(p) except ValueError: P = SemistandardTableau(p) try: Q = StandardTableau(q) except ValueError: Q = SemistandardTableau(q) return [P, Q] return [SemistandardTableau(p), SemistandardTableau(q)]
def to_tableaux(self): return SemistandardTableau( [row.to_list() for row in self.rows()[::-1]])
def RSK(obj1=None, obj2=None, insertion='RSK', check_standard=False, **options): r""" Perform the Robinson-Schensted-Knuth (RSK) correspondence. The Robinson-Schensted-Knuth (RSK) correspondence is most naturally stated as a bijection between generalized permutations (also known as two-line arrays, biwords, ...) and pairs of semi-standard Young tableaux `(P, Q)` of identical shape. The tableau `P` is known as the insertion tableau and `Q` is known as the recording tableau. The basic operation is known as row insertion `P \leftarrow k` (where `P` is a given semi-standard Young tableau, and `k` is an integer). Row insertion is a recursive algorithm which starts by setting `k_0 = k`, and in its `i`-th step inserts the number `k_i` into the `i`-th row of `P` by replacing the first integer greater than `k_i` in the row by `k_i` and defines `k_{i+1}` as the integer that has been replaced. If no integer greater than `k_i` exists in the `i`-th row, then `k_i` is simply appended to the row and the algorithm terminates at this point. Now the RSK algorithm starts by initializing two semi-standard tableaux `P_0` and `Q_0` as empty tableaux. For each nonnegative integer `t` starting at `0`, take the pair `(j_t, k_t)` from `p` and set `P_{t+1} = P_t \leftarrow k_t`, and define `Q_{t+1}` by adding a new box filled with `j_t` to the tableau `Q_t` at the same location the row insertion on `P_t` ended (that is to say, adding `j_t` such that `P_{t+1}` and `Q_{t+1}` have the same shape). The iterative process stops when `t` reaches the size of `p`, and the pair `(P_t, Q_t)` at this point is the image of `p` under the Robinson-Schensted-Knuth correspondence. This correspondence has been introduced in [Knu1970]_, where it has been referred to as "Construction A". For more information, see Chapter 7 in [Sta-EC2]_. We also note that integer matrices are in bijection with generalized permutations. In addition, we can also convert any word `w` (and any permutation) to a generalized permutation by considering the top line to be `(1, 2, \ldots, n)` where `n` is the length of `w`. The optional argument ``insertion`` allows to specify an alternative insertion procedure to be used instead of the standard Robinson-Schensted-Knuth insertion. If the input is a reduced word of a permutation (i.e., a type `A` Coxeter element), one can set ``insertion`` to ``'EG'``, which gives Edelman-Greene insertion, an algorithm defined in [EG1987]_ Definition 6.20 (where it is referred to as Coxeter-Knuth insertion). The Edelman-Greene insertion is similar to the standard row insertion except that if `k_i` and `k_i + 1` both exist in row `i`, we *only* set `k_{i+1} = k_i + 1` and continue. INPUT: - ``obj1, obj2`` -- Can be one of the following: - A word in an ordered alphabet - An integer matrix - Two lists of equal length representing a generalized permutation - Any object which has a method ``_rsk_iter()`` which returns an iterator over the object represented as generalized permutation or a pair of lists. - ``insertion`` -- (Default: ``'RSK'``) The following types of insertion are currently supported: - ``'RSK'`` -- Robinson-Schensted-Knuth - ``'EG'`` -- Edelman-Greene (only for reduced words of permutations/type `A` Coxeter elements) - ``check_standard`` -- (Default: ``False``) Check if either of the resulting tableaux should be standard tableau. EXAMPLES: If we only give one line, we treat the top line as being `(1, 2, \ldots, n)`:: sage: RSK([3,3,2,4,1]) [[[1, 3, 4], [2], [3]], [[1, 2, 4], [3], [5]]] sage: RSK(Word([3,3,2,4,1])) [[[1, 3, 4], [2], [3]], [[1, 2, 4], [3], [5]]] sage: RSK(Word([2,3,3,2,1,3,2,3])) [[[1, 2, 2, 3, 3], [2, 3], [3]], [[1, 2, 3, 6, 8], [4, 7], [5]]] With a generalized permutation:: sage: RSK([1, 2, 2, 2], [2, 1, 1, 2]) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] sage: RSK(Word([1,1,3,4,4]), [1,4,2,1,3]) [[[1, 1, 3], [2], [4]], [[1, 1, 4], [3], [4]]] sage: RSK([1,3,3,4,4], Word([6,2,2,1,7])) [[[1, 2, 7], [2], [6]], [[1, 3, 4], [3], [4]]] If we give it a matrix:: sage: RSK(matrix([[0,1],[2,1]])) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] We can also give it something looking like a matrix:: sage: RSK([[0,1],[2,1]]) [[[1, 1, 2], [2]], [[1, 2, 2], [2]]] There are also variations of the insertion algorithm in RSK, and currently only Edelman-Greene insertion is supported:: sage: RSK([2,1,2,3,2], insertion='EG') [[[1, 2, 3], [2, 3]], [[1, 3, 4], [2, 5]]] We reproduce figure 6.4 in [EG1987]_:: sage: RSK([2,3,2,1,2,3], insertion='EG') [[[1, 2, 3], [2, 3], [3]], [[1, 2, 6], [3, 5], [4]]] There is also :func:`~sage.combinat.rsk.RSK_inverse` which performs the inverse of the bijection on a pair of semistandard tableaux. We note that the inverse function takes 2 separate tableaux inputs, so to compose with :func:`~sage.combinat.rsk.RSK`, we need to use the python ``*`` on the output:: sage: RSK_inverse(*RSK([1, 2, 2, 2], [2, 1, 1, 2])) [[1, 2, 2, 2], [2, 1, 1, 2]] sage: P,Q = RSK([1, 2, 2, 2], [2, 1, 1, 2]) sage: RSK_inverse(P, Q) [[1, 2, 2, 2], [2, 1, 1, 2]] TESTS: Empty objects:: sage: RSK(Permutation([])) [[], []] sage: RSK(Word([])) [[], []] sage: RSK(matrix([[]])) [[], []] sage: RSK([], []) [[], []] sage: RSK([[]]) [[], []] sage: RSK(Word([]), insertion='EG') [[], []] """ from sage.combinat.tableau import SemistandardTableau, StandardTableau if obj1 is None and obj2 is None: if 'matrix' in options: obj1 = matrix(options['matrix']) else: raise ValueError("Invalid input") if is_Matrix(obj1): obj1 = obj1.rows() if len(obj1) == 0: return [StandardTableau([]), StandardTableau([])] if obj2 is None: try: itr = obj1._rsk_iter() except AttributeError: # If this is (something which looks like) a matrix # then build the generalized permutation try: t = [] b = [] for i, row in enumerate(obj1): for j, mult in enumerate(row): if mult > 0: t.extend([i + 1] * mult) b.extend([j + 1] * mult) itr = izip(t, b) except TypeError: itr = izip(range(1, len(obj1) + 1), obj1) else: if len(obj1) != len(obj2): raise ValueError("The two arrays must be the same length") # Check it is a generalized permutation lt = 0 lb = 0 for t, b in izip(obj1, obj2): if t < lt or (lt == t and b < lb): raise ValueError("Invalid generalized permutation") lt = t lb = b itr = izip(obj1, obj2) from bisect import bisect_right p = [] #the "insertion" tableau q = [] #the "recording" tableau use_EG = (insertion == 'EG') #For each x in self, insert x into the tableau p. lt = 0 lb = 0 for i, x in itr: for r, qr in izip(p, q): if r[-1] > x: #Figure out where to insert x into the row r. The #bisect command returns the position of the least #element of r greater than x. We will call it y. y_pos = bisect_right(r, x) if use_EG and r[y_pos] == x + 1 and y_pos > 0 and x == r[y_pos - 1]: #Special bump: Nothing to do except increment x by 1 x += 1 else: #Switch x and y x, r[y_pos] = r[y_pos], x else: break else: #We made through all of the rows of p without breaking #so we need to add a new row to p and q. r = [] p.append(r) qr = [] q.append(qr) r.append(x) qr.append(i) # Values are always inserted to the right if check_standard: try: P = StandardTableau(p) except ValueError: P = SemistandardTableau(p) try: Q = StandardTableau(q) except ValueError: Q = SemistandardTableau(q) return [P, Q] return [SemistandardTableau(p), SemistandardTableau(q)]