Skip to content

Commit aaaf5f4

Browse files
juliohmandreasnoack
authored andcommitted
Add multiexponents(m,n) for exponents of multinomial expansion (#57)
* Add multiexponents(m,n) for exponents of multinomial expansion * Implement iterator interface * Add comments * Refactor next(m::MultiExponents, s) * Fix indentation * Add tests for multiexponents() * Use immutable instead of struct because of Julia v0.5 * Add Julia v0.6 to Travis CI build * Avoid intermediate memory allocation in multiexponents * Refactor comments * Add URL for stars and bars technique
1 parent 84fe2fd commit aaaf5f4

File tree

6 files changed

+85
-0
lines changed

6 files changed

+85
-0
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ os:
33
- linux
44
julia:
55
- 0.5
6+
- 0.6
67
- nightly
78
sudo: false
89
notifications:

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This library provides the following functions:
2525
- `lucasnum(n)`: the n-th Lucas number; always returns a `BigInt`;
2626
- `multifactorial(n)`: returns the m-multifactorial n(!^m); always returns a `BigInt`;
2727
- `multinomial(k...)`: receives a tuple of `k_1, ..., k_n` and calculates the multinomial coefficient `(n k)`, where `n = sum(k)`; returns a `BigInt` only if given a `BigInt`;
28+
- `multiexponents(m,n)`: returns the exponents in the multinomial expansion (x₁ + x₂ + ... + xₘ)ⁿ;
2829
- `primorial(n)`: returns the product of all positive prime numbers <= n; always returns a `BigInt`;
2930
- `stirlings1(n, k, signed=false)`: returns the `(n,k)`-th Stirling number of the first kind; the number is signed if `signed` is true; returns a `BigInt` only if given a `BigInt`.
3031
- `stirlings2(n, k)`: returns the `(n,k)`-th Stirling number of the second kind; returns a `BigInt` only if given a `BigInt`.

src/Combinatorics.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ include("factorials.jl")
1919
include("combinations.jl")
2020
include("permutations.jl")
2121
include("partitions.jl")
22+
include("multinomials.jl")
2223
include("youngdiagrams.jl")
2324

2425
end #module

src/multinomials.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Multinomial theorem
2+
# https://en.wikipedia.org/wiki/Multinomial_theorem
3+
4+
export multiexponents
5+
6+
immutable MultiExponents{T}
7+
c::Combinations{T}
8+
nterms::Int
9+
end
10+
11+
start(m::MultiExponents) = start(m.c)
12+
13+
# Standard stars and bars:
14+
# https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)
15+
function next(m::MultiExponents, s)
16+
stars, ss = next(m.c, s)
17+
18+
# stars minus their consecutive
19+
# position becomes their index
20+
result = zeros(Int, m.nterms)
21+
for (i,s) in enumerate(stars)
22+
result[s-i+1] += 1
23+
end
24+
25+
result, ss
26+
end
27+
28+
done(m::MultiExponents, s) = done(m.c, s)
29+
30+
length(m::MultiExponents) = length(m.c)
31+
32+
"""
33+
multiexponents(m, n)
34+
35+
Returns the exponents in the multinomial expansion (x₁ + x₂ + ... + xₘ)ⁿ.
36+
37+
For example, the expansion (x₁ + x₂ + x₃)² = x₁² + x₁x₂ + x₁x₃ + ...
38+
has the exponents:
39+
40+
julia> collect(multiexponents(3, 2))
41+
42+
6-element Array{Any,1}:
43+
[2, 0, 0]
44+
[1, 1, 0]
45+
[1, 0, 1]
46+
[0, 2, 0]
47+
[0, 1, 1]
48+
[0, 0, 2]
49+
"""
50+
function multiexponents(m, n)
51+
# number of stars and bars = m+n-1
52+
c = combinations(1:m+n-1, n)
53+
54+
MultiExponents(c, m)
55+
end

test/multinomials.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Combinatorics
2+
using Base.Test
3+
4+
# degenerate cases (x₁ + x₂ + ⋯ + xₘ)¹
5+
@test [multiexponents(1,1)...] == [[1]]
6+
@test [multiexponents(2,1)...] == [[1,0],[0,1]]
7+
@test [multiexponents(3,1)...] == [[1,0,0],[0,1,0],[0,0,1]]
8+
@test hcat([multiexponents(10,1)...]...) == eye(10)
9+
10+
# degenerate cases (x₁ + x₂ + ⋯ + xₘ)⁰
11+
@test [multiexponents(1,0)...] == [[0]]
12+
@test [multiexponents(2,0)...] == [[0,0]]
13+
@test [multiexponents(3,0)...] == [[0,0,0]]
14+
@test [multiexponents(10,0)...] == [zeros(Int, 10)]
15+
16+
# degenerate cases (x₁)ⁿ
17+
@test [multiexponents(1,1)...] == [[1]]
18+
@test [multiexponents(1,2)...] == [[2]]
19+
@test [multiexponents(1,3)...] == [[3]]
20+
@test [multiexponents(1,10)...] == [[10]]
21+
22+
# general cases
23+
@test [multiexponents(3,2)...] == [[2,0,0],[1,1,0],[1,0,1],[0,2,0],[0,1,1],[0,0,2]]
24+
@test [multiexponents(2,3)...] == [[3,0],[2,1],[1,2],[0,3]]
25+
@test [multiexponents(2,2)...] == [[2,0],[1,1],[0,2]]
26+
@test [multiexponents(3,3)...] == [[3,0,0],[2,1,0],[2,0,1],[1,2,0],[1,1,1],[1,0,2],[0,3,0],[0,2,1],[0,1,2],[0,0,3]]

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ include("factorials.jl")
66
include("combinations.jl")
77
include("permutations.jl")
88
include("partitions.jl")
9+
include("multinomials.jl")
910
include("youngdiagrams.jl")
1011

0 commit comments

Comments
 (0)