Brent Yorgey’s fast algorithm for integer vector (multiset) partitions.¶
ALGORITHM:
Brent Yorgey, Generating Multiset Partitions, The Monad Reader, Issue 8, September 2007, p. 5.
https://wiki.haskell.org/The_Monad.Reader/Previous_issues
AUTHORS:
- D. K. Sunko (2020-02-19): initial version 
- F. Chapoton (2020-02-22): conversion to iterators and shorter doctests and doc tweaks 
- T. Scrimshaw (2020-03-06): Cython optimizations and doc tweaks 
- sage.combinat.fast_vector_partitions.fast_vector_partitions(v, min_vals=None)[source]¶
- Brent Yorgey’s fast algorithm for integer vector (multiset) partitions. - INPUT: - v– list of nonnegative integers, understood as the vector to be partitioned
- min_vals– (optional) list of nonnegative integers, of same length as- v
 - OUTPUT: list of lists, each representing a vector partition of - v- If - min_valsis given, only partitions with parts- p >= min_valsin the lexicographic ordering will appear.- If - min_valsis given and- len(min_vals) != len(v), an error is raised.- EXAMPLES: - The older the computer, the more impressive the comparison: - sage: from sage.combinat.fast_vector_partitions import fast_vector_partitions sage: fastvparts = list(fast_vector_partitions([3, 3, 3])) sage: vparts = list(VectorPartitions([3, 3, 3])) sage: vparts == fastvparts[::-1] True sage: len(fastvparts) 686 sage: list(fast_vector_partitions([1, 2, 3], min_vals=[0, 1, 1])) [[[1, 2, 3]], [[0, 2, 3], [1, 0, 0]], [[0, 2, 2], [1, 0, 1]], [[0, 2, 1], [1, 0, 2]], [[0, 2, 0], [1, 0, 3]], [[0, 1, 3], [1, 1, 0]], [[0, 1, 2], [1, 1, 1]], [[0, 1, 1], [1, 1, 2]], [[0, 1, 1], [0, 1, 2], [1, 0, 0]], [[0, 1, 1], [0, 1, 1], [1, 0, 1]]] sage: L1 = list(fast_vector_partitions([5, 7, 6], min_vals=[1, 3, 2])) sage: L1 == list(VectorPartitions([5, 7, 6], min=[1, 3, 2]))[::-1] True - >>> from sage.all import * >>> from sage.combinat.fast_vector_partitions import fast_vector_partitions >>> fastvparts = list(fast_vector_partitions([Integer(3), Integer(3), Integer(3)])) >>> vparts = list(VectorPartitions([Integer(3), Integer(3), Integer(3)])) >>> vparts == fastvparts[::-Integer(1)] True >>> len(fastvparts) 686 >>> list(fast_vector_partitions([Integer(1), Integer(2), Integer(3)], min_vals=[Integer(0), Integer(1), Integer(1)])) [[[1, 2, 3]], [[0, 2, 3], [1, 0, 0]], [[0, 2, 2], [1, 0, 1]], [[0, 2, 1], [1, 0, 2]], [[0, 2, 0], [1, 0, 3]], [[0, 1, 3], [1, 1, 0]], [[0, 1, 2], [1, 1, 1]], [[0, 1, 1], [1, 1, 2]], [[0, 1, 1], [0, 1, 2], [1, 0, 0]], [[0, 1, 1], [0, 1, 1], [1, 0, 1]]] >>> L1 = list(fast_vector_partitions([Integer(5), Integer(7), Integer(6)], min_vals=[Integer(1), Integer(3), Integer(2)])) >>> L1 == list(VectorPartitions([Integer(5), Integer(7), Integer(6)], min=[Integer(1), Integer(3), Integer(2)]))[::-Integer(1)] True - Note - The partitions are returned as an iterator. - In this documentation, - a <|= bmeans- a[i] <= b[i]for all- i(notation following B. Yorgey’s paper). It is the monomial partial ordering in Dickson’s lemma:- a <|= biff- x^adivides- x^bas monomials.- Warning - The ordering of the partitions is reversed with respect to the output of Sage class - VectorPartitions.
- sage.combinat.fast_vector_partitions.recursive_vector_partitions(v, vL)[source]¶
- Iterate over a lexicographically ordered list of lists, each list representing a vector partition of - v, such that no part of any partition is lexicographically smaller than- vL.- Internal part of - fast_vector_partitions().- INPUT: - v– list of nonnegative integers, understood as a vector
- vL– list of nonnegative integers, understood as a vector
 - EXAMPLES: - sage: from sage.combinat.fast_vector_partitions import recursive_vector_partitions sage: list(recursive_vector_partitions([2, 2, 2],[1, 1, 1])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]]] sage: list(recursive_vector_partitions([2, 2, 2],[1, 1, 0])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 0], [1, 1, 2]]] sage: list(recursive_vector_partitions([2, 2, 2],[1, 0, 1])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 0], [1, 1, 2]], [[1, 0, 2], [1, 2, 0]], [[1, 0, 1], [1, 2, 1]]] - >>> from sage.all import * >>> from sage.combinat.fast_vector_partitions import recursive_vector_partitions >>> list(recursive_vector_partitions([Integer(2), Integer(2), Integer(2)],[Integer(1), Integer(1), Integer(1)])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]]] >>> list(recursive_vector_partitions([Integer(2), Integer(2), Integer(2)],[Integer(1), Integer(1), Integer(0)])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 0], [1, 1, 2]]] >>> list(recursive_vector_partitions([Integer(2), Integer(2), Integer(2)],[Integer(1), Integer(0), Integer(1)])) [[[2, 2, 2]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 0], [1, 1, 2]], [[1, 0, 2], [1, 2, 0]], [[1, 0, 1], [1, 2, 1]]] 
