CurrentModule = Oscar
DocTestSetup = quote
using Oscar
end
A partition of a non-negative integer
A partition can be encoded as an array with elements Partition{T}
is provided which is a subtype of AbstractVector{T}
.
Here, T
can be any subtype of IntegerUnion
.
There is no performance impact by using an own type for partitions rather than simply using arrays.
The parametric type allows to increase performance by using smaller integer types.
partition
Because Partition
is a subtype of AbstractVector
, all functions that can be used for vectors (1-dimensional arrays) can be used for partitions as well.
julia> P = partition(6, 4, 4, 2)
[6, 4, 4, 2]
julia> length(P)
4
julia> P[1]
6
However, usually, size
for arrays already exists and returns the dimension of an array.
Instead, one can use the Julia function sum
to get the sum of the parts.
julia> P = partition(6, 4, 4, 2)
[6, 4, 4, 2]
julia> sum(P)
16
In algorithms involving partitions it is sometimes convenient to be able to access parts
beyond the length of the partition and then one wants to get the value zero instead of an
error. For this, OSCAR provides the function getindex_safe
:
getindex_safe
If you are sure that P[i]
exists, use getindex
because this will be faster.
partitions(::Oscar.IntegerUnion)
number_of_partitions(::Oscar.IntegerUnion)
For counting partitions, the Hardy-Ramanujan-Rademachen formula is used, see Joh12 for details. See also Knu11, Section 7.2.1.4 and OEIS, A000041.
How many ways are there to pay one euro, using coins worth 1, 2, 5, 10, 20, 50, and/or 100 cents? What if you are allowed to use at most two of each coin?
This is Exercise 11 in Knu11, Section 7.2.1.4. It goes back to the famous "Ways to change one dollar" problem, see Pol56. Generally, the problem is to generate and/or count partitions satisfying some restrictions. Of course, one could generate the list of all partitions of 100 (there are about 190 million) and then filter the result by the restrictions. But for certain types of restrictions there are much more efficient algorithms. The functions in this section implement some of these. In combination with Julia's filter function one can also handle more general types of restrictions.
For example, there are precisely six ways for the second question in the exercise quoted above:
julia> collect(partitions(100, [1, 2, 5, 10, 20, 50], [2, 2, 2, 2, 2, 2]))
6-element Vector{Partition{Int64}}:
[50, 50]
[50, 20, 20, 10]
[50, 20, 20, 5, 5]
[50, 20, 10, 10, 5, 5]
[50, 20, 20, 5, 2, 2, 1]
[50, 20, 10, 10, 5, 2, 2, 1]
and there are 4562 ways for the first question in the exercise:
julia> length(partitions(100, [1, 2, 5, 10, 20, 50]))
4562
The original "Ways to change one dollar" problem has 292 solutions:
julia> length(partitions(100, [1, 5, 10, 25, 50]))
292
number_of_partitions(::Oscar.IntegerUnion, ::Oscar.IntegerUnion)
For counting the partitions the recurrence relation
partitions(::T, ::Oscar.IntegerUnion, ::Oscar.IntegerUnion, ::Oscar.IntegerUnion) where T <: Oscar.IntegerUnion
partitions(::T, ::Vector{T}) where T <: Oscar.IntegerUnion
The conjugate of a partition
conjugate
The dominance order on partitions is the partial order
Note that whereas the lexicographic ordering is a total ordering, the dominance ordering is not.
Further, Knu11 says majorizes instead of dominates and uses the symbol
dominates