Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate Base combinatorics features #8

Merged
merged 5 commits into from
Nov 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Combinatorics

[![Combinatorics](http://pkg.julialang.org/badges/Combinatorics_0.3.svg)](http://pkg.julialang.org/?pkg=Combinatorics&ver=0.3)
[![Combinatorics](http://pkg.julialang.org/badges/Combinatorics_0.4.svg)](http://pkg.julialang.org/?pkg=Combinatorics&ver=0.4)
[![Build Status](https://travis-ci.org/JuliaLang/Combinatorics.jl.svg?branch=master)](https://travis-ci.org/JuliaLang/Combinatorics.jl)
[![Coverage Status](https://coveralls.io/repos/JuliaLang/Combinatorics.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/JuliaLang/Combinatorics.jl?branch=master)
Expand All @@ -11,18 +10,18 @@ combinatorics and permutations. As overflows are expected even for low values,
most of the functions always return `BigInt`, and are marked as such below.

This library provides the following functions:
- `bell(n)`: returns the n-th Bell number; always returns a `BigInt`;
- `catalan(n)`: returns the n-th Catalan number; always returns a `BigInt`;
- `combinations(a)`: returns combinations of all order by chaining calls to `Base.combinations(a,n);
- `bellnum(n)`: returns the n-th Bell number; always returns a `BigInt`;
- `catalannum(n)`: returns the n-th Catalan number; always returns a `BigInt`;
- `combinations(a)`: returns combinations of all order by chaining calls to `Base.combinations(a,n);
- `derangement(n)`/`subfactorial(n)`: returns the number of permutations of n with no fixed points; always returns a `BigInt`;
- `doublefactorial(n)`: returns the double factorial n!!; always returns a `BigInt`;
- `fibonacci(n)`: the n-th Fibonacci number; always returns a `BigInt`;
- `hyperfactorial(n)`: the n-th hyperfactorial, i.e. prod([i^i for i = 2:n]; always returns a `BigInt`;
- `integer_partitions(n)`: returns a `Vector{Int}` consisting of the partitions of the number `n`.
- `jacobisymbol(a,b)`: returns the Jacobi symbol (a/b);
- `lassalle(n)`: returns the nth Lassalle number A<sub>n</sub> defined in [arXiv:1009.4225](http://arxiv.org/abs/1009.4225) ([OEIS A180874](http://oeis.org/A180874)); always returns a `BigInt`;
- `lassallenum(n)`: returns the nth Lassalle number A<sub>n</sub> defined in [arXiv:1009.4225](http://arxiv.org/abs/1009.4225) ([OEIS A180874](http://oeis.org/A180874)); always returns a `BigInt`;
- `legendresymbol(a,p)`: returns the Legendre symbol (a/p);
- `lucas(n)`: the n-th Lucas number; always returns a `BigInt`;
- `lucasnum(n)`: the n-th Lucas number; always returns a `BigInt`;
- `multifactorial(n)`: returns the m-multifactorial n(!^m); always returns a `BigInt`;
- `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`;
- `primorial(n)`: returns the product of all positive prime numbers <= n; always returns a `BigInt`;
Expand Down
3 changes: 1 addition & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
julia 0.4
Compat
julia 0.5-
Polynomials
Iterators
157 changes: 6 additions & 151 deletions src/Combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,158 +2,13 @@ module Combinatorics

using Compat, Polynomials, Iterators

import Base:combinations

export bell,
derangement,
doublefactorial,
fibonacci,
hyperfactorial,
jacobisymbol,
lassalle,
legendresymbol,
lucas,
multifactorial,
multinomial,
primorial,
stirlings1,
subfactorial
import Base: start, next, done, length, eltype

include("numbers.jl")
include("factorials.jl")
include("combinations.jl")
include("permutations.jl")
include("partitions.jl")
include("youngdiagrams.jl")

# Returns the n-th Bell number
function bell(bn::Integer)
if bn < 0
throw(DomainError())
else
n = BigInt(bn)
end
list = Array(BigInt, div(n*(n+1), 2))
list[1] = 1
for i = 2:n
beg = div(i*(i-1),2)
list[beg+1] = list[beg]
for j = 2:i
list[beg+j] = list[beg+j-1]+list[beg+j-i]
end
end
return list[end]
end

# Returns the n-th Catalan number
function catalan(bn::Integer)
if bn<0
throw(DomainError())
else
n = BigInt(bn)
end
div(binomial(2*n, n), (n + 1))
end

#generate combinations of all orders, chaining of order iterators is eager,
#but sequence at each order is lazy
combinations(a) = chain([combinations(a,k) for k=1:length(a)]...)

# The number of permutations of n with no fixed points (subfactorial)
function derangement(sn::Integer)
n = BigInt(sn)
return num(factorial(n)*sum([(-1)^k//factorial(k) for k=0:n]))
end
subfactorial(n::Integer) = derangement(n)

function doublefactorial(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_2fac_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
return z
end

function fibonacci(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_fib_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
return z
end

# Hyperfactorial
hyperfactorial(n::Integer) = prod([i^i for i = BigInt(2):n])

function jacobisymbol(a::Integer, b::Integer)
ba = BigInt(a)
bb = BigInt(b)
return ccall((:__gmpz_jacobi, :libgmp), Cint,
(Ptr{BigInt}, Ptr{BigInt}), &ba, &bb)
end

#Computes Lassalle's sequence
#OEIS entry A180874
function lassalle(m::Integer)
A = ones(BigInt,m)
for n=2:m
A[n]=(-1)^(n-1) * (catalan(n) + sum([(-1)^j*binomial(2n-1, 2j-1)*A[j]*catalan(n-j) for j=1:n-1]))
end
A[m]
end

function legendresymbol(a::Integer, b::Integer)
ba = BigInt(a)
bb = BigInt(b)
return ccall((:__gmpz_legendre, :libgmp), Cint,
(Ptr{BigInt}, Ptr{BigInt}), &ba, &bb)
end

function lucas(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_lucnum_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
return z
end

function multifactorial(n::Integer, m::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_mfac_uiui, :libgmp), Void,
(Ptr{BigInt}, UInt, UInt), &z, @compat(UInt(n)), @compat(UInt(m)))
return z
end

# Multinomial coefficient where n = sum(k)
function multinomial(k...)
s = 0
result = 1
for i in k
s += i
result *= binomial(s, i)
end
result
end

function primorial(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_primorial_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
return z
end

# Returns s(n, k), the signed Stirling number of first kind
function stirlings1(n::Integer, k::Integer)
p = poly(0:(n-1))
p[n - k + 1]
end

end # module
end #module
52 changes: 52 additions & 0 deletions src/combinations.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export combinations

#The Combinations iterator

immutable Combinations{T}
a::T
t::Int
end

start(c::Combinations) = [1:c.t;]
function next(c::Combinations, s)
comb = [c.a[si] for si in s]
if c.t == 0
# special case to generate 1 result for t==0
return (comb,[length(c.a)+2])
end
s = copy(s)
for i = length(s):-1:1
s[i] += 1
if s[i] > (length(c.a) - (length(s)-i))
continue
end
for j = i+1:endof(s)
s[j] = s[j-1]+1
end
break
end
(comb,s)
end
done(c::Combinations, s) = !isempty(s) && s[1] > length(c.a)-c.t+1

length(c::Combinations) = binomial(length(c.a),c.t)

eltype{T}(::Type{Combinations{T}}) = Vector{eltype(T)}

"Generate all combinations of `n` elements from an indexable object. Because the number of combinations can be very large, this function returns an iterator object. Use `collect(combinations(array,n))` to get an array of all combinations.
"
function combinations(a, t::Integer)
if t < 0
# generate 0 combinations for negative argument
t = length(a)+1
end
Combinations(a, t)
end


"""
generate combinations of all orders, chaining of order iterators is eager,
but sequence at each order is lazy
"""
combinations(a) = chain([combinations(a,k) for k=1:length(a)]...)

82 changes: 82 additions & 0 deletions src/factorials.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#Factorials and elementary coefficients

export
derangement,
factorial,
subfactorial,
doublefactorial,
hyperfactorial,
multifactorial,
gamma,
primorial,
multinomial

import Base: factorial

"computes n!/k!"
function factorial{T<:Integer}(n::T, k::T)
if k < 0 || n < 0 || k > n
throw(DomainError())
end
f = one(T)
while n > k
f = Base.checked_mul(f,n)
n -= 1
end
return f
end
factorial(n::Integer, k::Integer) = factorial(promote(n, k)...)


"The number of permutations of n with no fixed points (subfactorial)"
function derangement(sn::Integer)
n = BigInt(sn)
return num(factorial(n)*sum([(-1)^k//factorial(k) for k=0:n]))
end
subfactorial(n::Integer) = derangement(n)

function doublefactorial(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_2fac_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

# Hyperfactorial
hyperfactorial(n::Integer) = prod([i^i for i = BigInt(2):n])

function multifactorial(n::Integer, m::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_mfac_uiui, :libgmp), Void,
(Ptr{BigInt}, UInt, UInt), &z, UInt(n), UInt(m))
return z
end

function primorial(n::Integer)
if n < 0
throw(DomainError())
end
z = BigInt()
ccall((:__gmpz_primorial_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

"Multinomial coefficient where n = sum(k)"
function multinomial(k...)
s = 0
result = 1
@inbounds for i in k
s += i
result *= binomial(s, i)
end
result
end


Loading