Skip to content

Commit

Permalink
Migrate functions, docs and tests from Base
Browse files Browse the repository at this point in the history
Also:
- clean up readme
- expose docs that were buried in comments
- get rid of @compat usage
  • Loading branch information
jiahao committed Nov 6, 2015
1 parent 78b31c3 commit f28bd62
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 193 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,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
1 change: 0 additions & 1 deletion REQUIRE
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
julia 0.5-
Compat
Polynomials
Iterators
11 changes: 7 additions & 4 deletions src/combinations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ 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
Expand All @@ -43,7 +43,10 @@ function combinations(a, t::Integer)
Combinations(a, t)
end

#generate combinations of all orders, chaining of order iterators is eager,
#but sequence at each order is lazy

"""
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)]...)

30 changes: 24 additions & 6 deletions src/factorials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export
derangement,
factorial,
subfactorial,
doublefactorial,
hyperfactorial,
Expand All @@ -10,7 +11,24 @@ export
primorial,
multinomial

# The number of permutations of n with no fixed points (subfactorial)
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]))
Expand All @@ -23,7 +41,7 @@ function doublefactorial(n::Integer)
end
z = BigInt()
ccall((:__gmpz_2fac_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

Expand All @@ -36,7 +54,7 @@ function multifactorial(n::Integer, m::Integer)
end
z = BigInt()
ccall((:__gmpz_mfac_uiui, :libgmp), Void,
(Ptr{BigInt}, UInt, UInt), &z, @compat(UInt(n)), @compat(UInt(m)))
(Ptr{BigInt}, UInt, UInt), &z, UInt(n), UInt(m))
return z
end

Expand All @@ -46,15 +64,15 @@ function primorial(n::Integer)
end
z = BigInt()
ccall((:__gmpz_primorial_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

#Multinomial coefficient where n = sum(k)
"Multinomial coefficient where n = sum(k)"
function multinomial(k...)
s = 0
result = 1
for i in k
@inbounds for i in k
s += i
result *= binomial(s, i)
end
Expand Down
16 changes: 9 additions & 7 deletions src/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export bellnum,
lucasnum,
stirlings1

# Returns the n-th Bell number
"Returns the n-th Bell number"
function bellnum(bn::Integer)
if bn < 0
throw(DomainError())
Expand All @@ -28,7 +28,7 @@ function bellnum(bn::Integer)
return list[end]
end

# Returns the n-th Catalan number
"Returns the n-th Catalan number"
function catalannum(bn::Integer)
if bn<0
throw(DomainError())
Expand All @@ -44,7 +44,7 @@ function fibonaccinum(n::Integer)
end
z = BigInt()
ccall((:__gmpz_fib_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

Expand All @@ -56,8 +56,10 @@ function jacobisymbol(a::Integer, b::Integer)
(Ptr{BigInt}, Ptr{BigInt}), &ba, &bb)
end

#Computes Lassalle's sequence
#OEIS entry A180874
"""
Computes Lassalle's sequence
OEIS entry A180874
"""
function lassallenum(m::Integer)
A = ones(BigInt,m)
for n=2:m
Expand All @@ -79,11 +81,11 @@ function lucasnum(n::Integer)
end
z = BigInt()
ccall((:__gmpz_lucnum_ui, :libgmp), Void,
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
(Ptr{BigInt}, UInt), &z, UInt(n))
return z
end

# Returns s(n, k), the signed Stirling number of first kind
"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]
Expand Down
156 changes: 93 additions & 63 deletions src/partitions.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#Partitions

export cool_lex, integer_partitions, ncpartitions
export
cool_lex,
integer_partitions,
ncpartitions,
partitions,
prevprod
#nextprod,


#integer partitions
Expand All @@ -11,12 +17,17 @@ end

length(p::IntegerPartitions) = npartitions(p.n)

partitions(n::Integer) = IntegerPartitions(n)

start(p::IntegerPartitions) = Int[]
done(p::IntegerPartitions, xs) = length(xs) == p.n
next(p::IntegerPartitions, xs) = (xs = nextpartition(p.n,xs); (xs,xs))

"""
Generate all integer arrays that sum to `n`. Because the number of partitions can be very large, this function returns an iterator object. Use `collect(partitions(n))` to get an array of all partitions. The number of partitions to generate can be efficiently computed using `length(partitions(n))`.
"""
partitions(n::Integer) = IntegerPartitions(n)



function nextpartition(n, as)
if isempty(as); return Int[n]; end

Expand Down Expand Up @@ -77,6 +88,9 @@ end

length(f::FixedPartitions) = npartitions(f.n,f.m)

"""
Generate all arrays of `m` integers that sum to `n`. Because the number of partitions can be very large, this function returns an iterator object. Use `collect(partitions(n,m))` to get an array of all partitions. The number of partitions to generate can be efficiently computed using `length(partitions(n,m))`.
"""
partitions(n::Integer, m::Integer) = n >= 1 && m >= 1 ? FixedPartitions(n,m) : throw(DomainError())

start(f::FixedPartitions) = Int[]
Expand Down Expand Up @@ -139,6 +153,9 @@ end

length(p::SetPartitions) = nsetpartitions(length(p.s))

"""
Generate all set partitions of the elements of an array, represented as arrays of arrays. Because the number of partitions can be very large, this function returns an iterator object. Use `collect(partitions(array))` to get an array of all partitions. The number of partitions to generate can be efficiently computed using `length(partitions(array))`.
"""
partitions(s::AbstractVector) = SetPartitions(s)

start(p::SetPartitions) = (n = length(p.s); (zeros(Int32, n), ones(Int32, n-1), n, 1))
Expand Down Expand Up @@ -206,6 +223,9 @@ end

length(p::FixedSetPartitions) = nfixedsetpartitions(length(p.s),p.m)

"""
Generate all set partitions of the elements of an array into exactly m subsets, represented as arrays of arrays. Because the number of partitions can be very large, this function returns an iterator object. Use `collect(partitions(array,m))` to get an array of all partitions. The number of partitions into m subsets is equal to the Stirling number of the second kind and can be efficiently computed using `length(partitions(array,m))`.
"""
partitions(s::AbstractVector,m::Int) = length(s) >= 1 && m >= 1 ? FixedSetPartitions(s,m) : throw(DomainError())

function start(p::FixedSetPartitions)
Expand Down Expand Up @@ -278,51 +298,59 @@ function nfixedsetpartitions(n::Int,m::Int)
return numpart
end


# For a list of integers i1, i2, i3, find the smallest
# i1^n1 * i2^n2 * i3^n3 >= x
# for integer n1, n2, n3
function nextprod(a::Vector{Int}, x)
if x > typemax(Int)
throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
end
k = length(a)
v = ones(Int, k) # current value of each counter
mx = [nextpow(ai,x) for ai in a] # maximum value of each counter
v[1] = mx[1] # start at first case that is >= x
p::widen(Int) = mx[1] # initial value of product in this case
best = p
icarry = 1

while v[end] < mx[end]
if p >= x
best = p < best ? p : best # keep the best found yet
carrytest = true
while carrytest
p = div(p, v[icarry])
v[icarry] = 1
icarry += 1
p *= a[icarry]
v[icarry] *= a[icarry]
carrytest = v[icarry] > mx[icarry] && icarry < k
end
if p < x
icarry = 1
end
else
while p < x
p *= a[1]
v[1] *= a[1]
end
end
end
best = mx[end] < best ? mx[end] : best
return Int(best) # could overflow, but best to have predictable return type
end

# For a list of integers i1, i2, i3, find the largest
# i1^n1 * i2^n2 * i3^n3 <= x
# for integer n1, n2, n3
#This function is still defined in Base because it is being used by Base.DSP
#"""
#Next integer not less than `n` that can be written as $\prod k_i^{p_i}$ for integers $p_1$, $p_2$, etc.
#
#For a list of integers i1, i2, i3, find the smallest
# i1^n1 * i2^n2 * i3^n3 >= x
#for integer n1, n2, n3
#"""
#function nextprod(a::Vector{Int}, x)
# if x > typemax(Int)
# throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
# end
# k = length(a)
# v = ones(Int, k) # current value of each counter
# mx = [nextpow(ai,x) for ai in a] # maximum value of each counter
# v[1] = mx[1] # start at first case that is >= x
# p::widen(Int) = mx[1] # initial value of product in this case
# best = p
# icarry = 1
#
# while v[end] < mx[end]
# if p >= x
# best = p < best ? p : best # keep the best found yet
# carrytest = true
# while carrytest
# p = div(p, v[icarry])
# v[icarry] = 1
# icarry += 1
# p *= a[icarry]
# v[icarry] *= a[icarry]
# carrytest = v[icarry] > mx[icarry] && icarry < k
# end
# if p < x
# icarry = 1
# end
# else
# while p < x
# p *= a[1]
# v[1] *= a[1]
# end
# end
# end
# best = mx[end] < best ? mx[end] : best
# return Int(best) # could overflow, but best to have predictable return type
#end