- sage.combinat.fast_vector_partitions.recursive_within_from_to(m, s, e, useS, useE)[source]¶
- Iterate over a lexicographically ordered list of lists - vsatisfying- e <= v <= sand- v <|= mas vectors.- Internal part of - fast_vector_partitions().- INPUT: - m– list of nonnegative integers, understood as a vector
- s– list of nonnegative integers, understood as a vector
- e– list of nonnegative integers, understood as a vector
- useS– boolean
- useE– boolean
 - EXAMPLES: - sage: from sage.combinat.fast_vector_partitions import recursive_within_from_to sage: list(recursive_within_from_to([1, 2, 3],[1, 2, 2],[1, 1, 1],True,True)) [[1, 2, 2], [1, 2, 1], [1, 2, 0], [1, 1, 3], [1, 1, 2], [1, 1, 1]] - >>> from sage.all import * >>> from sage.combinat.fast_vector_partitions import recursive_within_from_to >>> list(recursive_within_from_to([Integer(1), Integer(2), Integer(3)],[Integer(1), Integer(2), Integer(2)],[Integer(1), Integer(1), Integer(1)],True,True)) [[1, 2, 2], [1, 2, 1], [1, 2, 0], [1, 1, 3], [1, 1, 2], [1, 1, 1]] - Note - The flags - useSand- useEare used to implement the condition efficiently. Because testing it loops over the vector, re-testing at each step as the vector is parsed is inefficient: all but the last comparison have been done cumulatively already. This code tests only for the last one, using the flags to accumulate information from previous calls.- Warning - Expects to be called with - s <|= m.- Expects to be called first with - useS == useE == True.
- sage.combinat.fast_vector_partitions.within_from_to(m, s, e)[source]¶
- Iterate over a lexicographically ordered list of lists - vsatisfying- e <= v <= sand- v <|= mas vectors.- Internal part of - fast_vector_partitions().- INPUT: - m– list of nonnegative integers, understood as a vector
- s– list of nonnegative integers, understood as a vector
- e– list of nonnegative integers, understood as a vector
 - EXAMPLES: - sage: from sage.combinat.fast_vector_partitions import within_from_to sage: list(within_from_to([1, 2, 3], [1, 2, 2], [1, 1, 1])) [[1, 2, 2], [1, 2, 1], [1, 2, 0], [1, 1, 3], [1, 1, 2], [1, 1, 1]] - >>> from sage.all import * >>> from sage.combinat.fast_vector_partitions import within_from_to >>> list(within_from_to([Integer(1), Integer(2), Integer(3)], [Integer(1), Integer(2), Integer(2)], [Integer(1), Integer(1), Integer(1)])) [[1, 2, 2], [1, 2, 1], [1, 2, 0], [1, 1, 3], [1, 1, 2], [1, 1, 1]] - Note - The input - swill be “clipped” internally if it does not satisfy the condition- s <|= m.- To understand the input check, some line art is helpful. Assume that - (a,b)are the two least significant coordinates of some vector. Say:- e = (2,3), s = (7,6), m = (9,8).- In the figure, these values are denoted by - E,- S, and- M, while the letter- Xstands for all other allowed values of- v = (a,b):- b ^ | 8 --------X---X---X---X---X-----------M | | 7 - X X X X X | | | 6 - X X X X X S | | | 5 - X X X X X X | | | 4 - X X X X X X | | | 3 - E X X X X X | | | 2 - X X X X X | | | 1 - X X X X X | | | 0 ----|---|---X---X---X---X---X---|---|---> 0 1 2 3 4 5 6 7 8 9 a - If - Smoves horizontally, the full-height columns fill the box in until- Sreaches- M, at which point it remains the limit in the b-direction as it moves out of the box, while M takes over as the limit in the a-direction, so the- M-column remains filled only up to- S, no matter how much- Smoves further to the right.- If - Smoves vertically, its column will be filled to the top of the box, but it remains the relevant limit in the a-direction, while- Mtakes over in the b-direction as- Sgoes out of the box upwards.- Both behaviors are captured by using the smaller coordinate of - Sand- M, whenever- Sis outside the box defined by M. The input will be “clipped” accordingly in that case.- Warning - The “clipping” behavior is transparent to the user, but may be puzzling when comparing outputs with the function - recursive_within_from_to()which has no input protection.