Path: blob/master/src/sage/combinat/alternating_sign_matrix.py
8817 views
r"""1Alternating Sign Matrices23AUTHORS:45- Mike Hansen (2007): Initial version6- Pierre Cange, Luis Serrano (2012): Added monotone triangles7- Travis Scrimshaw (2013-28-03): Added element class for ASM's and made8:class:`MonotoneTriangles` inherit from :class:`GelfandTsetlinPatterns`9- Jessica Striker (2013): Added additional methods10"""11#*****************************************************************************12# Copyright (C) 2007 Mike Hansen <[email protected]>,13# 2012 Pierre Cagne <[email protected]>,14# Luis Serrano <[email protected]>15# 2013 Travis Scrimshaw <[email protected]>16# 2013 Jessica Striker <[email protected]>17#18# Distributed under the terms of the GNU General Public License (GPL)19#20# This code is distributed in the hope that it will be useful, but21# WITHOUT ANY WARRANTY; without even the implied warranty of22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU23# General Public License for more details.24#25# The full text of the GPL is available at:26#27# http://www.gnu.org/licenses/28#*****************************************************************************2930import itertools31import copy32from sage.misc.classcall_metaclass import ClasscallMetaclass33from sage.misc.flatten import flatten34from sage.misc.misc import prod35from sage.structure.unique_representation import UniqueRepresentation36from sage.structure.parent import Parent37from sage.structure.element import Element38from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets39from sage.matrix.matrix_space import MatrixSpace40from sage.matrix.constructor import matrix41from sage.rings.all import ZZ, factorial42from sage.rings.integer import Integer43from sage.combinat.posets.lattices import LatticePoset44from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPatternsTopRow45from sage.sets.set import Set46from sage.combinat.combinatorial_map import combinatorial_map47from sage.combinat.non_decreasing_parking_function import NonDecreasingParkingFunction48from sage.combinat.permutation import Permutation4950class AlternatingSignMatrix(Element):51r"""52An alternating sign matrix.5354An alternating sign matrix is a square matrix of `0`'s, `1`'s and `-1`'s55such that the sum of each row and column is `1` and the non-zero56entries in each row and column alternate in sign.57"""58__metaclass__ = ClasscallMetaclass5960@staticmethod61def __classcall_private__(cls, asm):62"""63Create an ASM.6465EXAMPLES::6667sage: AlternatingSignMatrix([[1, 0, 0],[0, 1, 0],[0, 0, 1]])68[1 0 0]69[0 1 0]70[0 0 1]71"""72asm = matrix(asm)73if not asm.is_square():74raise ValueError("The alternating sign matrices must be square")75P = AlternatingSignMatrices(asm.nrows())76if asm not in P:77raise ValueError("Invalid alternating sign matrix")78return P(asm)7980def __init__(self, parent, asm):81"""82Initialize ``self``.8384EXAMPLES:8586sage: A = AlternatingSignMatrices(3)87sage: elt = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])88sage: TestSuite(elt).run()89"""90self._matrix = asm91Element.__init__(self, parent)9293def _repr_(self):94"""95Return a string representation of ``self``.9697EXAMPLES::9899sage: A = AlternatingSignMatrices(3)100sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])101[1 0 0]102[0 1 0]103[0 0 1]104"""105return repr(self._matrix)106107def __eq__(self, other):108"""109Check equality.110111EXAMPLES::112113sage: A = AlternatingSignMatrices(3)114sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])115sage: M == A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])116True117sage: M == A([[1, 0, 0],[0, 0, 1],[0, 1, 0]])118False119"""120if isinstance(other, AlternatingSignMatrix):121return self._matrix == other._matrix122return self._matrix == other123124def __ne__(self, other):125"""126Check not equals. This is needed, see :trac:`14762`.127128EXAMPLES::129130sage: A = AlternatingSignMatrices(3)131sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])132sage: M != A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])133False134sage: M != A([[1, 0, 0],[0, 0, 1],[0, 1, 0]])135True136"""137return not self.__eq__(other)138139def __le__(self, other):140"""141Check less than or equal to. This is needed, see :trac:`15372`.142143EXAMPLES::144145sage: A = AlternatingSignMatrices(3)146sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])147sage: M <= A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])148True149sage: M <= A([[1, 0, 0],[0, 0, 1],[0, 1, 0]])150False151"""152if isinstance(other, AlternatingSignMatrix):153return self._matrix <= other._matrix154return False #return False if other is not an ASM155156def __lt__(self, other):157"""158Check less than. This is needed, see :trac:`15372`.159160EXAMPLES::161162sage: A = AlternatingSignMatrices(3)163sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])164sage: M < A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])165False166"""167if isinstance(other, AlternatingSignMatrix):168return self._matrix < other._matrix169return False #return False if other is not an ASM170171def __ge__(self, other):172"""173Check greater than or equal to. This is needed, see :trac:`15372`.174175EXAMPLES::176177sage: A = AlternatingSignMatrices(3)178sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])179sage: M >= A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])180True181sage: M >= A([[1, 0, 0],[0, 0, 1],[0, 1, 0]])182True183"""184if isinstance(other, AlternatingSignMatrix):185return self._matrix >= other._matrix186return False #return False if other is not an ASM187188def __gt__(self, other):189"""190Check greater than. This is needed, see :trac:`15372`.191192EXAMPLES::193194sage: A = AlternatingSignMatrices(3)195sage: M = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])196sage: M > A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])197False198"""199if isinstance(other, AlternatingSignMatrix):200return self._matrix > other._matrix201return False #return False if other is not an ASM202203def _latex_(self):204r"""205Return a `\LaTeX` representation of ``self``.206207EXAMPLES::208209sage: A = AlternatingSignMatrices(3)210sage: latex(A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]))211\left(\begin{array}{rrr}2121 & 0 & 0 \\2130 & 1 & 0 \\2140 & 0 & 1215\end{array}\right)216"""217return self._matrix._latex_()218219def to_matrix(self):220"""221Return ``self`` as a regular matrix.222223EXAMPLES::224225sage: A = AlternatingSignMatrices(3)226sage: asm = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])227sage: m = asm.to_matrix(); m228[1 0 0]229[0 1 0]230[0 0 1]231sage: m.parent()232Full MatrixSpace of 3 by 3 dense matrices over Integer Ring233"""234return copy.copy(self._matrix)235236@combinatorial_map(name='to monotone triangle')237def to_monotone_triangle(self):238r"""239Return a monotone triangle from ``self``.240241EXAMPLES::242243sage: A = AlternatingSignMatrices(3)244sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).to_monotone_triangle()245[[3, 2, 1], [2, 1], [1]]246sage: asm = A([[0, 1, 0],[1, -1, 1],[0, 1, 0]])247sage: asm.to_monotone_triangle()248[[3, 2, 1], [3, 1], [2]]249sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])250sage: asm.to_monotone_triangle()251[[3, 2, 1], [3, 1], [3]]252sage: A.from_monotone_triangle(asm.to_monotone_triangle()) == asm253True254"""255n = self._matrix.nrows()256triangle = [None]*n257prev = [0]*n258for j, row in enumerate(self._matrix):259add_row = [a+b for (a,b) in itertools.izip(row, prev)]260line = [i+1 for (i,val) in enumerate(add_row) if val==1]261triangle[n-1-j] = list(reversed(line))262prev = add_row263return MonotoneTriangles(n)(triangle)264265@combinatorial_map(name='rotate counterclockwise')266def rotate_ccw(self):267r"""268Return the counterclockwise quarter turn rotation of ``self``.269270EXAMPLES::271272sage: A = AlternatingSignMatrices(3)273sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).rotate_ccw()274[0 0 1]275[0 1 0]276[1 0 0]277sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])278sage: asm.rotate_ccw()279[1 0 0]280[0 0 1]281[0 1 0]282"""283l = list(self._matrix.transpose())284l.reverse()285return AlternatingSignMatrix(matrix(l))286287@combinatorial_map(name='rotate clockwise')288def rotate_cw(self):289r"""290Return the clockwise quarter turn rotation of ``self``.291292EXAMPLES::293294sage: A = AlternatingSignMatrices(3)295sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).rotate_cw()296[0 0 1]297[0 1 0]298[1 0 0]299sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])300sage: asm.rotate_cw()301[0 1 0]302[1 0 0]303[0 0 1]304"""305l = list(self._matrix.transpose())306l.reverse()307return AlternatingSignMatrix(matrix(l).transpose().antitranspose())308309@combinatorial_map(name='transpose')310def transpose(self):311r"""312Return the counterclockwise quarter turn rotation of ``self``.313314EXAMPLES::315316sage: A = AlternatingSignMatrices(3)317sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).transpose()318[1 0 0]319[0 1 0]320[0 0 1]321sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])322sage: asm.transpose()323[0 1 0]324[0 0 1]325[1 0 0]326"""327return AlternatingSignMatrix(self._matrix.transpose())328329def corner_sum_matrix(self):330r"""331Return the corner sum matrix from ``self``.332333EXAMPLES::334335sage: A = AlternatingSignMatrices(3)336sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).corner_sum_matrix()337[0 0 0 0]338[0 1 1 1]339[0 1 2 2]340[0 1 2 3]341sage: asm = A([[0, 1, 0],[1, -1, 1],[0, 1, 0]])342sage: asm.corner_sum_matrix()343[0 0 0 0]344[0 0 1 1]345[0 1 1 2]346[0 1 2 3]347sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])348sage: asm.corner_sum_matrix()349[0 0 0 0]350[0 0 1 1]351[0 0 1 2]352[0 1 2 3]353"""354asm = self.to_matrix()355n = asm.nrows() + 1356return matrix([[nw_corner_sum(asm,i,j) for i in range(n)] for j in range(n)])357358def height_function(self):359r"""360Return the height function from ``self``. A height function361corresponding to an `n \times n` ASM is an `(n+1) \times (n+1)` matrix362such that the first row is `0, 1, \ldots, n`, the last row is363`n, n-1, \ldots, 1, 0`, and the difference between adjacent entries364is 1.365366EXAMPLES::367368sage: A = AlternatingSignMatrices(3)369sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).height_function()370[0 1 2 3]371[1 0 1 2]372[2 1 0 1]373[3 2 1 0]374sage: asm = A([[0, 1, 0],[1, -1, 1],[0, 1, 0]])375sage: asm.height_function()376[0 1 2 3]377[1 2 1 2]378[2 1 2 1]379[3 2 1 0]380sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])381sage: asm.height_function()382[0 1 2 3]383[1 2 1 2]384[2 3 2 1]385[3 2 1 0]386"""387asm = self.to_matrix()388n = asm.nrows() + 1389return matrix([[i+j-2*nw_corner_sum(asm,i,j) for i in range(n)] for j in range(n)])390391@combinatorial_map(name='gyration')392def gyration(self):393r"""394Return the alternating sign matrix obtained by applying the gyration395action to the height function in bijection with ``self``.396397Gyration acts on height functions as follows. Go through the entries of398the matrix, first those for which the sum of the row and column indices399is even, then for those for which it is odd, and increment or decrement400the squares by 2 wherever possible such that the resulting matrix is401still a height function. Gyration was first defined in [Wieland00]_ as402an action on fully-packed loops.403404REFERENCES:405406.. [Wieland00] B. Wieland. *A large dihedral symmetry of the set of407alternating sign matrices*. Electron. J. Combin. 7 (2000).408409EXAMPLES::410411sage: A = AlternatingSignMatrices(3)412sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).gyration()413[0 0 1]414[0 1 0]415[1 0 0]416sage: asm = A([[0, 1, 0],[1, -1, 1],[0, 1, 0]])417sage: asm.gyration()418[1 0 0]419[0 1 0]420[0 0 1]421sage: asm = A([[0, 0, 1],[1, 0, 0],[0, 1, 0]])422sage: asm.gyration()423[0 1 0]424[0 0 1]425[1 0 0]426"""427A = self.parent()428hf = list(self.height_function())429k = len(hf) - 1430for i in range(1,k):431for j in range(1,k):432if (i+j) % 2 == 0 \433and hf[i-1][j] == hf[i+1][j] == hf[i][j+1] == hf[i][j-1]:434if hf[i][j] < hf[i+1][j]:435hf[i][j] += 2436else:437hf[i][j] -= 2438for i in range(1,k):439for j in range(1,k):440if (i+j) % 2 == 1 \441and hf[i-1][j] == hf[i+1][j] == hf[i][j+1] == hf[i][j-1]:442if hf[i][j] < hf[i+1][j]:443hf[i][j] += 2444else:445hf[i][j] -= 2446return A.from_height_function(matrix(hf))447448def ASM_compatible(self, B):449r"""450Return ``True`` if ``self`` and ``B`` are compatible alternating sign451matrices in the sense of [EKLP92]_. (If ``self`` is of size `n`, ``B``452must be of size `n+1`.)453454In [EKLP92]_, there is a notion of a pair of ASM's with sizes differing455by 1 being compatible, in the sense that they can be combined to encode456a tiling of the Aztec Diamond.457458REFERENCES:459460.. [EKLP92] N. Elkies, G. Kuperberg, M. Larsen, J. Propp,461*Alternating-Sign Matrices and Domino Tilings*, Journal of Algebraic462Combinatorics, volume 1 (1992), p. 111-132.463464EXAMPLES::465466sage: A = AlternatingSignMatrix(matrix([[0,0,1,0],[0,1,-1,1],[1,0,0,0],[0,0,1,0]]))467sage: B = AlternatingSignMatrix(matrix([[0,0,1,0,0],[0,0,0,1,0],[1,0,0,-1,1],[0,1,0,0,0],[0,0,0,1,0]]))468sage: A.ASM_compatible(B)469True470sage: A = AlternatingSignMatrix(matrix([[0,1,0],[1,-1,1],[0,1,0]]))471sage: B = AlternatingSignMatrix(matrix([[0,0,1,0],[0,0,0,1],[1,0,0,0],[0,1,0,0]]))472sage: A.ASM_compatible(B)473False474"""475if B.parent()._n - self.parent()._n != 1:476raise ValueError("mismatched sizes")477478AA = self.corner_sum_matrix()479BB = B.corner_sum_matrix()480for i in range(0, len(AA[0])):481for j in range(0, len(AA[0])):482if not (AA[i,j]>=BB[i,j] and AA[i,j]>=BB[i+1,j+1]-1 \483and AA[i,j]<=BB[i+1,j] and AA[i,j]<=BB[i,j+1]):484return False485return True486487def ASM_compatible_bigger(self):488r"""489Return all ASM's compatible with ``self`` that are of size one greater490than ``self``.491492Given an `n \times n` alternating sign matrix `A`, there are as many493ASM's of size `n+1` compatible with `A` as 2 raised to the power of494the number of 1's in `A` [EKLP92]_.495496EXAMPLES::497498sage: A = AlternatingSignMatrix(matrix([[1,0],[0,1]]))499sage: A.ASM_compatible_bigger()500[501[ 0 1 0] [1 0 0] [0 1 0] [1 0 0]502[ 1 -1 1] [0 0 1] [1 0 0] [0 1 0]503[ 0 1 0], [0 1 0], [0 0 1], [0 0 1]504]505sage: B = AlternatingSignMatrix(matrix([[0,1],[1,0]]))506sage: B.ASM_compatible_bigger()507[508[0 0 1] [0 0 1] [0 1 0] [ 0 1 0]509[0 1 0] [1 0 0] [0 0 1] [ 1 -1 1]510[1 0 0], [0 1 0], [1 0 0], [ 0 1 0]511]512"""513n = self.parent()._n + 1514M = AlternatingSignMatrices(n)515sign = []516asm = self.to_matrix()517B = matrix(n+1)518A = matrix([[2*(i+j-2*nw_corner_sum(asm,i,j))+1 for i in range(n)]519for j in range(n)])520for a in range(n+1):521B[a,0] = 2*a522B[0,a] = 2*a523B[a,n] = 2*(n-a)524B[n,a] = 2*(n-a)525526for i in range(1,n):527for j in range(1,n):528if A[i-1,j-1] == A[i,j] == A[i-1,j]-2 == A[i,j-1]-2:529B[i,j] = -A[i,j]530sign.append([i,j])531else:532B[i,j] = list({A[i-1,j-1]-1,A[i-1,j-1]+3} & {A[i-1,j]-3,A[i-1,j]+1} & {A[i,j-1]-3,A[i,j-1]+1} & {A[i,j]-1,A[i,j]+3})[0]533534output = [B]535for b in range(len(sign)):536N = len(output)537for c in range(N):538d = copy.copy(output[c])539output[c][sign[b][0],sign[b][1]] = -output[c][sign[b][0], sign[b][1]] + 3540d[sign[b][0],sign[b][1]] = -d[sign[b][0], sign[b][1]]-1541output.append(d)542543for k in range(len(output)):544output[k] = M.from_height_function(output[k]/2)545return(output)546547def ASM_compatible_smaller(self):548r"""549Return the list of all ASMs compatible with ``self`` that are of size550one smaller than ``self``.551552Given an alternating sign matrix `A` of size `n`, there are as many553ASM's of size `n-1` compatible with it as 2 raised to the power of554the number of `-1`'s in `A` [EKLP92]_.555556EXAMPLES::557558sage: A = AlternatingSignMatrix(matrix([[0,0,1,0],[0,1,-1,1],[1,0,0,0],[0,0,1,0]]))559sage: A.ASM_compatible_smaller()560[561[0 0 1] [ 0 1 0]562[1 0 0] [ 1 -1 1]563[0 1 0], [ 0 1 0]564]565sage: B = AlternatingSignMatrix(matrix([[1,0,0],[0,0,1],[0,1,0]]))566sage: B.ASM_compatible_smaller()567[568[1 0]569[0 1]570]571572"""573n = self.parent()._n574M = AlternatingSignMatrices(n)575A = matrix(n)576asm = self.to_matrix()577B = matrix([[2*(i+j-2*nw_corner_sum(asm,i,j)) for i in range(n)] for j in range(n)])578sign = []579for a in range(n):580A[a,0] = 2*a + 1581A[0,a] = 2*a + 1582A[n-1,a] = 2*(n-a) - 1583A[a,n-1] = 2*(n-a) - 1584585for i in range(n-1):586for j in range(n-1):587if B[i+1,j+1] == B[i,j] == B[i,j+1]+2 == B[i+1,j]+2:588A[i,j] = -B[i,j]589sign.append([i,j])590else:591A[i,j] = list({B[i,j]+1,B[i,j]-3} & {B[i,j+1]+3,B[i,j+1]-1} & {B[i+1,j]+3,B[i+1,j]-1} & {B[i+1,j+1]+1,B[i+1,j+1]-3})[0]592593output = [A]594for b in range(len(sign)):595N = len(output)596for c in range(N):597d = copy.copy(output[c])598output[c][sign[b][0],sign[b][1]] = -output[c][sign[b][0], sign[b][1]]+1599d[sign[b][0],sign[b][1]] = -d[sign[b][0], sign[b][1]]-3600output.append(d)601for k in range(0,len(output)):602output[k] = M.from_height_function((output[k]-matrix.ones(n,n))/2)603return(output)604605@combinatorial_map(name='to Dyck word')606def to_dyck_word(self):607r"""608Return the Dyck word determined by the last diagonal of609the monotone triangle corresponding to ``self``.610611EXAMPLES::612613sage: A = AlternatingSignMatrices(3)614sage: A([[0,1,0],[1,0,0],[0,0,1]]).to_dyck_word()615[1, 1, 0, 0, 1, 0]616sage: d = A([[0,1,0],[1,-1,1],[0,1,0]]).to_dyck_word(); d617[1, 1, 0, 1, 0, 0]618sage: parent(d)619Complete Dyck words620"""621MT = self.to_monotone_triangle()622nplus = self._matrix.nrows() + 1623parkfn = [nplus - row[0] for row in list(MT) if len(row) > 0]624return NonDecreasingParkingFunction(parkfn).to_dyck_word().reverse()625626def number_negative_ones(self):627"""628Return the number of entries in ``self`` equal to -1.629630EXAMPLES::631632sage: A = AlternatingSignMatrices(3)633sage: asm = A([[0,1,0],[1,0,0],[0,0,1]])634sage: asm.number_negative_ones()6350636sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]])637sage: asm.number_negative_ones()6381639"""640a = self._matrix641return sum(1 for (i,j) in a.nonzero_positions() if a[i,j] == -1)642643def is_permutation(self):644"""645Return ``True`` if ``self`` is a permutation matrix646and ``False`` otherwise.647648EXAMPLES::649650sage: A = AlternatingSignMatrices(3)651sage: asm = A([[0,1,0],[1,0,0],[0,0,1]])652sage: asm.is_permutation()653True654sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]])655sage: asm.is_permutation()656False657"""658return self.number_negative_ones() == 0659660def to_permutation(self):661"""662Return the corresponding permutation if ``self`` is a permutation663matrix.664665EXAMPLES::666667sage: A = AlternatingSignMatrices(3)668sage: asm = A([[0,1,0],[1,0,0],[0,0,1]])669sage: p = asm.to_permutation(); p670[2, 1, 3]671sage: parent(p)672Standard permutations673sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]])674sage: asm.to_permutation()675Traceback (most recent call last):676...677ValueError: Not a permutation matrix678"""679if not self.is_permutation():680raise ValueError('Not a permutation matrix')681asm_matrix = self.to_matrix()682return Permutation([ j+1 for (i,j) in asm_matrix.nonzero_positions() ])683684@combinatorial_map(name='to semistandard tableau')685def to_semistandard_tableau(self):686"""687Return the semistandard tableau corresponding the monotone triangle688corresponding to ``self``.689690EXAMPLES::691692sage: A = AlternatingSignMatrices(3)693sage: A([[0,0,1],[1,0,0],[0,1,0]]).to_semistandard_tableau()694[[1, 1, 3], [2, 3], [3]]695sage: t = A([[0,1,0],[1,-1,1],[0,1,0]]).to_semistandard_tableau(); t696[[1, 1, 2], [2, 3], [3]]697sage: parent(t)698Semistandard tableaux699"""700from sage.combinat.tableau import SemistandardTableau, SemistandardTableaux701mt = self.to_monotone_triangle()702ssyt = [[0]*(len(mt) - j) for j in range(len(mt))]703for i in range(len(mt)):704for j in range(len(mt[i])):705ssyt[i][j] = mt[j][-(i+1)]706return SemistandardTableau(ssyt)707708def left_key(self):709r"""710Return the left key of the alternating sign matrix ``self``.711712The left key of an alternating sign matrix was defined by Lascoux713in [LascouxPreprint]_ and is obtained by successively removing all the714`-1`'suntil what remains is a permutation matrix. This notion715corresponds to the notion of left key for semistandard tableaux. So716our algorithm proceeds as follows: we map ``self`` to its717corresponding monotone triangle, view that monotone triangle as a718semistandard tableaux, take its left key, and then map back through719monotone triangles to the permutation matrix which is the left key.720721REFERENCES:722723.. [Aval07] J.-C. Aval. *Keys and alternating sign matrices*.724Sem. Lothar. Combin. 59 (2007/10), Art. B59f, 13 pp.725726.. [LascouxPreprint] A. Lascoux. *Chern and Yang through ice*.727Preprint.728729EXAMPLES::730731sage: A = AlternatingSignMatrices(3)732sage: A([[0,0,1],[1,0,0],[0,1,0]]).left_key()733[0 0 1]734[1 0 0]735[0 1 0]736sage: t = A([[0,1,0],[1,-1,1],[0,1,0]]).left_key(); t737[1 0 0]738[0 0 1]739[0 1 0]740sage: parent(t)741Alternating sign matrices of size 3742"""743from sage.combinat.tableau import SemistandardTableau, SemistandardTableaux744lkey = self.to_semistandard_tableau().left_key_tableau()745mt = [[0]*(len(lkey) - j) for j in range(len(lkey))]746for i in range(len(lkey)):747for j in range(len(lkey[i])):748mt[i][j] = lkey[len(lkey[i])-j-1][i]749A = AlternatingSignMatrices(len(lkey))750return A.from_monotone_triangle(mt)751752@combinatorial_map(name='to left key permutation')753def left_key_as_permutation(self):754"""755Return the permutation of the left key of ``self``.756757.. SEEALSO::758759- :meth:`left_key()`760761EXAMPLES::762763sage: A = AlternatingSignMatrices(3)764sage: A([[0,0,1],[1,0,0],[0,1,0]]).left_key_as_permutation()765[3, 1, 2]766sage: t = A([[0,1,0],[1,-1,1],[0,1,0]]).left_key_as_permutation(); t767[1, 3, 2]768sage: parent(t)769Standard permutations770"""771return self.left_key().to_permutation()772773class AlternatingSignMatrices(Parent, UniqueRepresentation):774r"""775Class of all `n \times n` alternating sign matrices.776777An alternating sign matrix of size `n` is an `n \times n` matrix of `0`'s,778`1`'s and `-1`'s such that the sum of each row and column is `1` and the779non-zero entries in each row and column alternate in sign.780781Alternating sign matrices of size `n` are in bijection with782:class:`monotone triangles <MonotoneTriangles>` with `n` rows.783784INPUT:785786- `n` -- an integer, the size of the matrices.787788- ``use_monotone_triangle`` -- (Default: ``True``) If ``True``, the789generation of the matrices uses monotone triangles, else it will use the790earlier and now obsolete contre-tableaux implementation;791must be ``True`` to generate a lattice (with the ``lattice`` method)792793EXAMPLES:794795This will create an instance to manipulate the alternating sign796matrices of size 3::797798sage: A = AlternatingSignMatrices(3)799sage: A800Alternating sign matrices of size 3801sage: A.cardinality()8027803804Notably, this implementation allows to make a lattice of it::805806sage: L = A.lattice()807sage: L808Finite lattice containing 7 elements809sage: L.category()810Category of facade finite lattice posets811"""812def __init__(self, n, use_monotone_triangles=True):813r"""814Initialize ``self``.815816TESTS::817818sage: A = AlternatingSignMatrices(4)819sage: TestSuite(A).run()820sage: A == AlternatingSignMatrices(4, use_monotone_triangles=False)821False822"""823self._n = n824self._matrix_space = MatrixSpace(ZZ, n)825self._umt = use_monotone_triangles826Parent.__init__(self, category=FiniteEnumeratedSets())827828def _repr_(self):829r"""830Return a string representation of ``self``.831832TESTS::833834sage: A = AlternatingSignMatrices(4); A835Alternating sign matrices of size 4836"""837return "Alternating sign matrices of size %s" % self._n838839def _repr_option(self, key):840"""841Metadata about the :meth:`_repr_` output.842843See :meth:`sage.structure.parent._repr_option` for details.844845EXAMPLES::846847sage: A = AlternatingSignMatrices(3)848sage: A._repr_option('element_ascii_art')849True850"""851return self._matrix_space._repr_option(key)852853def __contains__(self, asm):854"""855Check if ``asm`` is in ``self``.856857TESTS::858859sage: A = AlternatingSignMatrices(3)860sage: [[0,1,0],[1,0,0],[0,0,1]] in A861True862sage: [[0,1,0],[1,-1,1],[0,1,0]] in A863True864sage: [[0, 1],[1,0]] in A865False866sage: [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]] in A867False868sage: [[-1, 1, 1],[1,-1,1],[1,1,-1]] in A869False870"""871if isinstance(asm, AlternatingSignMatrix):872return asm._matrix.nrows() == self._n873try:874asm = self._matrix_space(asm)875except (TypeError, ValueError):876return False877for row in asm:878pos = False879for val in row:880if val > 0:881if pos:882return False883else:884pos = True885elif val < 0:886if pos:887pos = False888else:889return False890if not pos:891return False892if any(sum(row) != 1 for row in asm.columns()):893return False894return True895896def _element_constructor_(self, asm):897"""898Construct an element of ``self``.899900EXAMPLES::901902sage: A = AlternatingSignMatrices(3)903sage: elt = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]); elt904[1 0 0]905[0 1 0]906[0 0 1]907sage: elt.parent() is A908True909sage: A([[3, 2, 1], [2, 1], [1]])910[1 0 0]911[0 1 0]912[0 0 1]913"""914if isinstance(asm, AlternatingSignMatrix):915if asm.parent() is self:916return asm917raise ValueError("Cannot convert between alternating sign matrices of different sizes")918if asm in MonotoneTriangles(self._n):919return self.from_monotone_triangle(asm)920return self.element_class(self, self._matrix_space(asm))921922Element = AlternatingSignMatrix923924def _an_element_(self):925"""926Return an element of ``self``.927"""928return self.element_class(self, self._matrix_space.identity_matrix())929930def from_monotone_triangle(self, triangle):931r"""932Return an alternating sign matrix from a monotone triangle.933934EXAMPLES::935936sage: A = AlternatingSignMatrices(3)937sage: A.from_monotone_triangle([[3, 2, 1], [2, 1], [1]])938[1 0 0]939[0 1 0]940[0 0 1]941sage: A.from_monotone_triangle([[3, 2, 1], [3, 2], [3]])942[0 0 1]943[0 1 0]944[1 0 0]945"""946n = len(triangle)947if n != self._n:948raise ValueError("Incorrect size")949asm = []950951prev = [0]*n952for line in reversed(triangle):953v = [1 if j+1 in reversed(line) else 0 for j in range(n)]954row = [a-b for (a, b) in zip(v, prev)]955asm.append(row)956prev = v957958return self.element_class(self, self._matrix_space(asm))959960def from_corner_sum(self, corner):961r"""962Return an alternating sign matrix from a corner sum matrix.963964EXAMPLES::965966sage: A = AlternatingSignMatrices(3)967sage: A.from_corner_sum(matrix([[0,0,0,0],[0,1,1,1],[0,1,2,2],[0,1,2,3]]))968[1 0 0]969[0 1 0]970[0 0 1]971sage: A.from_corner_sum(matrix([[0,0,0,0],[0,0,1,1],[0,1,1,2],[0,1,2,3]]))972[ 0 1 0]973[ 1 -1 1]974[ 0 1 0]975"""976asm_list=[]977n = len(list(corner)) - 1978for k in range(n):979asm_list.append([])980for i in range(n):981for j in range(n):982y = corner[i+1][j+1] \983- sum([sum([asm_list[i2][j2] for i2 in range(i)])984for j2 in range(j)]) \985- sum([asm_list[i2][j] for i2 in range(i)]) \986- sum([asm_list[i][j2] for j2 in range(j)])987asm_list[i].append(y)988return AlternatingSignMatrix(asm_list)989990def from_height_function(self,height):991r"""992Return an alternating sign matrix from a height function.993994EXAMPLES::995996sage: A = AlternatingSignMatrices(3)997sage: A.from_height_function(matrix([[0,1,2,3],[1,2,1,2],[2,3,2,1],[3,2,1,0]]))998[0 0 1]999[1 0 0]1000[0 1 0]1001sage: A.from_height_function(matrix([[0,1,2,3],[1,2,1,2],[2,1,2,1],[3,2,1,0]]))1002[ 0 1 0]1003[ 1 -1 1]1004[ 0 1 0]1005"""1006return self.from_corner_sum(matrix( [[((i+j-height[i][j])/int(2))1007for i in range(len(list(height)))]1008for j in range(len(list(height)))] ))10091010def size(self):1011r"""1012Return the size of the matrices in ``self``.10131014TESTS::10151016sage: A = AlternatingSignMatrices(4)1017sage: A.size()101841019"""1020return self._n10211022def cardinality(self):1023r"""1024Return the cardinality of ``self``.10251026The number of `n \times n` alternating sign matrices is equal to10271028.. MATH::10291030\prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10!1031\cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}10321033EXAMPLES::10341035sage: [AlternatingSignMatrices(n).cardinality() for n in range(0, 11)]1036[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]1037"""1038return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k)1039for k in range(self._n)] ))10401041def matrix_space(self):1042"""1043Return the underlying matrix space.10441045EXAMPLES::10461047sage: A = AlternatingSignMatrices(3)1048sage: A.matrix_space()1049Full MatrixSpace of 3 by 3 dense matrices over Integer Ring1050"""1051return self._matrix_space10521053def __iter__(self):1054r"""1055Iterator on the alternating sign matrices of size `n`.10561057If defined using ``use_monotone_triangles``, this iterator1058will use the iteration on the monotone triangles. Else, it1059will use the iteration on contre-tableaux.10601061TESTS::10621063sage: A = AlternatingSignMatrices(4)1064sage: len(list(A))1065421066"""1067if self._umt:1068for t in MonotoneTriangles(self._n):1069yield self.from_monotone_triangle(t)1070else:1071for c in ContreTableaux(self._n):1072yield from_contre_tableau(c)10731074def _lattice_initializer(self):1075r"""1076Return a 2-tuple to use in argument of ``LatticePoset``.10771078For more details about the cover relations, see1079``MonotoneTriangles``. Notice that the returned matrices are1080made immutable to ensure their hashability required by1081``LatticePoset``.10821083EXAMPLES:10841085Proof of the lattice property for alternating sign matrices of1086size 3::10871088sage: A = AlternatingSignMatrices(3)1089sage: P = Poset(A._lattice_initializer())1090sage: P.is_lattice()1091True1092"""1093assert(self._umt)1094(mts, rels) = MonotoneTriangles(self._n)._lattice_initializer()1095bij = dict((t, self.from_monotone_triangle(t)) for t in mts)1096asms, rels = bij.itervalues(), [(bij[a], bij[b]) for (a,b) in rels]1097return (asms, rels)10981099def cover_relations(self):1100r"""1101Iterate on the cover relations between the alternating sign1102matrices.11031104EXAMPLES::11051106sage: A = AlternatingSignMatrices(3)1107sage: for (a,b) in A.cover_relations():1108....: eval('a, b')1109(1110[1 0 0] [0 1 0]1111[0 1 0] [1 0 0]1112[0 0 1], [0 0 1]1113)1114(1115[1 0 0] [1 0 0]1116[0 1 0] [0 0 1]1117[0 0 1], [0 1 0]1118)1119(1120[0 1 0] [ 0 1 0]1121[1 0 0] [ 1 -1 1]1122[0 0 1], [ 0 1 0]1123)1124(1125[1 0 0] [ 0 1 0]1126[0 0 1] [ 1 -1 1]1127[0 1 0], [ 0 1 0]1128)1129(1130[ 0 1 0] [0 0 1]1131[ 1 -1 1] [1 0 0]1132[ 0 1 0], [0 1 0]1133)1134(1135[ 0 1 0] [0 1 0]1136[ 1 -1 1] [0 0 1]1137[ 0 1 0], [1 0 0]1138)1139(1140[0 0 1] [0 0 1]1141[1 0 0] [0 1 0]1142[0 1 0], [1 0 0]1143)1144(1145[0 1 0] [0 0 1]1146[0 0 1] [0 1 0]1147[1 0 0], [1 0 0]1148)11491150"""1151(_, rels) = self._lattice_initializer()1152return (_ for _ in rels)11531154def lattice(self):1155r"""1156Return the lattice of the alternating sign matrices of size1157`n`, created by ``LatticePoset``.11581159EXAMPLES::11601161sage: A = AlternatingSignMatrices(3)1162sage: L = A.lattice()1163sage: L1164Finite lattice containing 7 elements11651166"""1167return LatticePoset(self._lattice_initializer(), cover_relations=True)116811691170class MonotoneTriangles(GelfandTsetlinPatternsTopRow):1171r"""1172Monotone triangles with `n` rows.11731174A monotone triangle is a number triangle `(a_{i,j})_{1 \leq i \leq1175n , 1 \leq j \leq i}` on `\{1, \dots, n\}` such that:11761177- `a_{i,j} < a_{i,j+1}`11781179- `a_{i+1,j} < a_{i,j} \leq a_{i+1,j+1}`11801181This notably requires that the bottom column is ``[1,...,n]``.11821183Alternatively a monotone triangle is a strict Gelfand-Tsetlin pattern with1184top row `(n, \ldots, 2, 1)`.11851186INPUT:11871188- ``n`` -- The number of rows in the monotone triangles11891190EXAMPLES:11911192This represents the monotone triangles with base ``[3,2,1]``::11931194sage: M = MonotoneTriangles(3)1195sage: M1196Monotone triangles with 3 rows1197sage: M.cardinality()1198711991200The monotone triangles are a lattice::12011202sage: M.lattice()1203Finite lattice containing 7 elements12041205Monotone triangles can be converted to alternating sign matrices1206and back::12071208sage: M = MonotoneTriangles(5)1209sage: A = AlternatingSignMatrices(5)1210sage: all(A.from_monotone_triangle(m).to_monotone_triangle() == m for m in M)1211True1212"""1213def __init__(self, n):1214r"""1215Initialize ``self``.12161217TESTS::12181219sage: M = MonotoneTriangles(4)1220sage: TestSuite(M).run()1221sage: M2 = MonotoneTriangles(int(4))1222sage: M is M21223True1224"""1225GelfandTsetlinPatternsTopRow.__init__(self, tuple(reversed(range(1, n+1))), True)12261227def _repr_(self):1228r"""1229String representation.12301231TESTS::12321233sage: M = MonotoneTriangles(4)1234sage: M1235Monotone triangles with 4 rows1236"""1237return "Monotone triangles with %s rows" % self._n12381239def cardinality(self):1240r"""1241Cardinality of ``self``.12421243The number of monotone triangles with `n` rows is equal to12441245.. MATH::12461247\prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10!1248\cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}12491250EXAMPLES::12511252sage: M = MonotoneTriangles(4)1253sage: M.cardinality()1254421255"""1256return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k)1257for k in range(self._n)] ))12581259def _lattice_initializer(self):1260r"""1261Return a 2-tuple to use in argument of ``LatticePoset``.12621263This couple is composed by the set of the monotone triangles1264with `n` rows and the cover relations. Specializing this1265function allows to generate the monotone triangles just once,1266and so to speed up the computation in comparison of1267``(list(self), self.cover_relations())``. Notice that the1268function also switch the representation of monotone triangles1269from list of list to tuple of tuple in order to make them1270hashable (required to make a poset with them).12711272EXAMPLES::12731274sage: M = MonotoneTriangles(3)1275sage: P = Poset(M._lattice_initializer())1276sage: P.is_lattice()1277True1278"""1279# get a list of the elements and switch to a tuple1280# representation1281set_ = list(self)1282set_ = map(lambda x: tuple(map(tuple, x)), set_)1283return (set_, [(a,b) for a in set_ for b in set_ if _is_a_cover(a,b)])12841285def cover_relations(self):1286r"""1287Iterate on the cover relations in the set of monotone triangles1288with `n` rows.12891290EXAMPLES::12911292sage: M = MonotoneTriangles(3)1293sage: for (a,b) in M.cover_relations():1294....: eval('a, b')1295([[3, 2, 1], [2, 1], [1]], [[3, 2, 1], [2, 1], [2]])1296([[3, 2, 1], [2, 1], [1]], [[3, 2, 1], [3, 1], [1]])1297([[3, 2, 1], [2, 1], [2]], [[3, 2, 1], [3, 1], [2]])1298([[3, 2, 1], [3, 1], [1]], [[3, 2, 1], [3, 1], [2]])1299([[3, 2, 1], [3, 1], [2]], [[3, 2, 1], [3, 1], [3]])1300([[3, 2, 1], [3, 1], [2]], [[3, 2, 1], [3, 2], [2]])1301([[3, 2, 1], [3, 1], [3]], [[3, 2, 1], [3, 2], [3]])1302([[3, 2, 1], [3, 2], [2]], [[3, 2, 1], [3, 2], [3]])1303"""1304set_ = list(self)1305return ((a,b) for a in set_ for b in set_ if _is_a_cover(a,b))13061307def lattice(self):1308r"""1309Return the lattice of the monotone triangles with `n` rows.13101311EXAMPLES::13121313sage: M = MonotoneTriangles(3)1314sage: P = M.lattice()1315sage: P1316Finite lattice containing 7 elements13171318"""1319return LatticePoset(self._lattice_initializer(), cover_relations=True)13201321def _is_a_cover(mt0, mt1):1322r"""1323Define the cover relations.13241325Return ``True`` if and only if the second argument is a cover of1326the first one.13271328EXAMPLES::13291330sage: import sage.combinat.alternating_sign_matrix as asm1331sage: asm._is_a_cover([[1,2,3],[1,2],[1]], [[1,2,3],[1,3],[1]])1332True1333sage: asm._is_a_cover([[1,2,3],[1,3],[2]], [[1,2,3],[1,2],[1]])1334False1335"""1336diffs = 01337for (a,b) in itertools.izip(flatten(mt0), flatten(mt1)):1338if a != b:1339if a+1 == b:1340diffs += 11341else:1342return False1343if diffs > 1:1344return False1345return diffs == 113461347# Deprecated methods13481349def to_monotone_triangle(matrix):1350"""1351Deprecated method, use :meth:`AlternatingSignMatrix.to_monotone_triangle()`1352instead.13531354EXAMPLES::13551356sage: sage.combinat.alternating_sign_matrix.to_monotone_triangle([[0,1],[1,0]])1357doctest:...: DeprecationWarning: to_monotone_triangle() is deprecated. Use AlternatingSignMatrix.to_monotone_triangle() instead1358See http://trac.sagemath.org/14301 for details.1359[[2, 1], [2]]1360"""1361from sage.misc.superseded import deprecation1362deprecation(14301,'to_monotone_triangle() is deprecated. Use AlternatingSignMatrix.to_monotone_triangle() instead')1363return AlternatingSignMatrix(matrix).to_monotone_triangle()13641365def from_monotone_triangle(triangle):1366"""1367Deprecated method, use1368:meth:`AlternatingSignMatrices.from_monotone_triangle()` instead.13691370EXAMPLES::13711372sage: sage.combinat.alternating_sign_matrix.from_monotone_triangle([[1, 2], [2]])1373doctest:...: DeprecationWarning: from_monotone_triangle() is deprecated. Use AlternatingSignMatrix.from_monotone_triangle() instead1374See http://trac.sagemath.org/14301 for details.1375[0 1]1376[1 0]1377"""1378from sage.misc.superseded import deprecation1379deprecation(14301,'from_monotone_triangle() is deprecated. Use AlternatingSignMatrix.from_monotone_triangle() instead')1380return AlternatingSignMatrices(len(triangle)).from_monotone_triangle(triangle)13811382# For old pickles1383def AlternatingSignMatrices_n(n):1384"""1385For old pickles of ``AlternatingSignMatrices_n``.13861387EXAMPLES::13881389sage: sage.combinat.alternating_sign_matrix.AlternatingSignMatrices_n(3)1390doctest:...: DeprecationWarning: this class is deprecated. Use sage.combinat.alternating_sign_matrix.AlternatingSignMatrices instead1391See http://trac.sagemath.org/14301 for details.1392Alternating sign matrices of size 31393"""1394from sage.misc.superseded import deprecation1395deprecation(14301,'this class is deprecated. Use sage.combinat.alternating_sign_matrix.AlternatingSignMatrices instead')1396return AlternatingSignMatrices(n)13971398def MonotoneTriangles_n(n):1399"""1400For old pickles of ``MonotoneTriangles_n``.14011402EXAMPLES::14031404sage: sage.combinat.alternating_sign_matrix.MonotoneTriangles_n(3)1405doctest:...: DeprecationWarning: this class is deprecated. Use sage.combinat.alternating_sign_matrix.MonotoneTriangles instead1406See http://trac.sagemath.org/14301 for details.1407Monotone triangles with 3 rows1408"""1409from sage.misc.superseded import deprecation1410deprecation(14301,'this class is deprecated. Use sage.combinat.alternating_sign_matrix.MonotoneTriangles instead')1411return MonotoneTriangles(n)14121413from sage.structure.sage_object import register_unpickle_override1414register_unpickle_override('sage.combinat.alternating_sign_matrix', 'AlternatingSignMatrices_n', AlternatingSignMatrices)1415register_unpickle_override('sage.combinat.alternating_sign_matrix', 'MonotoneTriangles_n', MonotoneTriangles)1416register_unpickle_override('sage.combinat.alternating_sign_matrix', 'MonotoneTriangles_n', MonotoneTriangles_n)14171418# Here are the previous implementations of the combinatorial structure1419# of the alternating sign matrices. Please, consider it obsolete and1420# tend to use the monotone triangles instead.14211422def from_contre_tableau(comps):1423r"""1424Returns an alternating sign matrix from a contre-tableau.14251426EXAMPLES::14271428sage: import sage.combinat.alternating_sign_matrix as asm1429sage: asm.from_contre_tableau([[1, 2, 3], [1, 2], [1]])1430doctest:...: DeprecationWarning: You can use from_monotone_triangle instead.1431See http://trac.sagemath.org/12930 for details.1432[0 0 1]1433[0 1 0]1434[1 0 0]1435sage: asm.from_contre_tableau([[1, 2, 3], [2, 3], [3]])1436[1 0 0]1437[0 1 0]1438[0 0 1]1439"""1440from sage.misc.superseded import deprecation1441deprecation(12930, 'You can use from_monotone_triangle instead.')1442n = len(comps)1443MS = MatrixSpace(ZZ, n)1444M = [ [0 for _ in range(n)] for _ in range(n) ]14451446previous_set = Set([])14471448for col in range(n-1, -1, -1):1449s = Set( comps[col] )1450for x in s - previous_set:1451M[x-1][col] = 114521453for x in previous_set - s:1454M[x-1][col] = -114551456previous_set = s14571458return MS(M)145914601461class ContreTableaux(Parent):1462"""1463Factory class for the combinatorial class of contre tableaux of size `n`.14641465EXAMPLES::14661467sage: ct4 = ContreTableaux(4); ct41468Contre tableaux of size 41469sage: ct4.cardinality()1470421471"""1472__metaclass__ = ClasscallMetaclass1473@staticmethod1474def __classcall_private__(cls, n, **kwds):1475r"""1476Factory pattern.14771478Check properties on arguments, then call the appropriate class.14791480EXAMPLES::14811482sage: C = ContreTableaux(4)1483sage: type(C)1484<class 'sage.combinat.alternating_sign_matrix.ContreTableaux_n'>14851486"""1487assert(isinstance(n, (int, Integer)))1488return ContreTableaux_n(n, **kwds)148914901491class ContreTableaux_n(ContreTableaux):1492def __init__(self, n):1493"""1494TESTS::14951496sage: ct2 = ContreTableaux(2); ct21497Contre tableaux of size 21498sage: ct2 == loads(dumps(ct2))1499True1500"""1501self.n = n15021503def __repr__(self):1504"""1505TESTS::15061507sage: repr(ContreTableaux(2))1508'Contre tableaux of size 2'1509"""1510return "Contre tableaux of size %s"%self.n15111512def __eq__(self, other):1513"""1514TESTS::15151516sage: C = ContreTableaux(4)1517sage: C == loads(dumps(C))1518True15191520"""1521return self.n == other.n15221523def cardinality(self):1524"""1525EXAMPLES::15261527sage: [ ContreTableaux(n).cardinality() for n in range(0, 11)]1528[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]1529"""1530return prod( [ factorial(3*k+1)/factorial(self.n+k) for k in range(self.n)] )15311532def _iterator_rec(self, i):1533"""1534EXAMPLES::15351536sage: c = ContreTableaux(2)1537sage: list(c._iterator_rec(0))1538[[]]1539sage: list(c._iterator_rec(1))1540[[[1, 2]]]1541sage: list(c._iterator_rec(2))1542[[[1, 2], [1]], [[1, 2], [2]]]1543"""1544if i == 0:1545yield []1546elif i == 1:1547yield [range(1, self.n+1)]1548else:1549for columns in self._iterator_rec(i-1):1550previous_column = columns[-1]1551for column in _next_column_iterator(previous_column, len(previous_column)-1):1552yield columns + [ column ]15531554def __iter__(self):1555"""1556EXAMPLES::15571558sage: list(ContreTableaux(0))1559[[]]1560sage: list(ContreTableaux(1))1561[[[1]]]1562sage: list(ContreTableaux(2))1563[[[1, 2], [1]], [[1, 2], [2]]]1564sage: list(ContreTableaux(3))1565[[[1, 2, 3], [1, 2], [1]],1566[[1, 2, 3], [1, 2], [2]],1567[[1, 2, 3], [1, 3], [1]],1568[[1, 2, 3], [1, 3], [2]],1569[[1, 2, 3], [1, 3], [3]],1570[[1, 2, 3], [2, 3], [2]],1571[[1, 2, 3], [2, 3], [3]]]1572"""15731574for z in self._iterator_rec(self.n):1575yield z157615771578def _next_column_iterator(previous_column, height, i = None):1579"""1580Returns a generator for all columns of height height properly1581filled from row 1 to ``i``15821583EXAMPLES::15841585sage: import sage.combinat.alternating_sign_matrix as asm1586sage: list(asm._next_column_iterator([1], 0))1587[[]]1588sage: list(asm._next_column_iterator([1,5],1))1589[[1], [2], [3], [4], [5]]1590sage: list(asm._next_column_iterator([1,4,5],2))1591[[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]1592"""1593if i is None:1594i = height1595if i == 0:1596yield [-1]*height1597else:1598for column in _next_column_iterator(previous_column, height, i-1):1599min_value = previous_column[i-1]1600if i > 1:1601min_value = max(min_value, column[i-2]+1)1602for value in range(min_value, previous_column[i]+1):1603c = copy.copy(column)1604c[i-1] = value1605yield c160616071608def _previous_column_iterator(column, height, max_value):1609"""1610EXAMPLES::16111612sage: import sage.combinat.alternating_sign_matrix as asm1613sage: list(asm._previous_column_iterator([2,3], 3, 4))1614[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]1615"""1616new_column = [1] + column + [ max_value ] * (height - len(column))1617return _next_column_iterator(new_column, height)161816191620class TruncatedStaircases(Parent):1621"""1622Factory class for the combinatorial class of truncated staircases1623of size ``n`` with last column ``last_column``.16241625EXAMPLES::16261627sage: t4 = TruncatedStaircases(4, [2,3]); t41628Truncated staircases of size 4 with last column [2, 3]1629sage: t4.cardinality()163041631"""1632__metaclass__ = ClasscallMetaclass1633@staticmethod1634def __classcall_private__(cls, n, last_column, **kwds):1635r"""1636Factory pattern.16371638Check properties on arguments, then call the appropriate class.16391640TESTS::16411642sage: T = TruncatedStaircases(4, [2,3])1643sage: type(T)1644<class 'sage.combinat.alternating_sign_matrix.TruncatedStaircases_nlastcolumn'>16451646"""1647assert(isinstance(n, (int, Integer)))1648return TruncatedStaircases_nlastcolumn(n, last_column, **kwds)164916501651class TruncatedStaircases_nlastcolumn(TruncatedStaircases):1652def __init__(self, n, last_column):1653"""1654TESTS::16551656sage: t4 = TruncatedStaircases(4, [2,3]); t41657Truncated staircases of size 4 with last column [2, 3]1658sage: t4 == loads(dumps(t4))1659True1660"""1661self.n = n1662self.last_column = last_column16631664def __repr__(self):1665"""1666TESTS::16671668sage: repr(TruncatedStaircases(4, [2,3]))1669'Truncated staircases of size 4 with last column [2, 3]'1670"""1671return "Truncated staircases of size %s with last column %s"%(self.n, self.last_column)16721673def _iterator_rec(self, i):1674"""1675EXAMPLES::16761677sage: t = TruncatedStaircases(3, [2,3])1678sage: list(t._iterator_rec(1))1679[]1680sage: list(t._iterator_rec(2))1681[[[2, 3]]]1682sage: list(t._iterator_rec(3))1683[[[1, 2, 3], [2, 3]]]1684"""1685if i < len(self.last_column):1686return1687elif i == len(self.last_column):1688yield [self.last_column]1689else:1690for columns in self._iterator_rec(i-1):1691previous_column = columns[0]1692for column in _previous_column_iterator(previous_column, len(previous_column)+1, self.n):1693yield [column] + columns16941695def __iter__(self):1696"""1697EXAMPLES:::16981699sage: list(TruncatedStaircases(4, [2,3]))1700[[[4, 3, 2, 1], [3, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 2], [3, 2]]]1701"""1702for z in self._iterator_rec(self.n):1703yield map(lambda x: list(reversed(x)), z)17041705def __eq__(self, other):1706r"""1707TESTS::17081709sage: T = TruncatedStaircases(4, [2,3])1710sage: T == loads(dumps(T))1711True1712"""1713return ((self.n == other.n) and1714(self.last_column == other.last_column))17151716def cardinality(self):1717r"""1718EXAMPLES::17191720sage: T = TruncatedStaircases(4, [2,3])1721sage: T.cardinality()172241723"""1724c = 01725for _ in self:1726c += 11727return c17281729def nw_corner_sum(M,i,j):1730r"""1731Return the sum of entries to the northwest of `(i,j)` in matrix.17321733EXAMPLES::17341735sage: from sage.combinat.alternating_sign_matrix import nw_corner_sum1736sage: A = matrix.ones(3,3)1737sage: nw_corner_sum(A,2,2)173841739"""1740if i >= 0 and j >= 0:1741return sum([sum([M[i2][j2] for j2 in range(j)]) for i2 in range(i)])1742return 01743174417451746