def to_tableau(self): """ Returns the Tableau object corresponding to self. EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape = [2,2]) sage: t = T(rows=[[1,2],[3,4]]).to_tableau(); t [[1, 2], [3, 4]] sage: type(t) <class 'sage.combinat.tableau.Tableau_class'> sage: type(t[0][0]) <type 'sage.rings.integer.Integer'> sage: T = CrystalOfTableaux(['D',3], shape = [1,1]) sage: t=T(rows=[[-3],[3]]).to_tableau(); t [[-3], [3]] sage: t=T(rows=[[3],[-3]]).to_tableau(); t [[3], [-3]] sage: T = CrystalOfTableaux(['B',2], shape = [1,1]) sage: t = T(rows=[[0],[0]]).to_tableau(); t [[0], [0]] """ if self._list == []: return Tableau([]) tab = [ [self[0].value] ] for i in range(1,len(self)): if self[i-1] < self[i] or (self[i-1].value != 0 and self[i-1] == self[i]): tab.append([self[i].value]) else: l = len(tab)-1 tab[l].append(self[i].value) for x in tab: x.reverse() return Tableau(tab).conjugate()
def __init__(self, parent, t): """ Initialize ``self``. EXAMPLES:: sage: R = WeakReversePlanePartition([[0, 1, 2], [0, 2]]) sage: TestSuite(R).run() """ if not isinstance(t, Tableau): t = [list(row) for row in t] else: t = list(t) Tableau.__init__(self, parent, t)
def product_on_basis(self, t1, t2): r""" EXAMPLES:: sage: FSym = algebras.FSym(QQ) sage: TF = FSym.dual().F() sage: t1 = StandardTableau([[1,2]]) sage: TF.product_on_basis(t1, t1) F[12|34] + F[123|4] + F[1234] + F[124|3] + F[13|24] + F[134|2] sage: t0 = StandardTableau([]) sage: TF.product_on_basis(t1, t0) == TF[t1] == TF.product_on_basis(t0, t1) True """ z = [] n = t1.size() m = t2.size() npmp1 = n + m + 1 ST = self._indices from itertools import combinations for I in combinations(range(1, npmp1), n): J = [j for j in range(1, npmp1) if (j not in I)] tt1 = [[I[x - 1] for x in row] for row in t1] tt2 = [tuple([J[x - 1] for x in row]) for row in t2] z.append(ST(Tableau(tt1).slide_multiply(tt2))) return self.sum_of_monomials(z)
def __init__(self, parent, *args, **options): """ There are several ways to input tableaux, by rows, by columns, as the list of column elements, or as a sequence of numbers in column reading. EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape = [2,2]) sage: t = T(rows=[[1,2],[3,4]]) sage: t [[1, 2], [3, 4]] sage: TestSuite(t).run() sage: t = T(columns=[[3,1],[4,2]]) sage: t [[1, 2], [3, 4]] sage: TestSuite(t).run() sage: t = T(list=[3,1,4,2]) sage: t [[1, 2], [3, 4]] sage: t = T(3,1,4,2) sage: t [[1, 2], [3, 4]] Currently inputting the empty tableau as an empty sequence is broken due to a bug in the generic __call__ method (see trac ticket #8648) EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape=[]) sage: t = T() sage: t._list [0] """ if len(args) == 1: if isinstance(args[0], Tableau_class): options['rows'] = args[0] if options.has_key('list'): list = options['list'] elif options.has_key('rows'): rows=options['rows'] # list=Tableau(rows).to_word_by_column() rows=Tableau(rows).conjugate() list=[] for col in rows: col.reverse() list+=col elif options.has_key('columns'): columns=options['columns'] list=[] for col in columns: list+=col else: list = [i for i in args] if list != [] and type(list[0]) is Integer: list=[parent.letters(x) for x in list] TensorProductOfCrystalsElement.__init__(self, parent, list)
def _latex_(self): r""" EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape = [4,2]) sage: t = T(rows=[[1,1,2,3],[2,3]]) sage: latex(t) # indirect doctest {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{1-4} \lr{1}&\lr{1}&\lr{2}&\lr{3}\\\cline{1-4} \lr{2}&\lr{3}\\\cline{1-2} \end{array}$} } """ from sage.combinat.output import tex_from_array # Modified version of to_tableau() to have the entrys be letters # rather than their values if self._list == []: return "{\\emptyset}" tab = [[self[0]]] for i in range(1, len(self)): if self[i - 1] < self[i] or (self[i - 1].value != 0 and self[i - 1] == self[i]): tab.append([self[i]]) else: l = len(tab) - 1 tab[l].append(self[i]) for x in tab: x.reverse() T = Tableau(tab).conjugate() return tex_from_array([[letter._latex_() for letter in row] for row in T])
def to_dual_tableau(elt): r""" Return a type `A_n` crystal tableau ``elt`` as a tableau expressed in terms of dual letters. The dual letter of `k` is expressed as `\overline{n+2-k}` represented as `-(n+2-k)`. EXAMPLES:: sage: from sage.combinat.crystals.kac_modules import to_dual_tableau sage: T = crystals.Tableaux(['A',2], shape=[2,1]) sage: ascii_art([to_dual_tableau(t) for t in T]) [ -3 -3 -3 -2 -3 -1 -3 -1 -2 -1 -3 -3 -3 -2 -2 -2 ] [ -2 , -2 , -2 , -1 , -1 , -1 , -1 , -1 ] TESTS: Check that :trac:`23935` is fixed:: sage: from sage.combinat.crystals.kac_modules import to_dual_tableau sage: T = crystals.Tableaux(['A',2], shape=[]) sage: to_dual_tableau(T[0]) [] sage: Ktriv = crystals.KacModule(['A',[1,1]], [], []) sage: Ktriv.module_generator() ({}, [], []) """ from sage.combinat.tableau import Tableau M = elt.parent().cartan_type().rank() + 2 if not elt: return Tableau([]) tab = [[elt[0].value - M]] for i in range(1, len(elt)): if elt[i - 1] < elt[i] or (elt[i - 1].value != 0 and elt[i - 1] == elt[i]): tab.append([elt[i].value - M]) else: tab[len(tab) - 1].append(elt[i].value - M) for x in tab: x.reverse() return Tableau(tab).conjugate()
def to_tableau(self): r""" Return the tableau class of ``self``. EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.to_tableau() [[4, 3, 3, 1], [2, 1, 1], [1, 1]] """ return Tableau(self)
def _latex_(self): """ Gives the latex output of a spin column. EXAMPLES:: sage: C = CrystalOfSpins(['B',3]) sage: b = C([1,1,-1]) sage: b._latex_() '{\\def\\lr#1{\\multicolumn{1}{|@{\\hspace{.6ex}}c@{\\hspace{.6ex}}|}{\\raisebox{-.3ex}{$#1$}}}\n\\raisebox{-.6ex}{$\\begin{array}[b]{c}\n\\cline{1-1}\n\\lr{-}\\\\\n\\cline{1-1}\n\\lr{+}\\\\\n\\cline{1-1}\n\\lr{+}\\\\\n\\cline{1-1}\n\\end{array}$}\n}' """ return Tableau([[i] for i in reversed(self.signature())])._latex_()
def _latex_(self): r""" Gives the latex output of a spin column. EXAMPLES:: sage: C = crystals.Spins(['B',3]) sage: b = C([1,1,-1]) sage: print(b._latex_()) {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} \raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1} \lr{-}\\\cline{1-1} \lr{+}\\\cline{1-1} \lr{+}\\\cline{1-1} \end{array}$} } """ return Tableau([[i] for i in reversed(self.signature())])._latex_()
def _tableau_dict(self): r""" A dictionary pairing the vertices of the underlying Yang-Baxter graph with standard tableau. EXAMPLES:: sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") sage: orth._tableau_dict {(0, 2, 1, -1, 0): [[1, 3, 4], [2, 5]], (2, 0, -1, 1, 0): [[1, 2, 5], [3, 4]], (2, 0, 1, -1, 0): [[1, 3, 5], [2, 4]], (0, 2, -1, 1, 0): [[1, 2, 4], [3, 5]], (0, -1, 2, 1, 0): [[1, 2, 3], [4, 5]]} """ # construct a dictionary pairing vertices with tableau t = StandardTableaux(self._partition).last() tableau_dict = {self._yang_baxter_graph.root():t} for (u,w,(i,beta)) in self._yang_baxter_graph._edges_in_bfs(): # TODO: improve the following si = PermutationGroupElement((i,i+1)) tableau_dict[w] = Tableau([map(si, row) for row in tableau_dict[u]]) return tableau_dict
def latex_dual(elt): r""" Return a latex representation of a type `A_n` crystal tableau ``elt`` expressed in terms of dual letters. The dual letter of `k` is expressed as `\overline{n+2-k}`. EXAMPLES:: sage: from sage.combinat.crystals.kac_modules import latex_dual sage: T = crystals.Tableaux(['A',2], shape=[2,1]) sage: print(latex_dual(T[0])) {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2} \lr{\overline{3}}&\lr{\overline{3}}\\\cline{1-2} \lr{\overline{2}}\\\cline{1-1} \end{array}$} } """ M = elt.parent().cartan_type().rank() + 2 from sage.combinat.tableau import Tableau from sage.combinat.output import tex_from_array # Modified version of to_tableau() to have the entries be letters # rather than their values if not elt: return "{\\emptyset}" tab = [["\\overline{{{}}}".format(M - elt[0].value)]] for i in range(1, len(elt)): if elt[i - 1] < elt[i] or (elt[i - 1].value != 0 and elt[i - 1] == elt[i]): tab.append(["\\overline{{{}}}".format(M - elt[i].value)]) else: l = len(tab) - 1 tab[l].append("\\overline{{{}}}".format(M - elt[i].value)) for x in tab: x.reverse() T = Tableau(tab).conjugate() return tex_from_array([list(row) for row in T])
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 pak_correspondence(self): r""" Return the image of the `\lambda`-rpp ``self`` under the Pak correspondence (as a :class:`~sage.combinat.tableau.Tableau`). See :mod:`~sage.combinat.hillman_grassl`. The Pak correspondence is the map `\xi_\lambda` from [Sulzgr2017]_ Section 7, and is the map `\xi_\lambda` from [Pak2002]_ Section 4. It is the inverse of the Sulzgruber correspondence (:meth:`sulzgruber_correspondence`). The following description of the Pak correspondence follows [Hopkins2017]_ (which denotes it by `\mathcal{RSK}^{-1}`): Fix a partition `\lambda` (see :meth:`~sage.combinat.partition.Partition`). We draw all partitions and tableaux in English notation. A `\lambda`-*array* will mean a tableau of shape `\lambda` whose entries are nonnegative integers. (No conditions on the order of these entries are made. Note that `0` is allowed.) A *weak reverse plane partition of shape* `\lambda` (short: `\lambda`-*rpp*) will mean a `\lambda`-array whose entries weakly increase along each row and weakly increase along each column. We shall also use the following notation: If `(u, v)` is a cell of `\lambda`, and if `\pi` is a `\lambda`-rpp, then: * the *lower bound* of `\pi` at `(u, v)` (denoted by `\pi_{<(u, v)}`) is defined to be `\max \{ \pi_{u-1, v} , \pi_{u, v-1} \}` (where `\pi_{0, v}` and `\pi_{u, 0}` are understood to mean `0`). * the *upper bound* of `\pi` at `(u, v)` (denoted by `\pi_{>(u, v)}`) is defined to be `\min \{ \pi_{u+1, v} , \pi_{u, v+1} \}` (where `\pi_{i, j}` is understood to mean `+ \infty` if `(i, j)` is not in `\lambda`; thus, the upper bound at a corner cell is `+ \infty`). * *toggling* `\pi` at `(u, v)` means replacing the entry `\pi_{u, v}` of `\pi` at `(u, v)` by `\pi_{<(u, v)} + \pi_{>(u, v)} - \pi_{u, v}` (this is well-defined as long as `(u, v)` is not a corner of `\lambda`). Note that every `\lambda`-rpp `\pi` and every cell `(u, v)` of `\lambda` satisfy `\pi_{<(u, v)} \leq \pi_{u, v} \leq \pi_{>(u, v)}`. Note that toggling a `\lambda`-rpp (at a cell that is not a corner) always results in a `\lambda`-rpp. Also, toggling is an involution). Note also that the lower bound of `\pi` at `(u, v)` is defined (and finite) even when `(u, v)` is not a cell of `\lambda`, as long as both `(u-1, v)` and `(u, v-1)` are cells of `\lambda`. The Pak correspondence `\Phi_\lambda` sends a `\lambda`-array `M = (m_{i, j})` to a `\lambda`-rpp `\Phi_\lambda(M)`. It is defined by recursion on `\lambda` (that is, we assume that `\Phi_\mu` is already defined for every partition `\mu` smaller than `\lambda`), and its definition proceeds as follows: * If `\lambda = \varnothing`, then `\Phi_\lambda` is the obvious bijection sending the only `\varnothing`-array to the only `\varnothing`-rpp. * Pick any corner `c = (i, j)` of `\lambda`, and let `\mu` be the result of removing this corner `c` from the partition `\lambda`. (The exact choice of `c` is immaterial.) * Let `M'` be what remains of `M` when the corner cell `c` is removed. * Let `\pi' = \Phi_\mu(M')`. * For each positive integer `k` such that `(i-k, j-k)` is a cell of `\lambda`, toggle `\pi'` at `(i-k, j-k)`. (All these togglings commute, so the order in which they are made is immaterial.) * Extend the `\mu`-rpp `\pi'` to a `\lambda`-rpp `\pi` by adding the cell `c` and writing the number `m_{i, j} - \pi'_{<(i, j)}` into this cell. * Set `\Phi_\lambda(M) = \pi`. .. SEEALSO:: :meth:`~sage.combinat.hillman_grassl.pak_correspondence` for the Pak correspondence as a standalone function. :meth:`~sage.combinat.tableau.Tableau.sulzgruber_correspondence` for the inverse map. EXAMPLES:: sage: a = WeakReversePlanePartition([[1, 2, 3], [1, 2, 3], [2, 4, 4]]) sage: A = a.pak_correspondence(); A [[1, 0, 2], [0, 2, 0], [1, 1, 0]] sage: a.parent(), A.parent() (Weak Reverse Plane Partitions, Tableaux) Applying the Pak correspondence to the transpose of a `\lambda`-rpp `M` yields the same result as applying it to `M` and then transposing the result:: sage: a = WeakReversePlanePartition([[1,3,5],[2,4]]) sage: acc = a.pak_correspondence().conjugate() sage: acc == a.conjugate().pak_correspondence() True """ return Tableau(pak_correspondence(list(self)))
def hillman_grassl_inverse(self): r""" Return the image of the `\lambda`-rpp ``self`` under the inverse of the Hillman-Grassl correspondence (as a :class:`~sage.combinat.tableau.Tableau`). Fix a partition `\lambda` (see :meth:`~sage.combinat.partition.Partition`). We draw all partitions and tableaux in English notation. A `\lambda`-*array* will mean a tableau of shape `\lambda` whose entries are nonnegative integers. (No conditions on the order of these entries are made. Note that `0` is allowed.) A *weak reverse plane partition of shape* `\lambda` (short: `\lambda`-*rpp*) will mean a `\lambda`-array whose entries weakly increase along each row and weakly increase along each column. The inverse `H^{-1}` of the Hillman-Grassl correspondence (see (:meth:`~sage.combinat.tableau.Tableau.hillman_grassl` for the latter) sends a `\lambda`-rpp `\pi` to a `\lambda`-array `H^{-1}(\pi)` constructed recursively as follows: * If all entries of `\pi` are `0`, then `H^{-1}(\pi) = \pi`. * Otherwise, let `s` be the index of the leftmost column of `\pi` containing a nonzero entry. Write the `\lambda`-array `M` as `(m_{i, j})`. * Define a sequence `((i_1, j_1), (i_2, j_2), \ldots, (i_n, j_n))` of boxes in the diagram of `\lambda` (actually a lattice path made of northward and eastward steps) as follows: Let `(i_1, j_1)` be the bottommost box in the `s`-th column of `\pi`. If `(i_k, j_k)` is defined for some `k \geq 1`, then `(i_{k+1}, j_{k+1})` is constructed as follows: If `q_{i_k - 1, j_k}` is well-defined and equals `q_{i_k, j_k}`, then we set `(i_{k+1}, j_{k+1}) = (i_k - 1, j_k)`. Otherwise, we set `(i_{k+1}, j_{k+1}) = (i_k, j_k + 1)` if this is still a box of `\lambda`. Otherwise, the sequence ends here. * Let `\pi'` be the `\lambda`-rpp obtained from `\pi` by subtracting `1` from the `(i_k, j_k)`-th entry of `\pi` for each `k \in \{1, 2, \ldots, n\}`. * Let `N'` be the image `H^{-1}(\pi')` (which is already constructed by recursion). Then, `H^{-1}(\pi)` is obtained from `N'` by adding `1` to the `(i_n, s)`-th entry of `N'`. This construction appears in [HilGra1976]_ Section 6 (where `\lambda`-arrays are re-encoded as sequences of "hook number multiplicities") and [EnumComb2]_ Section 7.22. .. SEEALSO:: :meth:`~sage.combinat.hillman_grassl.hillman_grassl_inverse` for the inverse of the Hillman-Grassl correspondence as a standalone function. :meth:`~sage.combinat.tableau.Tableau.hillman_grassl` for the inverse map. EXAMPLES:: sage: a = WeakReversePlanePartition([[2, 2, 4], [2, 3, 4], [3, 5]]) sage: a.hillman_grassl_inverse() [[2, 1, 1], [0, 2, 0], [1, 1]] sage: b = WeakReversePlanePartition([[1, 1, 2, 2], [1, 1, 2, 2], [2, 2, 3, 3], [2, 2, 3, 3]]) sage: B = b.hillman_grassl_inverse(); B [[1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 1]] sage: b.parent(), B.parent() (Weak Reverse Plane Partitions, Tableaux) Applying the inverse of the Hillman-Grassl correspondence to the transpose of a `\lambda`-rpp `M` yields the same result as applying it to `M` and then transposing the result ([Gans1981]_ Corollary 3.4):: sage: a = WeakReversePlanePartition([[1,3,5],[2,4]]) sage: aic = a.hillman_grassl_inverse().conjugate() sage: aic == a.conjugate().hillman_grassl_inverse() True """ return Tableau(hillman_grassl_inverse(list(self)))
def __init__(self, parent, *args, **options): """ There are several ways to input tableaux, by rows, by columns, as the list of column elements, or as a sequence of numbers in column reading. EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape = [2,2]) sage: t = T(rows=[[1,2],[3,4]]) sage: t [[1, 2], [3, 4]] sage: TestSuite(t).run() sage: t = T(columns=[[3,1],[4,2]]) sage: t [[1, 2], [3, 4]] sage: TestSuite(t).run() sage: t = T(list=[3,1,4,2]) sage: t [[1, 2], [3, 4]] sage: t = T(3,1,4,2) sage: t [[1, 2], [3, 4]] Currently inputting the empty tableau as an empty sequence is broken due to a bug in the generic __call__ method (see trac ticket #8648) EXAMPLES:: sage: T = CrystalOfTableaux(['A',3], shape=[]) sage: t = T() sage: t._list [0] TESTS: Integer types that are not a Sage ``Integer`` (such as a Python ``int`` and typically arise from compiled code) were not converted into a letter. This caused certain functions to fail. This is fixed in :trac:`13204`:: sage: T = CrystalOfTableaux(['A',3], shape = [2,2]) sage: t = T(list=[int(3),1,4,2]) sage: type(t[0]) <class 'sage.combinat.crystals.letters.ClassicalCrystalOfLetters_with_category.element_class'> sage: t = T(list=[3,int(1),4,2]) sage: type(t[1]) <class 'sage.combinat.crystals.letters.ClassicalCrystalOfLetters_with_category.element_class'> sage: C = KirillovReshetikhinCrystal(['A',int(3),1], 1,1) sage: C[0].e(0) [[4]] """ if len(args) == 1: if isinstance(args[0], Tableau): options['rows'] = args[0] if options.has_key('list'): list = options['list'] elif options.has_key('rows'): rows = options['rows'] # list=Tableau(rows).to_word_by_column() rows = Tableau(rows).conjugate() list = [] for col in rows: col.reverse() list += col elif options.has_key('columns'): columns = options['columns'] list = [] for col in columns: list += col else: list = [i for i in args] TensorProductOfCrystalsElement.__init__(self, parent, map(parent.letters, list))