# Ticket #15350: trac_15350-partitions-et-al-dg.patch

File trac_15350-partitions-et-al-dg.patch, 57.0 KB (added by Darij Grinberg, 9 years ago)

updated: one typo in docstring fixed

• ## sage/combinat/partition.py

# HG changeset patch
# User darij grinberg <darijgrinberg@gmail.com>
# Date 1383465089 25200
# Node ID a9e302f1751bb3fbec1066e784ece7bf502c730f
# Parent  8f48ebf71e082817f941548c11276c5d76a80096
trac #15350: various improvements to partitions and related files

diff --git a/sage/combinat/partition.py b/sage/combinat/partition.py
 a r""" Partitions A partition p of a nonnegative integer n is at A partition p of a nonnegative integer n is a non-increasing list of positive integers (the *parts* of the partition) with total sum n. For display options, see :obj:Partition its conjugate partition by \lambda^{\prime}. For more on conjugate partitions, see :meth:Partition.conjugate(). - The comparisons on partitions uses lexicographic order. - The comparisons on partitions use lexicographic order. .. NOTE:: AUTHORS: EXAMPLES: There are 5 partitions of the integer 4:: There are 5 partitions of the integer 4:: sage: Partitions(4).cardinality() 5 When we are at the last partition, Non sage: Partitions(4).next([1,1,1,1]) is None True We can use iter to get an object which iterates over the partitions one by one to save memory.  Note that when we do something like We can use iter to get an object which iterates over the partitions one by one to save memory.  Note that when we do something like for part in Partitions(4) this iterator is used in the background:: sage: g = iter(Partitions(4)) by one to save memory. Note that when w [2, 1, 1] [1, 1, 1, 1] We can add constraints to to the type of partitions we want. For example, to get all of the partitions of 4 of length 2, we'd do the We can add constraints to the type of partitions we want. For example, to get all of the partitions of 4 of length 2, we'd do the following:: sage: Partitions(4, length=2).list() [[3, 1], [2, 2]] Here is the list of partitions of length at least 2 and the list of ones with length at most 2:: Here is the list of partitions of length at least 2 and the list of ones with length at most 2:: sage: Partitions(4, min_length=2).list() [[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] ones with length at most 2:: The options min_part and max_part can be used to set constraints on the sizes of all parts. Using max_part, we can select partitions having only 'small' entries. The following is the list of the partitions of 4 with parts at most 2:: of the partitions of 4 with parts at most 2:: sage: Partitions(4, max_part=2).list() [[2, 2], [2, 1, 1], [1, 1, 1, 1]] The min_part options is complementary to max_part and selects partitions having only 'large' parts. Here is the list of all partitions of 4 with each part at least 2:: partitions of 4 with each part at least 2:: sage: Partitions(4, min_part=2).list() [[4], [2, 2]] The options inner and outer can be used to set part-by-part constraints. This is the list of partitions of 4 with [3, 1, 1] as an outer bound:: constraints. This is the list of partitions of 4 with [3, 1, 1] as an outer bound (that is, partitions of 4 contained in the partition [3, 1, 1]):: sage: Partitions(4, outer=[3,1,1]).list() [[3, 1], [2, 1, 1]] outer sets max_length to the length of its argument. Moreover, the parts of outer may be infinite to clear constraints on specific parts. Here is the list of the partitions of 4 of length at most 3 such that the second and third part are 1 when they exist:: parts of outer may be infinite to clear constraints on specific parts. Here is the list of the partitions of 4 of length at most 3 such that the second and third part are 1 when they exist:: sage: Partitions(4, outer=[oo,1,1]).list() [[4], [3, 1], [2, 1, 1]] Finally, here are the partitions of 4 with [1,1,1] as an inner bound. Note that inner sets min_length to the length of its argument:: Finally, here are the partitions of 4 with [1,1,1] as an inner bound (i. e., the partitions of 4 containing the partition [1,1,1]). Note that inner sets min_length to the length of its argument:: sage: Partitions(4, inner=[1,1,1]).list() [[2, 1, 1], [1, 1, 1, 1]] argument:: The options min_slope and max_slope can be used to set constraints on the slope, that is on the difference p[i+1]-p[i] of two consecutive parts. Here is the list of the strictly decreasing partitions of 4:: partitions of 4:: sage: Partitions(4, max_slope=-1).list() [[4], [3, 1]] The constraints can be combined together in all reasonable ways. Here are all the partitions of 11 of length between 2 and 4 such that the difference between two consecutive parts is between -3 and -1:: Here are all the partitions of 11 of length between 2 and 4 such that the difference between two consecutive parts is between -3 and -1:: sage: Partitions(11,min_slope=-3,max_slope=-1,min_length=2,max_length=4).list() [[7, 4], [6, 5], [6, 4, 1], [6, 3, 2], [5, 4, 2], [5, 3, 2, 1]] If we create a partition with extra zero sage: Partition([4,1,0,0]) [4, 1] The idea of a partition being followed by infinitely many parts of size 0 is consistent with the get_part method:: sage: Partition([0]) [] sage: Partition([0,0]) [] The idea of a partition being followed by infinitely many parts of size 0 is consistent with the get_part method:: sage: p = Partition([5, 2]) sage: p.get_part(0) consistent with the get_part method: sage: p.get_part(10) 0 We can go back and forth between the exponential notations of a partition. The exponential notation can be padded with extra zeros:: We can go back and forth between the standard and the exponential notations of a partition. The exponential notation can be padded with extra zeros:: sage: Partition([6,4,4,2,1]).to_exp() [1, 1, 0, 2, 0, 1] zeros:: sage: Partition([6,4,4,2,1]).to_exp(10) [1, 1, 0, 2, 0, 1, 0, 0, 0, 0] We can get the coordinates of the corners of a partition:: We can get the (zero-based!) coordinates of the corners of a partition:: sage: Partition([4,3,1]).corners() [(0, 3), (1, 2), (2, 0)] class Partition(CombinatorialObject, Ele def _latex_young_diagram(self): r""" LaTeX output as a young diagram. LaTeX output as a Young diagram. EXAMPLES:: class Partition(CombinatorialObject, Ele r""" Prints the Ferrers diagram. See :meth:ferrers_diagram for more on the ferrers diagram. See :meth:ferrers_diagram for more on the Ferrers diagram. EXAMPLES:: class Partition(CombinatorialObject, Ele with cycle type self (thus describes the powermap of symmetric groups). Wraps GAP's PowerPartition. Equivalent to GAP's PowerPartition. EXAMPLES:: class Partition(CombinatorialObject, Ele else: yield Partition(p[:-1] + [ p[-1] - 1 ]) def down_list(self): """ Return a list of the partitions that can be obtained from self class Partition(CombinatorialObject, Ele return (a,b) def frobenius_rank(self): """ Return the Frobenius rank of the partition. The Frobenius rank is the number of cells on the main diagonal. r""" Return the Frobenius rank of the partition self. The Frobenius rank of a partition \lambda = (\lambda_1, \lambda_2, \lambda_3, \cdots) is defined to be the largest i such that \lambda_i \geq i. In other words, it is the number of cells on the main diagonal of \lambda. In yet other words, it is the size of the largest square fitting into the Young diagram of \lambda. EXAMPLES:: class Partition(CombinatorialObject, Ele 1 sage: Partition([2,2,1,1,1,1]).frobenius_rank() 2 """ mu = self if mu.is_empty(): return 0 if len(mu) <= mu[0]: return len(filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(mu)])) else: muconj = mu.conjugate() return len(filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(muconj)])) sage: Partition([3,2]).frobenius_rank() 2 sage: Partition([3,2,2]).frobenius_rank() 2 sage: Partition([8,4,4,4,4]).frobenius_rank() 4 sage: Partition([8,4,1]).frobenius_rank() 2 sage: Partition([3,3,1]).frobenius_rank() 2 """ for i, x in enumerate(self): if x <= i: return i return len(self) def beta_numbers(self, length=None): """ class Partition(CombinatorialObject, Ele [6, 4, 2] sage: Partition([4,3,2]).beta_numbers(5) [8, 6, 4, 1, 0] """ if length==None: length=self.length() elif length self.length(): beta.extend( range(length-self.length()-1,-1,-1) ) sage: Partition([]).beta_numbers() [] sage: Partition([]).beta_numbers(3) [2, 1, 0] sage: Partition([6,4,1,1]).beta_numbers() [9, 6, 2, 1] sage: Partition([6,4,1,1]).beta_numbers(6) [11, 8, 4, 3, 1, 0] sage: Partition([1,1,1]).beta_numbers() [3, 2, 1] sage: Partition([1,1,1]).beta_numbers(4) [4, 3, 2, 0] """ true_length = len(self) if length == None: length = true_length elif length < true_length: raise ValueError("length must be at least the length of the partition") beta = [l + length - i - 1 for (i, l) in enumerate(self)] if length > true_length: beta.extend( range(length-true_length-1,-1,-1) ) return beta def crank(self): r""" Return the Dyson crank of self. The Dyson crank of a partition \lambda is defined as follows: If \lambda contains at least one 1, then the crank is \mu(\lambda) - \omega(\lambda), where \omega(\lambda) is the number of 1s in \lambda, and \mu(\lambda) is the number of parts of \lambda larger than \omega(\lambda). If \lambda contains no 1, then the crank is simply the largest part of \lambda. REFERENCES: .. [AG1988] George E. Andrews, F. G. Garvan, *Dyson's crank of a partition*. Bull. Amer. Math. Soc. (N.S.) Volume 18, Number 2 (1988), 167-171. http://projecteuclid.org/euclid.bams/1183554533 EXAMPLES:: sage: Partition([]).crank() 0 sage: Partition([3,2,2]).crank() 3 sage: Partition([5,4,2,1,1]).crank() 0 sage: Partition([1,1,1]).crank() -3 sage: Partition([6,4,4,3]).crank() 6 sage: Partition([6,3,3,1,1]).crank() 1 sage: Partition([6]).crank() 6 sage: Partition([5,1]).crank() 0 sage: Partition([4,2]).crank() 4 sage: Partition([4,1,1]).crank() -1 sage: Partition([3,3]).crank() 3 sage: Partition([3,2,1]).crank() 1 sage: Partition([3,1,1,1]).crank() -3 sage: Partition([2,2,2]).crank() 2 sage: Partition([2,2,1,1]).crank() -2 sage: Partition([2,1,1,1,1]).crank() -4 sage: Partition([1,1,1,1,1,1]).crank() -6 """ l = len(self) if l == 0: return 0 if self[-1] > 1: return self[0] ind_1 = self.index(1) w = l - ind_1      # w is omega(self). m = len([x for x in self if x > w]) return m - w def larger_lex(self, rhs): """ Return True if self is larger than rhs in lexicographic class Partition(CombinatorialObject, Ele """ res = 1 for (i,j) in self.cells(): res *= (a - (i-1)/alpha+j-1) res *= (a - (i-1)/alpha + j-1) return res def get_part(self, i, default=Integer(0)): class Partition(CombinatorialObject, Ele http://www.sciencedirect.com/science/article/pii/S0195669801905414 """ # Check for valid input if len(self) > 0 and len(self) + self._list[0] - 1 >= n: # -1 since we double count the (0,0) cell if len(self) > 0 and len(self) + self._list[0] > n: # >, not >=, since we double count the (0,0) cell raise ValueError("the hook length must be less than n") ret = self # Arbitrary exp class Partition(CombinatorialObject, Ele def upper_hook(self, i, j, alpha): r""" Return the upper hook length of the cell (i,j) in self. When alpha = 1, this is just the normal hook length. Return the upper hook length of the cell (i,j) in self. When alpha = 1, this is just the normal hook length. The upper hook length of a cell (i,j) in a partition \kappa is defined by .. MATH:: h_*^\kappa(i,j) = \kappa_j^\prime-i+\alpha(\kappa_i - j+1). h^*_\kappa(i,j) = \kappa^\prime_j - i + \alpha(\kappa_i - j + 1). EXAMPLES:: class Partition(CombinatorialObject, Ele """ p = self conj = self.conjugate() return conj[j]-(i+1)+alpha*(p[i]-(j+1)+1) return conj[j] - (i+1) + alpha*(p[i]-j) def upper_hook_lengths(self, alpha): r""" class Partition(CombinatorialObject, Ele .. MATH:: h_*^\kappa(i,j) = \kappa_j^\prime-i+1+\alpha(\kappa_i - j). h^*_\kappa(i,j) = \kappa^\prime_j - i + \alpha(\kappa_i - j + 1). EXAMPLES:: class Partition(CombinatorialObject, Ele """ p = self conj = p.conjugate() return [[conj[j]-(i+1)+alpha*(p[i]-(j+1)+1) for j in range(p[i])] for i in range(len(p))] return [[conj[j] - (i+1) + alpha*(p[i]-j) for j in range(p[i])] for i in range(len(p))] def lower_hook(self, i, j, alpha): r""" Return the lower hook length of the cell (i,j) in self. When alpha = 1, this is just the normal hook length. Return the lower hook length of the cell (i,j) in self. When alpha = 1, this is just the normal hook length. The lower hook length of a cell (i,j) in a partition \kappa is defined by .. MATH:: h_*^\kappa(i,j) = \kappa_j^\prime-i+1+\alpha(\kappa_i - j). h_*^\kappa(i,j) = \kappa^\prime_j - i + 1 + \alpha(\kappa_i - j). EXAMPLES:: class Partition(CombinatorialObject, Ele """ p = self conj = self.conjugate() return conj[j]-(i+1)+1+alpha*(p[i]-(j+1)) return conj[j] - i + alpha*(p[i] - (j+1)) def lower_hook_lengths(self, alpha): r""" class Partition(CombinatorialObject, Ele .. MATH:: h_\kappa^*(i,j) = \kappa_j^\prime-i+\alpha(\kappa_i - j + 1). h_*^\kappa(i,j) = \kappa^\prime_j - i + 1 + \alpha(\kappa_i - j). EXAMPLES:: class Partition(CombinatorialObject, Ele """ p = self conj = p.conjugate() return [[conj[j]-(i+1)+1+alpha*(p[i]-(j+1)) for j in range(p[i])] for i in range(len(p))] return [[conj[j] - i + alpha*(p[i]-(j+1)) for j in range(p[i])] for i in range(len(p))] def weighted_size(self): class Partition(CombinatorialObject, Ele .. MATH:: \sum_i i * \lambda_i. \sum_i i \cdot \lambda_i, where \lambda = (\lambda_0, \lambda_1, \lambda_2, \cdots ). This also the sum of the leg length of every cell in \lambda, or class Partition(CombinatorialObject, Ele \sum_i \binom{\lambda^{\prime}_i}{2} where \lambda^{\prime} the conjugate partition of \lambda. where \lambda^{\prime} is the conjugate partition of \lambda. EXAMPLES:: class Partition(CombinatorialObject, Ele 9 sage: Partition([5,2]).weighted_size() 2 sage: Partition([]).weighted_size() 0 """ p = self return sum([i*p[i] for i in range(len(p))]) class Partition(CombinatorialObject, Ele Return the evaluation of self. The **commutative evaluation**, often shortened to **evaluation**, of a word (we think of a partition as a word in \{0, 1, 2, \ldots\}) a word (we think of a partition as a word in \{1, 2, 3, \ldots\}) is its image in the free commutative monoid. In other words, this counts how many occurrances there are of each letter. this counts how many occurrences there are of each letter. This is also is known as **Parikh vector** and **abelianization** and has the same output as :meth:to_exp(). class Partition(CombinatorialObject, Ele 8 sage: Partition([2,2,2]).centralizer_size() 48 sage: Partition([2,2,1]).centralizer_size(q=2, t=3) 9/16 sage: Partition([]).centralizer_size() 1 sage: Partition([]).centralizer_size(q=2, t=4) 1 """ p = self a = p.to_exp() size = prod([(i+1)**a[i]*factorial(a[i]) for i in range(len(a))]) size *= prod( [ (1-q**p[i])/(1-t**p[i]) for i in range(len(p)) ] ) size *= prod( [ (1-q**j)/(1-t**j) for j in p ] ) return size class Partition(CombinatorialObject, Ele self. This method returns 1^{j_1}j_1! \cdots n^{j_n}j_n! where j_k is the number of parts in self equal to k. j_k is the number of parts in self equal to k. The number of permutations having self as a cycle type is given by .. MATH:: \frac{n!}{1^{j_1}j_1! \cdots n^{j_n}j_n!} . \frac{n!}{1^{j_1}j_1! \cdots n^{j_n}j_n!} (where n is the size of self). EXAMPLES:: class Partition(CombinatorialObject, Ele For consistency with partition tuples there is also an optional multicharge argument which is an offset to the usual content. By setting the multicharge equal to the 0-element the ring \ZZ/e\ZZ the corresponding e-residue will be returned. This is the content modulo e. setting the multicharge equal to the 0-element of the ring \ZZ/e\ZZ, the corresponding e-residue will be returned. This is the content modulo e. The content (and residue) do not strictly depend on the partition, however, this method is included because it is often useful in the class Partition(CombinatorialObject, Ele def zero_one_sequence(self): r""" Computes the finite 0-1 sequence of the partition. Compute the finite 0-1 sequence of the partition. The full 0-1 sequence is the sequence (infinite in both directions) indicating the steps taken when following the class Partition(CombinatorialObject, Ele The finite 0-1 sequence is obtained from the full 0-1 sequence by omitting all heading 0's and trailing 1's. The output sequence is finite, starts with a 1 and ends with a 0 (unless it is empty, for the empty partition). 0 (unless it is empty, for the empty partition). Its length is the sum of the first part of the partition with the length of the partition. REFERENCES: class Partition(CombinatorialObject, Ele sage: all(Partitions().from_zero_one(mu.zero_one_sequence()) == mu for n in range(10) for mu in Partitions(n)) True """ tmp = [self.get_part(i)-i for i in range(len(self))] tmp = [self[i]-i for i in range(len(self))] return ([Integer(not (i in tmp)) for i in range(-len(self)+1,self.get_part(0)+1)]) def core(self, length): """ Return the core of the partition -- in the literature the core is commonly referred to as the k-core, p-core, r-core, ... . The construction of the core can be visualized by repeatedly removing border strips of size r from self until this is no longer possible. The remaining partition is the core. r""" Return the length-core of the partition -- in the literature the core is commonly referred to as the k-core, p-core, r-core, ... . The r-core of a partition \lambda can be obtained by repeatedly removing rim hooks of size r from (the Young diagram of) \lambda until this is no longer possible. The remaining partition is the core. EXAMPLES:: class Partition(CombinatorialObject, Ele return Partition(filter(lambda x: x != 0, part)) def quotient(self, length): """ r""" Return the quotient of the partition  -- in the literature the core is commonly referred to as the k-core, p-core, r-core, ... . The quotient is a list of r partitions, constructed in the following way. Label each cell in p with its content, modulo r. Let R_i be the set of rows ending in a cell labelled i, and C_i be the set of columns ending in a cell labelled i. Then the j-th component of the quotient of p is the partition defined by intersecting R_j with C_j+1. quotient is commonly referred to as the k-quotient, p-quotient, r-quotient, ... . The r-quotient of a partition \lambda is a list of r partitions (labelled from 0 to r-1), constructed in the following way. Label each cell in the Young diagram of \lambda with its content modulo r. Let R_i be the set of rows ending in a cell labelled i, and C_i be the set of columns ending in a cell labelled i. Then the j-th component of the quotient of \lambda is the partition defined by intersecting R_j with C_{j+1}. (See Theorem 2.7.37 in [JamesKerber]_.) REFERENCES: .. [JamesKerber] Gordon James, Adalbert Kerber, *The Representation Theory of the Symmetric Group*, Encyclopedia of Mathematics and its Applications, vol. 16, Addison-Wesley 1981. EXAMPLES:: class Partition(CombinatorialObject, Ele ([3, 3], [2, 2, 1], [], [3, 3, 3], [1]) sage: all(p == Partition(core=p.core(k), quotient=p.quotient(k)) ...       for i in range(10) for p in Partitions(i) ...       for k in range(1,6)) ....:     for i in range(10) for p in Partitions(i) ....:     for k in range(1,6)) True """ p = self class Partition(CombinatorialObject, Ele remainder = len(p) % length part = p[:] + [0]*(length-remainder) #Add the canonical vector to the partition part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)] result = [None]*length class Partition(CombinatorialObject, Ele be checked by trying to remove border strips of size k from self. If this is not possible, then self is a k-core. A partition is said to be a *k-core* if it has no hooks of length k. Equivalently, a partition is said to be a k-core if it is its own k-core (where the latter is defined as in :meth:core). EXAMPLES:: sage: p = Partition([12,8,5,5,2,2,1]) class Partition(CombinatorialObject, Ele def k_interior(self, k): r""" Return the partition consisting of the cells of self, whose hook Return the partition consisting of the cells of self whose hook lengths are greater than k. EXAMPLES:: class Partition(CombinatorialObject, Ele def add_cell(self, i, j = None): r""" Return a partition corresponding to self with a cell added in row i. This does not change self. Return a partition corresponding to self with a cell added in row i. (This does not change self.) EXAMPLES:: class Partition(CombinatorialObject, Ele def remove_cell(self, i, j = None): """ Return the partition obtained by removing a cell at the end of row i. i of self. EXAMPLES:: class Partition(CombinatorialObject, Ele iv[t] -= 1 j += 1 j = sum(shelf[:t+1]) res.append(Partition([i for i in tmp if i != 0]).conjugate()) res.append(Partition([u for u in tmp if u != 0]).conjugate()) return res def remove_horizontal_border_strip(self, k): class Partition(CombinatorialObject, Ele .. MATH:: \frac{ 1 - q^a * t^{\ell + 1} }{ 1 - q^{a + 1} * t^{\ell} } \frac{ 1 - q^a \cdot t^{\ell + 1} }{ 1 - q^{a + 1} \cdot t^{\ell} } where a is the arm length of c and \ell is the leg length of c. The coordinates i and j of the cell are understood to be 0-based, so that (0, 0) is the northwesternmost cell (in English notation). EXAMPLES:: sage: Partition([3,2,1]).arms_legs_coeff(1,1) class Partition(CombinatorialObject, Ele res /= (1-q**(self.arm_length(i,j)+1) * t**self.leg_length(i,j)) return res else: return ZZ(1) return ZZ.one() def atom(self): """ class Partition(CombinatorialObject, Ele def jacobi_trudi(self): """ Return the Jacobi-Trudi polynomial of self thought of as a skew Return the Jacobi-Trudi matrix of self thought of as a skew partition. See :meth:SkewPartition.jacobi_trudi() . class Partition(CombinatorialObject, Ele def character_polynomial(self): r""" Return the character polynomial associated to the partition self. The character polynomial q_\mu is defined by Return the character polynomial associated to the partition self. The character polynomial q_\mu associated to a partition \mu is defined by .. MATH:: class Partition(CombinatorialObject, Ele \frac{ \chi^\mu_\alpha }{1^{a_1}2^{a_2}\cdots k^{a_k}a_1!a_2!\cdots a_k!} \prod_{i=1}^{k} (ix_i-1)^{a_i} where a_i is the multiplicity of i in \alpha. where k is the size of \mu, and a_i is the multiplicity of i in \alpha. It is computed in the following manner: class Partition(CombinatorialObject, Ele REFERENCES: .. [ORV] Olshanski, Regev, Vershik, "Frobenius-Schur functions" .. [ORV] Grigori Olshanski, Amitai Regev, Anatoly Vershik, *Frobenius-Schur functions*, :arxiv:math/0110077v1. Possibly newer version at http://www.wisdom.weizmann.ac.il/~regev/papers/FrobeniusSchurFunctions.ps AUTHORS: Partition_class = deprecated_function_al class Partitions(UniqueRepresentation, Parent): r""" Partitions(n, **kwargs) returns the combinatorial class of integer partitions of n, and subject to the constraints given by the integer partitions of n subject to the constraints given by the keywords. Valid keywords are: starting, ending, min_part, class Partitions(UniqueRepresentation, P k; the slope is the difference between successive parts. - parts_in=S specifies that the partitions have parts in the set S, which can be any sequence of positive integers. S, which can be any sequence of pairwise distinct positive integers. The max_* versions, along with inner and ending, work analogously. class Partitions_n(Partitions): def __contains__(self, x): """ Checks if x is contained in self. TESTS:: Check if x is contained in self. TESTS:: sage: p = Partitions(5) sage: [2,1] in p class Partitions_n(Partitions): True sage: [3,2] in p True sage: [2,3] in p False """ return x in _Partitions and sum(x) == self.n class Partitions_n(Partitions): \sum_{n=0}^{\infty} p_n x^n = \prod_{k=1}^{\infty} \left( \frac{1}{1-x^k} \right). We use Sage to verify that the first several coefficients do instead agree:: indeed agree:: sage: q = PowerSeriesRing(QQ, 'q', default_prec=9).gen() sage: prod([(1-q^k)^(-1) for k in range(1,9)])  ## partial product of class Partitions_n(Partitions): def random_element_uniform(self): """ Return a random partitions of n with uniform probability. Return a random partition of n with uniform probability. EXAMPLES:: class Partitions_n(Partitions): return Partition(res) def random_element_plancherel(self): """ Returns a random partitions of n. r""" Return a random partition of n. EXAMPLES:: class Partitions_parts_in(Partitions): """ Partitions of n with parts in a given set S. This is invoked indirectly when calling Partitions(n, parts_in=parts), where parts is a list of pairwise distinct integers. TESTS:: sage: TestSuite( sage.combinat.partition.Partitions_parts_in(6, parts=[2,1]) ).run() class Partitions_parts_in(Partitions): TESTS: Let's check the consistency of GAP's function and our own algorithm that actually generates the partitions. :: algorithm that actually generates the partitions:: sage: ps = Partitions(15, parts_in=[1,2,3]) sage: ps.cardinality() == len(ps.list()) class Partitions_parts_in(Partitions): def __iter__(self): """ An iterator a list of the partitions of n. An iterator through the partitions of n with all parts belonging to a particular set. EXAMPLES:: class Partitions_ending(Partitions): class PartitionsInBox(Partitions): r""" All partitions with fit in a h \times w box. All partitions which fit in an h \times w box. EXAMPLES:: sage: PartitionsInBox(2,2) class PartitionsInBox(Partitions): sage: PartitionsInBox(2,2).list() [[], [1], [1, 1], [2], [2, 1], [2, 2]] """ def __init__(self, h, w): """ Initialize self. class PartitionsInBox(Partitions): False sage: [2,1,1] in PartitionsInBox(2,2) False sage: [3,1] in PartitionsInBox(3, 2) False sage: [3,1] in PartitionsInBox(2, 3) True """ return x in _Partitions and len(x) <= self.h \ and (len(x) == 0 or x[0] <= self.w) class PartitionsInBox(Partitions): sage: PartitionsInBox(2,2).list() [[], [1], [1, 1], [2], [2, 1], [2, 2]] sage: PartitionsInBox(2,3).list() [[], [1], [1, 1], [2], [2, 1], [2, 2], [3], [3, 1], [3, 2], [3, 3]] TESTS: def number_of_partitions(n, k=None, algo if n < 0: raise ValueError("n (=%s) must be a nonnegative integer"%n) elif n == 0: return ZZ(1) return ZZ.one() if algorithm == 'default': if k is None:
• ## sage/combinat/partition_tuple.py

diff --git a/sage/combinat/partition_tuple.py b/sage/combinat/partition_tuple.py
 a A :class:PartitionTuple is a tuple of n = \lvert \mu \rvert = \lvert \mu^{(1)} \rvert + \lvert \mu^{(2)} \rvert + \cdots + \lvert \mu^{(k)} \rvert then \mu is an k-partition of n. then \mu is a k-partition of n. In representation theory partition tuples arise as the natural indexing set for the ordinary irreducible representations of: class PartitionTuple(CombinatorialObject n = \lvert \mu \rvert = \lvert \mu^{(1)} \rvert + \lvert \mu^{(2)} \rvert + \cdots + \lvert \mu^{(k)} \rvert then \mu is an k-partition of n. then \mu is a k-partition of n. In representation theory PartitionTuples arise as the natural indexing set for the ordinary irreducible representations of: class PartitionTuple(CombinatorialObject def _latex_young_diagram(self): """ LaTeX output as a young diagram. LaTeX output as a Young diagram. EXAMPLES:: class PartitionTuple(CombinatorialObject REFERENCE: .. [KMR] A. Kleshchev, A. Mathas, and A. Ram, Universal Specht modules for cyclotomic Hecke algebras, Proc. LMS (to appear). .. [KMR] A. Kleshchev, A. Mathas, and A. Ram, *Universal Specht modules for cyclotomic Hecke algebras*, Proc. London Math. Soc. (2012) 105 (6): 1245-1289. :arxiv:1102.3519v1 """ (comp,row,col)=cell
• ## sage/combinat/sf/classical.py

diff --git a/sage/combinat/sf/classical.py b/sage/combinat/sf/classical.py
 a class SymmetricFunctionAlgebra_classical # Partitions # ############## if x in sage.combinat.partition.Partitions(): return eclass(self, {sage.combinat.partition.Partition(filter(lambda x: x!=0, x)):R(1)}) return eclass(self, {sage.combinat.partition.Partition(filter(lambda x: x!=0, x)): R.one()}) # Todo: discard all of this which is taken care by Sage's coercion # (up to changes of base ring) class SymmetricFunctionAlgebra_classical if xm: return self._from_dict(t(xm)._monomial_coefficients, coerce=True) else: return self(0) return self.zero() else: f = lambda part: self._from_dict(t( {part:Integer(1)} )._monomial_coefficients) f = lambda part: self._from_dict(t( {part: ZZ.one()} )._monomial_coefficients) return self._apply_module_endomorphism(x, f) class SymmetricFunctionAlgebra_classical elif isinstance(x, llt.LLT_generic.Element): P = x.parent() BR = self.base_ring() zero = BR(0) zero = BR.zero() PBR = P.base_ring() if not BR.has_coerce_map_from(PBR): raise TypeError, "no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)"%(PBR, self.base_ring())
• ## sage/combinat/sf/dual.py

diff --git a/sage/combinat/sf/dual.py b/sage/combinat/sf/dual.py
 a class SymmetricFunctionAlgebra_dual(clas self._inverse_transition_matrices = {} scalar_target = scalar(sage.combinat.partition.Partition([1])).parent() scalar_target = (scalar_target(1)*dual_basis.base_ring()(1)).parent() scalar_target = (scalar_target.one()*dual_basis.base_ring().one()).parent() self._sym = sage.combinat.sf.sf.SymmetricFunctions(scalar_target) self._p = self._sym.power() class SymmetricFunctionAlgebra_dual(clas [-1  1] """ base_ring = self.base_ring() zero = base_ring(0) zero = base_ring.zero() # Handle the n == 0 and n == 1 cases separately if n == 0 or n == 1: part = sage.combinat.partition.Partition([1]*n) self._to_self_cache[ part ] = { part: base_ring(1) } self._from_self_cache[ part ] = { part: base_ring(1) } self._to_self_cache[ part ] = { part: base_ring.one() } self._from_self_cache[ part ] = { part: base_ring.one() } self._transition_matrices[n] = matrix(base_ring, [[1]]) self._inverse_transition_matrices[n] = matrix(base_ring, [[1]]) return class SymmetricFunctionAlgebra_dual(clas parent = A base_ring = parent.base_ring() zero = base_ring(0) zero = base_ring.zero() if dual is None: # We need to compute the dual
• ## sage/combinat/sf/hall_littlewood.py

diff --git a/sage/combinat/sf/hall_littlewood.py b/sage/combinat/sf/hall_littlewood.py
 a class HallLittlewood_p(HallLittlewood_ge """ from sage.combinat.sf.kfpoly import schur_to_hl t = QQt.gen() zero = self.base_ring()(0) zero = self.base_ring().zero() res_dict = schur_to_hl(part, t) f = lambda part2: res_dict.get(part2,zero) return f class HallLittlewood_qp(HallLittlewood_g t = QQt.gen() if part == []: return lambda part2: QQt(1) return lambda part2: QQt.one() res = hall_littlewood(part) # call to symmetrica (returns in variable x) f = lambda part2: res.coefficient(part2).subs(x=t)
• ## sage/combinat/sf/jack.py

diff --git a/sage/combinat/sf/jack.py b/sage/combinat/sf/jack.py
 a implementation in sage. REFERENCES: .. [Jack1970] A class of symmetric functions with a parameter, Proc. R Soc. Edinburgh (A), 69, 1-18. .. [Jack1970] H. Jack, *A class of symmetric functions with a parameter*, Proc. R. Soc. Edinburgh (A), 69, 1-18. .. [Ma1995] I. G. Macdonald, Symmetric functions and Hall polynomials, second ed., .. [Ma1995] I. G. Macdonald, *Symmetric functions and Hall polynomials*, second ed., The Clarendon Press, Oxford University Press, New York, 1995, With contributions by A. Zelevinsky, Oxford Science Publications. """
• ## sage/combinat/sf/k_dual.py

diff --git a/sage/combinat/sf/k_dual.py b/sage/combinat/sf/k_dual.py
 a class kMonomial(KBoundedQuotientBasis): return self([]) if la[0] <= self.k: return self(la) if self.t==1: return self(0) if self.t == 1: return self.zero() else: kHLP = self._kBoundedRing.kHallLittlewoodP() return self(kHLP._m_to_kHLP_on_basis(la)) class kbounded_HallLittlewoodP(KBoundedQ sage: kHLP(mk([2,1])^2) 4*HLP3[2, 2, 1, 1] + 6*HLP3[2, 2, 2] + 2*HLP3[3, 2, 1] + 2*HLP3[3, 3] """ if self.t==1: if self.t == 1: if la in self._kbounded_partitions: return self(la) else: return self(0) return self.zero() else: HLP = self._kBoundedRing._quotient_basis m = self._kBoundedRing._sym.m() class kbounded_HallLittlewoodP(KBoundedQ """ mk = self._kBoundedRing.km() if la not in self._kbounded_partitions: return mk(0) return mk.zero() if self.t==1: return mk(la) else:
• ## sage/combinat/sf/kschur.py

diff --git a/sage/combinat/sf/kschur.py b/sage/combinat/sf/kschur.py
 a class kSchurFunctions_generic(sfa.Symmet """ orig = el P = el.parent() zero = self.base_ring()(0) zero = self.base_ring().zero() out = {} while not el.is_zero(): l = el.support() class kSchurFunctions_t(kSchurFunctions_ pass if x in sage.combinat.partition.Partitions(): if len(x) > 0 and max(x) > self.k: return self(0) return self.zero() x = sage.combinat.partition.Partition(x) return self._from_dict({x:self.base_ring()(1)}) return self._from_dict({x:self.base_ring().one()}) def _s_cache(self, n): class kSchurFunctions_t(kSchurFunctions_ R = self.base_ring() t = self.t s = self._s zero = s(0) zero = s.zero() if n == 0: p = sage.combinat.partition.Partition([]) self._self_to_s_cache[0] = {p: {p:R(1)}} self._self_to_s_cache[0] = {p: {p:R.one()}} return else: self._self_to_s_cache[n] = {}
• ## sage/combinat/sf/powersum.py

diff --git a/sage/combinat/sf/powersum.py b/sage/combinat/sf/powersum.py
 a class SymmetricFunctionAlgebra_power(mul def coproduct_on_generators(self, i): r""" Returns coproduct on generators for power sums p_i. Return coproduct on generators for power sums p_i (for i > 0). The elements p_i are primitive elements. INPUT: class SymmetricFunctionAlgebra_power(mul sage: p.coproduct_on_generators(2) p[] # p[2] + p[2] # p[] """ def P(k): return Partition([k]) if k else Partition([]) Pi = Partition([i]) P0 = Partition([]) T = self.tensor_square() return T.sum_of_monomials( [(P(i), P(0)), (P(0), P(i))] ) return T.sum_of_monomials( [(Pi, P0), (P0, Pi)] ) def antipode_on_basis(self, partition): r""" Returns the antipode of self[partition]. The antipode on the generator p_i is -p_i and the antipode on p_\mu is (-1)^{length(\mu)} p_\mu. Return the antipode of self[partition]. The antipode on the generator p_i (for i > 0) is -p_i, and the antipode on p_\mu is (-1)^{length(\mu)} p_\mu. INPUT: class SymmetricFunctionAlgebra_power(mul return -self[partition] #This is slightly faster than: return (-1)**len(partition) * self[partition] def bottom_schur_function(self, partition, degree=None): r""" Return the least-degree component of s[partition], where s denotes the Schur basis of the symmetric functions, and the grading is not the usual grading on the symmetric functions but rather the grading which gives every p_i degree 1. This least-degree component has its degree equal to the Frobenius rank of partition, while the degree with respect to the usual grading is still the size of partition. This method requires the base ring to be a (commutative) \QQ-algebra. This restriction is unavoidable, since the least-degree component (in general) has noninteger coefficients in all classical bases of the symmetric functions. The optional keyword degree allows taking any homogeneous component rather than merely the least-degree one. Specifically, if degree is set, then the degree-th component will be returned. REFERENCES: .. [ClSt03] Peter Clifford, Richard P. Stanley, *Bottom Schur functions*. :arxiv:math/0311382v2. EXAMPLES:: sage: Sym = SymmetricFunctions(QQ) sage: p = Sym.p() sage: p.bottom_schur_function([2,2,1]) -1/6*p[3, 2] + 1/4*p[4, 1] sage: p.bottom_schur_function([2,1]) -1/3*p[3] sage: p.bottom_schur_function([3]) 1/3*p[3] sage: p.bottom_schur_function([1,1,1]) 1/3*p[3] sage: p.bottom_schur_function(Partition([1,1,1])) 1/3*p[3] sage: p.bottom_schur_function([2,1], degree=1) -1/3*p[3] sage: p.bottom_schur_function([2,1], degree=2) 0 sage: p.bottom_schur_function([2,1], degree=3) 1/3*p[1, 1, 1] sage: p.bottom_schur_function([2,2,1], degree=3) 1/8*p[2, 2, 1] - 1/6*p[3, 1, 1] """ from sage.combinat.partition import _Partitions s = self.realization_of().schur() partition = _Partitions(partition) if degree is None: degree = partition.frobenius_rank() s_partition = self(s[partition]) return self.sum_of_terms([(p, coeff) for p, coeff in s_partition if len(p) == degree], distinct=True) class Element(classical.SymmetricFunctionAlgebra_classical.Element): def omega(self): r""" class SymmetricFunctionAlgebra_power(mul INPUT: - x -- an power sum symmetric function - x -- a power sum symmetric function - zee -- (default: uses standard zee function) optional input specifying the scalar product on the power sum basis with normalization \langle p_{\mu}, p_{\mu} \rangle = class SymmetricFunctionAlgebra_power(mul """ p = self.parent() if 1 not in part: return p(0) return p.zero() else: return len([i for i in part if i == 1]) * p(part[:-1])
• ## sage/combinat/sf/witt.py

diff --git a/sage/combinat/sf/witt.py b/sage/combinat/sf/witt.py
 a class SymmetricFunctionAlgebra_witt(mult .. MATH:: h_n = \sum_{\lambda \vdash n} w_{\lambda} h_n = \sum_{\lambda \vdash n} w_{\lambda} for all nonnegative integers n, where \lambda \vdash n means that \lambda is a partition of n. class SymmetricFunctionAlgebra_witt(mult """ # Much of this code is adapted from dual.py base_ring = self.base_ring() zero = base_ring(0) zero = base_ring.zero() from sage.combinat.partition import Partition, Partitions_n # Handle the n == 0 case separately if n == 0: part = Partition([]) to_self_cache[ part ] = { part: base_ring(1) } from_self_cache[ part ] = { part: base_ring(1) } to_self_cache[ part ] = { part: base_ring.one() } from_self_cache[ part ] = { part: base_ring.one() } transition_matrices[n] = matrix(base_ring, [[1]]) inverse_transition_matrices[n] = matrix(base_ring, [[1]]) return
• ## sage/combinat/skew_partition.py

diff --git a/sage/combinat/skew_partition.py b/sage/combinat/skew_partition.py
 a is an involution:: sage: SkewPartition([[4,3,1],[2]]).conjugate().conjugate() [4, 3, 1] / [2] The :meth:jacobi_trudy() method computes the Jacobi-Trudi matrix. See The :meth:jacobi_trudi() method computes the Jacobi-Trudi matrix. See [Mac95]_ for a definition and discussion. :: from sage.graphs.digraph import DiGraph from sage.matrix.matrix_space import MatrixSpace from sage.combinat.combinat import CombinatorialObject from sage.combinat.partition import Partitions, PartitionOptions, _Partitions from sage.combinat.partition import PartitionOptions, _Partitions from sage.combinat.tableau import TableauOptions from sage.combinat.composition import Compositions class SkewPartition(CombinatorialObject, icorners += [(nn, 0)] return icorners def frobenius_rank(self): r""" Return the Frobenius rank of the skew partition self. The Frobenius rank of a skew partition \lambda / \mu can be defined in various ways. The quickest one is probably the following: Writing \lambda as (\lambda_1, \lambda_2, \cdots , \lambda_N), and writing \mu as (\mu_1, \mu_2, \cdots , \mu_N), we define the Frobenius rank of \lambda / \mu to be the number of all 1 \leq i \leq N such that .. MATH:: \lambda_i - i \not\in \{ \mu_1 - 1, \mu_2 - 2, \cdots , \mu_N - N \}. In other words, the Frobenius rank of \lambda / \mu is the number of rows in the Jacobi-Trudi matrix of \lambda / \mu which don't contain h_0. Further definitions have been considered in [Stan2002]_ (where Frobenius rank is just being called rank). If \mu is the empty shape, then the Frobenius rank of \lambda / \mu is just the usual Frobenius rank of the partition \lambda (see :meth:~sage.combinat.partition.Partition.frobenius_rank()). REFERENCES: .. [Stan2002] Richard P. Stanley, *The rank and minimal border strip decompositions of a skew partition*, J. Combin. Theory Ser. A 100 (2002), pp. 349-375. :arxiv:math/0109092v1. EXAMPLES:: sage: SkewPartition([[8,8,7,4], [4,1,1]]).frobenius_rank() 4 sage: SkewPartition([[2,1], [1]]).frobenius_rank() 2 sage: SkewPartition([[2,1,1], [1]]).frobenius_rank() 2 sage: SkewPartition([[2,1,1], [1,1]]).frobenius_rank() 2 sage: SkewPartition([[5,4,3,2], [2,1,1]]).frobenius_rank() 3 sage: SkewPartition([[4,2,1], [3,1,1]]).frobenius_rank() 2 sage: SkewPartition([[4,2,1], [3,2,1]]).frobenius_rank() 1 If the inner shape is empty, then the Frobenius rank of the skew partition is just the standard Frobenius rank of the partition:: sage: all( SkewPartition([lam, Partition([])]).frobenius_rank() ....:      == lam.frobenius_rank() for i in range(6) ....:      for lam in Partitions(i) ) True If the inner and outer shapes are equal, then the Frobenius rank is zero:: sage: all( SkewPartition([lam, lam]).frobenius_rank() == 0 ....:      for i in range(6) for lam in Partitions(i) ) True """ N = len(self[0]) mu_betas = [x - j for (j, x) in enumerate(self[1])] mu_betas.extend([- j for j in range(len(self[1]), N)]) res = 0 for i, x in enumerate(self[0]): if not x - i in mu_betas: res += 1 return res def cells(self): """ Return the coordinates of the cells of self. Coordinates are class SkewPartition(CombinatorialObject, def to_dag(self): """ Return a directed acyclic graph corresponding to the skew partition. partition self. The directed acyclic graph corresponding to a skew partition p is the digraph whose vertices are the cells of p, and whose edges go from each cell to its lower and right neighbors (in English notation). EXAMPLES:: class SkewPartition(CombinatorialObject, #Check to see if there is anything below if row != len(skew) - 1: if len(skew[row+1]) > column: if skew[row+1][column] is not None: newstring = "%d,%d" % (row+1, column) G.add_edge(string, newstring) newstring = "%d,%d" % (row+1, column) G.add_edge(string, newstring) return G def quotient(self, k): class SkewPartition(CombinatorialObject, def rows_intersection_set(self): r""" Return the set of cells in the lines of \lambda which intersect the skew partition. Return the set of cells in the rows of the outer shape of self which rows intersect the skew diagram of self. EXAMPLES:: sage: skp = SkewPartition([[3,2,1],[2,1]]) sage: cells = Set([ (0,0), (0, 1), (0,2), (1, 0), (1, 1), (2, 0)]) sage: skp.rows_intersection_set() == cells class SkewPartition(CombinatorialObject, def columns_intersection_set(self): """ Return the set of cells in the lines of lambda which intersect the skew partition. Return the set of cells in the columns of the outer shape of self which columns intersect the skew diagram of self. EXAMPLES:: sage: skp = SkewPartition([[3,2,1],[2,1]]) sage: cells = Set([ (0,0), (0, 1), (0,2), (1, 0), (1, 1), (2, 0)]) sage: skp.columns_intersection_set() == cells class SkewPartition(CombinatorialObject, def jacobi_trudi(self): """ Return the Jacobi-Trudi matrix of self`. EXAMPLES:: sage: SkewPartition([[3,2,1],[2,1]]).jacobi_trudi() [h[1]    0    0] [h[3] h[1]    0] class SkewPartition(CombinatorialObject, p = self.outer() q = self.inner() from sage.combinat.sf.sf import SymmetricFunctions if len(p) == 0 and len(q) == 0: nn = len(p) if nn == 0: return MatrixSpace(SymmetricFunctions(QQ).homogeneous(), 0)(0) nn = len(p) h = SymmetricFunctions(QQ).homogeneous() H = MatrixSpace(h, nn) q  = q + [0]*int(nn-len(q)) q = q + [0]*int(nn-len(q)) m = [] for i in range(1,nn+1): row = [] for j in range(1,nn+1): v = p[j-1]-q[i-1]-j+i if v < 0: row.append(h(0)) row.append(h.zero()) elif v == 0: row.append(h([])) else: class SkewPartitions_rowlengths(SkewPart if x in SkewPartitions(): o = x[0] i = x[1]+[0]*(len(x[0])-len(x[1])) return [x[0]-x[1] for x in zip(o,i)] == self.co return [u[0]-u[1] for u in zip(o,i)] == self.co return False def _repr_(self): class SkewPartitions_rowlengths(SkewPart yield self.element_class(self, [[self.co[0]],[]]) return result = [] for sskp in SkewPartitions(row_lengths=self.co[:-1], overlap=self.overlap): for sp in self._from_row_lengths_aux(sskp, self.co[-2], self.co[-1], self.overlap): yield self.element_class(self, sp)