Skip to content

Commit f28bd62

Browse files
committed
Migrate functions, docs and tests from Base
Also: - clean up readme - expose docs that were buried in comments - get rid of @compat usage
1 parent 78b31c3 commit f28bd62

File tree

11 files changed

+193
-193
lines changed

11 files changed

+193
-193
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ combinatorics and permutations. As overflows are expected even for low values,
1010
most of the functions always return `BigInt`, and are marked as such below.
1111

1212
This library provides the following functions:
13-
- `bell(n)`: returns the n-th Bell number; always returns a `BigInt`;
14-
- `catalan(n)`: returns the n-th Catalan number; always returns a `BigInt`;
15-
- `combinations(a)`: returns combinations of all order by chaining calls to `Base.combinations(a,n);
13+
- `bellnum(n)`: returns the n-th Bell number; always returns a `BigInt`;
14+
- `catalannum(n)`: returns the n-th Catalan number; always returns a `BigInt`;
15+
- `combinations(a)`: returns combinations of all order by chaining calls to `Base.combinations(a,n);
1616
- `derangement(n)`/`subfactorial(n)`: returns the number of permutations of n with no fixed points; always returns a `BigInt`;
1717
- `doublefactorial(n)`: returns the double factorial n!!; always returns a `BigInt`;
1818
- `fibonacci(n)`: the n-th Fibonacci number; always returns a `BigInt`;
1919
- `hyperfactorial(n)`: the n-th hyperfactorial, i.e. prod([i^i for i = 2:n]; always returns a `BigInt`;
2020
- `integer_partitions(n)`: returns a `Vector{Int}` consisting of the partitions of the number `n`.
2121
- `jacobisymbol(a,b)`: returns the Jacobi symbol (a/b);
22-
- `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`;
22+
- `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`;
2323
- `legendresymbol(a,p)`: returns the Legendre symbol (a/p);
24-
- `lucas(n)`: the n-th Lucas number; always returns a `BigInt`;
24+
- `lucasnum(n)`: the n-th Lucas number; always returns a `BigInt`;
2525
- `multifactorial(n)`: returns the m-multifactorial n(!^m); always returns a `BigInt`;
2626
- `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`;
2727
- `primorial(n)`: returns the product of all positive prime numbers <= n; always returns a `BigInt`;

REQUIRE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
julia 0.5-
2-
Compat
32
Polynomials
43
Iterators

src/combinations.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ length(c::Combinations) = binomial(length(c.a),c.t)
3333

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

36-
37-
36+
"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.
37+
"
3838
function combinations(a, t::Integer)
3939
if t < 0
4040
# generate 0 combinations for negative argument
@@ -43,7 +43,10 @@ function combinations(a, t::Integer)
4343
Combinations(a, t)
4444
end
4545

46-
#generate combinations of all orders, chaining of order iterators is eager,
47-
#but sequence at each order is lazy
46+
47+
"""
48+
generate combinations of all orders, chaining of order iterators is eager,
49+
but sequence at each order is lazy
50+
"""
4851
combinations(a) = chain([combinations(a,k) for k=1:length(a)]...)
4952

src/factorials.jl

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
export
44
derangement,
5+
factorial,
56
subfactorial,
67
doublefactorial,
78
hyperfactorial,
@@ -10,7 +11,24 @@ export
1011
primorial,
1112
multinomial
1213

13-
# The number of permutations of n with no fixed points (subfactorial)
14+
import Base: factorial
15+
16+
"computes n!/k!"
17+
function factorial{T<:Integer}(n::T, k::T)
18+
if k < 0 || n < 0 || k > n
19+
throw(DomainError())
20+
end
21+
f = one(T)
22+
while n > k
23+
f = Base.checked_mul(f,n)
24+
n -= 1
25+
end
26+
return f
27+
end
28+
factorial(n::Integer, k::Integer) = factorial(promote(n, k)...)
29+
30+
31+
"The number of permutations of n with no fixed points (subfactorial)"
1432
function derangement(sn::Integer)
1533
n = BigInt(sn)
1634
return num(factorial(n)*sum([(-1)^k//factorial(k) for k=0:n]))
@@ -23,7 +41,7 @@ function doublefactorial(n::Integer)
2341
end
2442
z = BigInt()
2543
ccall((:__gmpz_2fac_ui, :libgmp), Void,
26-
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
44+
(Ptr{BigInt}, UInt), &z, UInt(n))
2745
return z
2846
end
2947

@@ -36,7 +54,7 @@ function multifactorial(n::Integer, m::Integer)
3654
end
3755
z = BigInt()
3856
ccall((:__gmpz_mfac_uiui, :libgmp), Void,
39-
(Ptr{BigInt}, UInt, UInt), &z, @compat(UInt(n)), @compat(UInt(m)))
57+
(Ptr{BigInt}, UInt, UInt), &z, UInt(n), UInt(m))
4058
return z
4159
end
4260

@@ -46,15 +64,15 @@ function primorial(n::Integer)
4664
end
4765
z = BigInt()
4866
ccall((:__gmpz_primorial_ui, :libgmp), Void,
49-
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
67+
(Ptr{BigInt}, UInt), &z, UInt(n))
5068
return z
5169
end
5270

53-
#Multinomial coefficient where n = sum(k)
71+
"Multinomial coefficient where n = sum(k)"
5472
function multinomial(k...)
5573
s = 0
5674
result = 1
57-
for i in k
75+
@inbounds for i in k
5876
s += i
5977
result *= binomial(s, i)
6078
end

src/numbers.jl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export bellnum,
99
lucasnum,
1010
stirlings1
1111

12-
# Returns the n-th Bell number
12+
"Returns the n-th Bell number"
1313
function bellnum(bn::Integer)
1414
if bn < 0
1515
throw(DomainError())
@@ -28,7 +28,7 @@ function bellnum(bn::Integer)
2828
return list[end]
2929
end
3030

31-
# Returns the n-th Catalan number
31+
"Returns the n-th Catalan number"
3232
function catalannum(bn::Integer)
3333
if bn<0
3434
throw(DomainError())
@@ -44,7 +44,7 @@ function fibonaccinum(n::Integer)
4444
end
4545
z = BigInt()
4646
ccall((:__gmpz_fib_ui, :libgmp), Void,
47-
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
47+
(Ptr{BigInt}, UInt), &z, UInt(n))
4848
return z
4949
end
5050

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

59-
#Computes Lassalle's sequence
60-
#OEIS entry A180874
59+
"""
60+
Computes Lassalle's sequence
61+
OEIS entry A180874
62+
"""
6163
function lassallenum(m::Integer)
6264
A = ones(BigInt,m)
6365
for n=2:m
@@ -79,11 +81,11 @@ function lucasnum(n::Integer)
7981
end
8082
z = BigInt()
8183
ccall((:__gmpz_lucnum_ui, :libgmp), Void,
82-
(Ptr{BigInt}, UInt), &z, @compat(UInt(n)))
84+
(Ptr{BigInt}, UInt), &z, UInt(n))
8385
return z
8486
end
8587

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

src/partitions.jl

Lines changed: 93 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#Partitions
22

3-
export cool_lex, integer_partitions, ncpartitions
3+
export
4+
cool_lex,
5+
integer_partitions,
6+
ncpartitions,
7+
partitions,
8+
prevprod
9+
#nextprod,
410

511

612
#integer partitions
@@ -11,12 +17,17 @@ end
1117

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

14-
partitions(n::Integer) = IntegerPartitions(n)
15-
1620
start(p::IntegerPartitions) = Int[]
1721
done(p::IntegerPartitions, xs) = length(xs) == p.n
1822
next(p::IntegerPartitions, xs) = (xs = nextpartition(p.n,xs); (xs,xs))
1923

24+
"""
25+
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))`.
26+
"""
27+
partitions(n::Integer) = IntegerPartitions(n)
28+
29+
30+
2031
function nextpartition(n, as)
2132
if isempty(as); return Int[n]; end
2233

@@ -77,6 +88,9 @@ end
7788

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

91+
"""
92+
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))`.
93+
"""
8094
partitions(n::Integer, m::Integer) = n >= 1 && m >= 1 ? FixedPartitions(n,m) : throw(DomainError())
8195

8296
start(f::FixedPartitions) = Int[]
@@ -139,6 +153,9 @@ end
139153

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

156+
"""
157+
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))`.
158+
"""
142159
partitions(s::AbstractVector) = SetPartitions(s)
143160

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

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

226+
"""
227+
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))`.
228+
"""
209229
partitions(s::AbstractVector,m::Int) = length(s) >= 1 && m >= 1 ? FixedSetPartitions(s,m) : throw(DomainError())
210230

211231
function start(p::FixedSetPartitions)
@@ -278,51 +298,59 @@ function nfixedsetpartitions(n::Int,m::Int)
278298
return numpart
279299
end
280300

281-
282-
# For a list of integers i1, i2, i3, find the smallest
283-
# i1^n1 * i2^n2 * i3^n3 >= x
284-
# for integer n1, n2, n3
285-
function nextprod(a::Vector{Int}, x)
286-
if x > typemax(Int)
287-
throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
288-
end
289-
k = length(a)
290-
v = ones(Int, k) # current value of each counter
291-
mx = [nextpow(ai,x) for ai in a] # maximum value of each counter
292-
v[1] = mx[1] # start at first case that is >= x
293-
p::widen(Int) = mx[1] # initial value of product in this case
294-
best = p
295-
icarry = 1
296-
297-
while v[end] < mx[end]
298-
if p >= x
299-
best = p < best ? p : best # keep the best found yet
300-
carrytest = true
301-
while carrytest
302-
p = div(p, v[icarry])
303-
v[icarry] = 1
304-
icarry += 1
305-
p *= a[icarry]
306-
v[icarry] *= a[icarry]
307-
carrytest = v[icarry] > mx[icarry] && icarry < k
308-
end
309-
if p < x
310-
icarry = 1
311-
end
312-
else
313-
while p < x
314-
p *= a[1]
315-
v[1] *= a[1]
316-
end
317-
end
318-
end
319-
best = mx[end] < best ? mx[end] : best
320-
return Int(best) # could overflow, but best to have predictable return type
321-
end
322-
323-
# For a list of integers i1, i2, i3, find the largest
324-
# i1^n1 * i2^n2 * i3^n3 <= x
325-
# for integer n1, n2, n3
301+
#This function is still defined in Base because it is being used by Base.DSP
302+
#"""
303+
#Next integer not less than `n` that can be written as $\prod k_i^{p_i}$ for integers $p_1$, $p_2$, etc.
304+
#
305+
#For a list of integers i1, i2, i3, find the smallest
306+
# i1^n1 * i2^n2 * i3^n3 >= x
307+
#for integer n1, n2, n3
308+
#"""
309+
#function nextprod(a::Vector{Int}, x)
310+
# if x > typemax(Int)
311+
# throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
312+
# end
313+
# k = length(a)
314+
# v = ones(Int, k) # current value of each counter
315+
# mx = [nextpow(ai,x) for ai in a] # maximum value of each counter
316+
# v[1] = mx[1] # start at first case that is >= x
317+
# p::widen(Int) = mx[1] # initial value of product in this case
318+
# best = p
319+
# icarry = 1
320+
#
321+
# while v[end] < mx[end]
322+
# if p >= x
323+
# best = p < best ? p : best # keep the best found yet
324+
# carrytest = true
325+
# while carrytest
326+
# p = div(p, v[icarry])
327+
# v[icarry] = 1
328+
# icarry += 1
329+
# p *= a[icarry]
330+
# v[icarry] *= a[icarry]
331+
# carrytest = v[icarry] > mx[icarry] && icarry < k
332+
# end
333+
# if p < x
334+
# icarry = 1
335+
# end
336+
# else
337+
# while p < x
338+
# p *= a[1]
339+
# v[1] *= a[1]
340+
# end
341+
# end
342+
# end
343+
# best = mx[end] < best ? mx[end] : best
344+
# return Int(best) # could overflow, but best to have predictable return type
345+
#end
346+
347+
"""
348+
Previous integer not greater than `n` that can be written as $\prod k_i^{p_i}$ for integers $p_1$, $p_2$, etc.
349+
350+
For a list of integers i1, i2, i3, find the largest
351+
i1^n1 * i2^n2 * i3^n3 <= x
352+
for integer n1, n2, n3
353+
"""
326354
function prevprod(a::Vector{Int}, x)
327355
if x > typemax(Int)
328356
throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
@@ -362,7 +390,7 @@ function prevprod(a::Vector{Int}, x)
362390
end
363391

364392

365-
# Lists the partitions of the number n, the order is consistent with GAP
393+
"Lists the partitions of the number n, the order is consistent with GAP"
366394
function integer_partitions(n::Integer)
367395
if n < 0
368396
throw(DomainError())
@@ -384,20 +412,22 @@ function integer_partitions(n::Integer)
384412
list
385413
end
386414

387-
# Produces (n,k)-combinations in cool-lex order
388-
#
389-
#Implements the cool-lex algorithm to generate (n,k)-combinations
390-
#@article{Ruskey:2009fk,
391-
# Author = {Frank Ruskey and Aaron Williams},
392-
# Doi = {10.1016/j.disc.2007.11.048},
393-
# Journal = {Discrete Mathematics},
394-
# Month = {September},
395-
# Number = {17},
396-
# Pages = {5305-5320},
397-
# Title = {The coolest way to generate combinations},
398-
# Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570},
399-
# Volume = {309},
400-
# Year = {2009}}
415+
"""
416+
Produces (n,k)-combinations in cool-lex order
417+
418+
Implements the cool-lex algorithm to generate (n,k)-combinations
419+
@article{Ruskey:2009fk,
420+
Author = {Frank Ruskey and Aaron Williams},
421+
Doi = {10.1016/j.disc.2007.11.048},
422+
Journal = {Discrete Mathematics},
423+
Month = {September},
424+
Number = {17},
425+
Pages = {5305-5320},
426+
Title = {The coolest way to generate combinations},
427+
Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570},
428+
Volume = {309},
429+
Year = {2009}}
430+
"""
401431
function cool_lex(n::Integer, t::Integer)
402432
s = n-t
403433
if n > 64 error("Not implemented for n > 64") end

0 commit comments

Comments
 (0)