Path: blob/master/sage/combinat/alternating_sign_matrix.py
4069 views
r"""1Alternating Sign Matrices2"""3#*****************************************************************************4# Copyright (C) 2007 Mike Hansen <[email protected]>,5#6# Distributed under the terms of the GNU General Public License (GPL)7#8# This code is distributed in the hope that it will be useful,9# but WITHOUT ANY WARRANTY; without even the implied warranty of10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU11# General Public License for more details.12#13# The full text of the GPL is available at:14#15# http://www.gnu.org/licenses/16#*****************************************************************************1718from combinat import CombinatorialClass19from sage.matrix.matrix_space import MatrixSpace20from sage.rings.all import ZZ, factorial21from sage.sets.set import Set22from sage.misc.misc import prod23import copy2425def from_contre_tableau(comps):26"""27Returns an alternating sign matrix from a contretableaux.2829TESTS::3031sage: import sage.combinat.alternating_sign_matrix as asm32sage: asm.from_contre_tableau([[1, 2, 3], [1, 2], [1]])33[0 0 1]34[0 1 0]35[1 0 0]36sage: asm.from_contre_tableau([[1, 2, 3], [2, 3], [3]])37[1 0 0]38[0 1 0]39[0 0 1]40"""41n = len(comps)42MS = MatrixSpace(ZZ, n)43M = [ [0 for _ in range(n)] for _ in range(n) ]4445previous_set = Set([])4647for col in range(n-1, -1, -1):48s = Set( comps[col] )49for x in s - previous_set:50M[x-1][col] = 15152for x in previous_set - s:53M[x-1][col] = -15455previous_set = s5657return MS(M)5859def AlternatingSignMatrices(n):60r"""61Returns the combinatorial class of alternating sign matrices of62size n.6364EXAMPLES::6566sage: a2 = AlternatingSignMatrices(2); a267Alternating sign matrices of size 268sage: for a in a2: print a, "-\n"69[0 1]70[1 0]71-72[1 0]73[0 1]74-75"""76return AlternatingSignMatrices_n(n)7778class AlternatingSignMatrices_n(CombinatorialClass):79def __init__(self, n):80"""81TESTS::8283sage: a2 = AlternatingSignMatrices(2); a284Alternating sign matrices of size 285sage: a2 == loads(dumps(a2))86True87"""88self.n = n8990def __repr__(self):91"""92TESTS::9394sage: repr(AlternatingSignMatrices(2))95'Alternating sign matrices of size 2'96"""97return "Alternating sign matrices of size %s"%self.n9899def cardinality(self):100"""101TESTS::102103sage: [ AlternatingSignMatrices(n).cardinality() for n in range(0, 11)]104[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]105106::107108sage: asms = [ AlternatingSignMatrices(n) for n in range(6) ]109sage: all( [ asm.cardinality() == len(asm.list()) for asm in asms] )110True111"""112return prod( [ factorial(3*k+1)/factorial(self.n+k) for k in range(self.n)] )113114def __iter__(self):115"""116TESTS::117118sage: AlternatingSignMatrices(0).list() # indirect doctest119[[]]120sage: AlternatingSignMatrices(1).list() # indirect doctest121[[1]]122sage: map(list, AlternatingSignMatrices(2).list()) # indirect doctest123[[(0, 1), (1, 0)], [(1, 0), (0, 1)]]124sage: map(list, AlternatingSignMatrices(3).list()) # indirect doctest125[[(0, 0, 1), (0, 1, 0), (1, 0, 0)],126[(0, 1, 0), (0, 0, 1), (1, 0, 0)],127[(0, 0, 1), (1, 0, 0), (0, 1, 0)],128[(0, 1, 0), (1, -1, 1), (0, 1, 0)],129[(0, 1, 0), (1, 0, 0), (0, 0, 1)],130[(1, 0, 0), (0, 0, 1), (0, 1, 0)],131[(1, 0, 0), (0, 1, 0), (0, 0, 1)]]132"""133for z in ContreTableaux(self.n):134yield from_contre_tableau(z)135136137def ContreTableaux(n):138"""139Returns the combinatorial class of contre tableaux of size n.140141EXAMPLES::142143sage: ct4 = ContreTableaux(4); ct4144Contre tableaux of size 4145sage: ct4.cardinality()14642147sage: ct4.first()148[[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]149sage: ct4.last()150[[1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]151sage: ct4.random_element()152[[1, 2, 3, 4], [1, 2, 3], [1, 3], [3]]153"""154return ContreTableaux_n(n)155156class ContreTableaux_n(CombinatorialClass):157def __init__(self, n):158"""159TESTS::160161sage: ct2 = ContreTableaux(2); ct2162Contre tableaux of size 2163sage: ct2 == loads(dumps(ct2))164True165"""166self.n = n167168def __repr__(self):169"""170TESTS::171172sage: repr(ContreTableaux(2))173'Contre tableaux of size 2'174"""175return "Contre tableaux of size %s"%self.n176177def cardinality(self):178"""179TESTS::180181sage: [ ContreTableaux(n).cardinality() for n in range(0, 11)]182[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]183"""184return prod( [ factorial(3*k+1)/factorial(self.n+k) for k in range(self.n)] )185186def _iterator_rec(self, i):187"""188TESTS::189190sage: c = ContreTableaux(2)191sage: list(c._iterator_rec(0))192[[]]193sage: list(c._iterator_rec(1))194[[[1, 2]]]195sage: list(c._iterator_rec(2))196[[[1, 2], [1]], [[1, 2], [2]]]197"""198if i == 0:199yield []200elif i == 1:201yield [range(1, self.n+1)]202else:203for columns in self._iterator_rec(i-1):204previous_column = columns[-1]205for column in _next_column_iterator(previous_column, len(previous_column)-1):206yield columns + [ column ]207208def __iter__(self):209"""210TESTS::211212sage: ContreTableaux(0).list() #indirect test213[[]]214sage: ContreTableaux(1).list() #indirect test215[[[1]]]216sage: ContreTableaux(2).list() #indirect test217[[[1, 2], [1]], [[1, 2], [2]]]218sage: ContreTableaux(3).list() #indirect test219[[[1, 2, 3], [1, 2], [1]],220[[1, 2, 3], [1, 2], [2]],221[[1, 2, 3], [1, 3], [1]],222[[1, 2, 3], [1, 3], [2]],223[[1, 2, 3], [1, 3], [3]],224[[1, 2, 3], [2, 3], [2]],225[[1, 2, 3], [2, 3], [3]]]226"""227228for z in self._iterator_rec(self.n):229yield z230231232233def _next_column_iterator(previous_column, height, i = None):234"""235Returns a generator for all columns of height height properly236filled from row 1 to i237238TESTS::239240sage: import sage.combinat.alternating_sign_matrix as asm241sage: list(asm._next_column_iterator([1], 0))242[[]]243sage: list(asm._next_column_iterator([1,5],1))244[[1], [2], [3], [4], [5]]245sage: list(asm._next_column_iterator([1,4,5],2))246[[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]247"""248if i is None:249i = height250if i == 0:251yield [-1]*height252else:253for column in _next_column_iterator(previous_column, height, i-1):254min_value = previous_column[i-1]255if i > 1:256min_value = max(min_value, column[i-2]+1)257for value in range(min_value, previous_column[i]+1):258c = copy.copy(column)259c[i-1] = value260yield c261262def _previous_column_iterator(column, height, max_value):263"""264TESTS::265266sage: import sage.combinat.alternating_sign_matrix as asm267sage: list(asm._previous_column_iterator([2,3], 3, 4))268[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]269"""270new_column = [1] + column + [ max_value ] * (height - len(column))271return _next_column_iterator(new_column, height)272273def TruncatedStaircases(n, last_column):274"""275Returns the combinatorial class of truncated staircases of size n276with last column last_column.277278EXAMPLES::279280sage: t4 = TruncatedStaircases(4, [2,3]); t4281Truncated staircases of size 4 with last column [2, 3]282sage: t4.cardinality()2834284sage: t4.first()285[[4, 3, 2, 1], [3, 2, 1], [3, 2]]286sage: t4.list()287[[[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]]]288"""289return TruncatedStaircases_nlastcolumn(n, last_column)290291class TruncatedStaircases_nlastcolumn(CombinatorialClass):292def __init__(self, n, last_column):293"""294TESTS::295296sage: t4 = TruncatedStaircases(4, [2,3]); t4297Truncated staircases of size 4 with last column [2, 3]298sage: t4 == loads(dumps(t4))299True300"""301self.n = n302self.last_column = last_column303304def __repr__(self):305"""306TESTS::307308sage: repr(TruncatedStaircases(4, [2,3]))309'Truncated staircases of size 4 with last column [2, 3]'310"""311return "Truncated staircases of size %s with last column %s"%(self.n, self.last_column)312313def _iterator_rec(self, i):314"""315TESTS::316317sage: t = TruncatedStaircases(3, [2,3])318sage: list(t._iterator_rec(1))319[]320sage: list(t._iterator_rec(2))321[[[2, 3]]]322sage: list(t._iterator_rec(3))323[[[1, 2, 3], [2, 3]]]324"""325if i < len(self.last_column):326return327elif i == len(self.last_column):328yield [self.last_column]329else:330for columns in self._iterator_rec(i-1):331previous_column = columns[0]332for column in _previous_column_iterator(previous_column, len(previous_column)+1, self.n):333yield [column] + columns334335def __iter__(self):336"""337EXAMPLES:::338339sage: TruncatedStaircases(4, [2,3]).list() #indirect test340[[[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]]]341"""342for z in self._iterator_rec(self.n):343yield map(lambda x: list(reversed(x)), z)344345346347348