"""
Previous integer not greater than `n` that can be written as $\prod k_i^{p_i}$ for integers $p_1$, $p_2$, etc.
For a list of integers i1, i2, i3, find the largest
i1^n1 * i2^n2 * i3^n3 <= x
for integer n1, n2, n3
"""
function prevprod(a::Vector{Int}, x)
if x > typemax(Int)
throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
Expand Down Expand Up @@ -362,7 +390,7 @@ function prevprod(a::Vector{Int}, x)
end


# Lists the partitions of the number n, the order is consistent with GAP
"Lists the partitions of the number n, the order is consistent with GAP"
function integer_partitions(n::Integer)
if n < 0
throw(DomainError())
Expand All @@ -384,20 +412,22 @@ function integer_partitions(n::Integer)
list
end

# Produces (n,k)-combinations in cool-lex order
#
#Implements the cool-lex algorithm to generate (n,k)-combinations
#@article{Ruskey:2009fk,
# Author = {Frank Ruskey and Aaron Williams},
# Doi = {10.1016/j.disc.2007.11.048},
# Journal = {Discrete Mathematics},
# Month = {September},
# Number = {17},
# Pages = {5305-5320},
# Title = {The coolest way to generate combinations},
# Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570},
# Volume = {309},
# Year = {2009}}
"""
Produces (n,k)-combinations in cool-lex order
Implements the cool-lex algorithm to generate (n,k)-combinations
@article{Ruskey:2009fk,
Author = {Frank Ruskey and Aaron Williams},
Doi = {10.1016/j.disc.2007.11.048},
Journal = {Discrete Mathematics},
Month = {September},
Number = {17},
Pages = {5305-5320},
Title = {The coolest way to generate combinations},
Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570},
Volume = {309},
Year = {2009}}
"""
function cool_lex(n::Integer, t::Integer)
s = n-t
if n > 64 error("Not implemented for n > 64") end
Expand Down
Loading

0 comments on commit f28bd62

Please sign in to comment.