Skip to content

Commit

Permalink
Updates for Julia 0.6 and 0.7 (#62)
Browse files Browse the repository at this point in the history
Also includes general stylistic cleanup and an overhaul of the Young
diagram functionality to avoid type piracy.

Fixes #61.
  • Loading branch information
ararslan authored Mar 31, 2018
1 parent aaaf5f4 commit 1403f71
Show file tree
Hide file tree
Showing 19 changed files with 534 additions and 373 deletions.
9 changes: 4 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ language: julia
os:
- linux
julia:
- 0.5
- 0.6
- nightly
sudo: false
notifications:
email: false
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd())'
- julia -e 'Pkg.test("Combinatorics", coverage=true)'
#script:
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
# - julia -e 'Pkg.clone(pwd())'
# - julia -e 'Pkg.test("Combinatorics", coverage=true)'
after_success:
- julia -e 'Pkg.add("Coverage"); cd(Pkg.dir("Combinatorics")); using Coverage; Coveralls.submit(Coveralls.process_folder()); Codecov.submit(process_folder())'
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Combinatorics

[![Combinatorics](http://pkg.julialang.org/badges/Combinatorics_0.5.svg)](http://pkg.julialang.org/?pkg=Combinatorics)
[![Combinatorics](http://pkg.julialang.org/badges/Combinatorics_0.6.svg)](http://pkg.julialang.org/?pkg=Combinatorics)
[![Combinatorics](http://pkg.julialang.org/badges/Combinatorics_0.7.svg)](http://pkg.julialang.org/?pkg=Combinatorics)
[![Build Status](https://travis-ci.org/JuliaMath/Combinatorics.jl.svg?branch=master)](https://travis-ci.org/JuliaMath/Combinatorics.jl)
[![Coverage Status](https://coveralls.io/repos/github/JuliaMath/Combinatorics.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaMath/Combinatorics.jl?branch=master)
[![Codecov](https://codecov.io/gh/JuliaMath/Combinatorics.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaMath/Combinatorics.jl)
Expand Down
4 changes: 2 additions & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
julia 0.5
Compat 0.18.0
julia 0.6
Compat 0.59.0
Polynomials
IterTools
14 changes: 3 additions & 11 deletions src/Combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,9 @@ __precompile__(true)

module Combinatorics

using Compat, Polynomials, IterTools

import Base: start, next, done, length, eltype

#These 8 functions were removed from Julia 0.5 as part of JuliaLang/julia#13897,
#so check if it's necessary to import them to overload the stub methods left in
#Base. Only do this if on a version of Julia post-combinatorics removal.
if isdefined(Base, :combinations) && VERSION >= v"0.5.0-dev+1204"
import Base: combinations, partitions, prevprod, levicivita, nthperm,
nthperm!, parity, permutations
end
using Compat
using Polynomials
using IterTools

include("numbers.jl")
include("factorials.jl")
Expand Down
153 changes: 82 additions & 71 deletions src/combinations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,92 +5,93 @@ export combinations,

#The Combinations iterator

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

start(c::Combinations) = [1:c.t;]
function next(c::Combinations, s)
Base.start(c::Combinations) = collect(1:c.t)
function Base.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])
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))
if s[i] > (length(c.a) - (length(s) - i))
continue
end
for j = i+1:endof(s)
for j = i+1:lastindex(s)
s[j] = s[j-1]+1
end
break
end
(comb,s)
(comb, s)
end
done(c::Combinations, s) = !isempty(s) && s[1] > length(c.a)-c.t+1
Base.done(c::Combinations, s) = !isempty(s) && s[1] > length(c.a) - c.t + 1

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

length(c::Combinations) = binomial(length(c.a),c.t)
Base.eltype(::Type{Combinations{T}}) where {T} = Vector{eltype(T)}

eltype{T}(::Type{Combinations{T}}) = Vector{eltype(T)}
"""
combinations(a, n)
"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.
"
Generate all combinations of `n` elements from an indexable object `a`. Because the number
of combinations can be very large, this function returns an iterator object.
Use `collect(combinations(a, 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
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)
Generate combinations of the elements of `a` of all orders. Chaining of order iterators
is eager, but the sequence at each order is lazy.
"""
combinations(a) = chain([combinations(a,k) for k=1:length(a)]...)
combinations(a) = IterTools.chain([combinations(a, k) for k = 1:length(a)]...)



# cool-lex combinations iterator

"""
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}}
CoolLexCombinations
Produce ``(n,k)``-combinations in cool-lex order.
# Reference
Ruskey, F., & Williams, A. (2009). The coolest way to generate combinations.
*Discrete Mathematics*, 309(17), 5305-5320.
"""
immutable CoolLexCombinations
n :: Int
t :: Int
struct CoolLexCombinations
n::Int
t::Int
end

immutable CoolLexIterState{T<:Integer}
R0:: T
R1:: T
R2:: T
R3:: T
struct CoolLexIterState{T<:Integer}
R0::T
R1::T
R2::T
R3::T
end

function start(C::CoolLexCombinations)
function Base.start(C::CoolLexCombinations)
if C.n < 0
throw(DomainError())
throw(DomainError(C.n))
end
if C.t 0
throw(DomainError())
throw(DomainError(C.t))
end

#What integer size should I use?
Expand All @@ -103,7 +104,7 @@ function start(C::CoolLexCombinations)
CoolLexIterState{T}(0, 0, T(1) << C.n, (T(1) << C.t) - 1)
end

function next(C::CoolLexCombinations, S::CoolLexIterState)
function Base.next(C::CoolLexCombinations, S::CoolLexIterState)
R0 = S.R0
R1 = S.R1
R2 = S.R2
Expand All @@ -122,36 +123,36 @@ end
#Converts an integer bit pattern X into a subset
#If X & 2^k == 1, then k is in the subset
function _cool_lex_visit(X::Integer)
subset = Int[]
n=1
while X != 0
if X & 1 == 1 push!(subset, n) end
X >>= 1
n += 1
end
subset
subset = Int[]
n = 1
while X != 0
X & 1 == 1 && push!(subset, n)
X >>= 1
n += 1
end
subset
end

done(C::CoolLexCombinations, S::CoolLexIterState) = (S.R3 & S.R2 != 0)
Base.done(C::CoolLexCombinations, S::CoolLexIterState) = (S.R3 & S.R2 != 0)

length(C::CoolLexCombinations) = max(0, binomial(C.n, C.t))
Base.length(C::CoolLexCombinations) = max(0, binomial(C.n, C.t))


immutable MultiSetCombinations{T}
struct MultiSetCombinations{T}
m::T
f::Vector{Int}
t::Int
ref::Vector{Int}
end

eltype{T}(::Type{MultiSetCombinations{T}}) = Vector{eltype(T)}
Base.eltype(::Type{MultiSetCombinations{T}}) where {T} = Vector{eltype(T)}

function length(c::MultiSetCombinations)
function Base.length(c::MultiSetCombinations)
t = c.t
if t > length(c.ref)
return 0
end
p = [1; zeros(Int,t)]
p = [1; zeros(Int, t)]
for i in 1:length(c.f)
f = c.f[i]
if i == 1
Expand All @@ -167,7 +168,7 @@ function length(c::MultiSetCombinations)
return p[t+1]
end

function multiset_combinations{T<:Integer}(m, f::Vector{T}, t::Integer)
function multiset_combinations(m, f::Vector{<:Integer}, t::Integer)
length(m) == length(f) || error("Lengths of m and f are not the same.")
ref = length(f) > 0 ? vcat([[i for j in 1:f[i] ] for i in 1:length(f)]...) : Int[]
if t < 0
Expand All @@ -176,15 +177,19 @@ function multiset_combinations{T<:Integer}(m, f::Vector{T}, t::Integer)
MultiSetCombinations(m, f, t, ref)
end

"generate all combinations of size t from an array a with possibly duplicated elements."
function multiset_combinations{T}(a::T, t::Integer)
"""
multiset_combinations(a, t)
Generate all combinations of size `t` from an array `a` with possibly duplicated elements.
"""
function multiset_combinations(a, t::Integer)
m = unique(collect(a))
f = Int[sum([c == x for c in a]) for x in m]
multiset_combinations(m, f, t)
end

start(c::MultiSetCombinations) = c.ref
function next(c::MultiSetCombinations, s)
Base.start(c::MultiSetCombinations) = c.ref
function Base.next(c::MultiSetCombinations, s)
ref = c.ref
n = length(ref)
t = c.t
Expand All @@ -195,7 +200,9 @@ function next(c::MultiSetCombinations, s)
for i in t:-1:1
if s[i] < ref[i + (n - t)]
j = 1
while ref[j] <= s[i]; j += 1; end
while ref[j] <= s[i]
j += 1
end
s[i] = ref[j]
for l in (i+1):t
s[l] = ref[j+=1]
Expand All @@ -210,23 +217,27 @@ function next(c::MultiSetCombinations, s)
end
(comb, s)
end
done(c::MultiSetCombinations, s) =
(!isempty(s) && max(s[1], c.t) > length(c.ref)) || (isempty(s) && c.t > 0)
Base.done(c::MultiSetCombinations, s) =
(!isempty(s) && max(s[1], c.t) > length(c.ref)) || (isempty(s) && c.t > 0)

immutable WithReplacementCombinations{T}
struct WithReplacementCombinations{T}
a::T
t::Int
end

eltype{T}(::Type{WithReplacementCombinations{T}}) = Vector{eltype(T)}
Base.eltype(::Type{WithReplacementCombinations{T}}) where {T} = Vector{eltype(T)}

Base.length(c::WithReplacementCombinations) = binomial(length(c.a) + c.t - 1, c.t)

length(c::WithReplacementCombinations) = binomial(length(c.a)+c.t-1, c.t)
"""
with_replacement_combinations(a, t)
"generate all combinations with replacement of size t from an array a."
Generate all combinations with replacement of size `t` from an array `a`.
"""
with_replacement_combinations(a, t::Integer) = WithReplacementCombinations(a, t)

start(c::WithReplacementCombinations) = [1 for i in 1:c.t]
function next(c::WithReplacementCombinations, s)
Base.start(c::WithReplacementCombinations) = [1 for i in 1:c.t]
function Base.next(c::WithReplacementCombinations, s)
n = length(c.a)
t = c.t
comb = [c.a[si] for si in s]
Expand All @@ -249,4 +260,4 @@ function next(c::WithReplacementCombinations, s)
end
(comb, s)
end
done(c::WithReplacementCombinations, s) = !isempty(s) && s[1] > length(c.a) || c.t < 0
Base.done(c::WithReplacementCombinations, s) = !isempty(s) && s[1] > length(c.a) || c.t < 0
Loading

0 comments on commit 1403f71

Please sign in to comment.