diff --git a/.travis.yml b/.travis.yml index f7d5910..7ed9138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ language: julia os: - linux julia: - - 0.6 + - 0.7 + - 1.0 - nightly sudo: false notifications: diff --git a/REQUIRE b/REQUIRE index 849d7d9..447f6e5 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,2 @@ -julia 0.6 -Compat 0.59.0 +julia 0.7 Polynomials -IterTools diff --git a/src/Combinatorics.jl b/src/Combinatorics.jl index 9c5d610..ce6d978 100644 --- a/src/Combinatorics.jl +++ b/src/Combinatorics.jl @@ -2,9 +2,7 @@ VERSION < v"0.7.0-beta2.199" && __precompile__() module Combinatorics -using Compat using Polynomials -using IterTools include("numbers.jl") include("factorials.jl") diff --git a/src/combinations.jl b/src/combinations.jl index d2fa9b2..bc8898d 100644 --- a/src/combinations.jl +++ b/src/combinations.jl @@ -11,8 +11,9 @@ struct Combinations{T} t::Int end -Base.start(c::Combinations) = collect(1:c.t) -function Base.next(c::Combinations, s) +function Base.iterate(c::Combinations, s = collect(1:c.t)) + (!isempty(s) && s[1] > length(c.a) - c.t + 1) && return + comb = [c.a[si] for si in s] if c.t == 0 # special case to generate 1 result for t==0 @@ -31,7 +32,6 @@ function Base.next(c::Combinations, s) end (comb, s) end -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) @@ -59,7 +59,7 @@ end 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) = IterTools.chain([combinations(a, k) for k = 1:length(a)]...) +combinations(a) = Iterators.flatten([combinations(a, k) for k = 1:length(a)]) @@ -87,7 +87,7 @@ struct CoolLexIterState{T<:Integer} R3::T end -function Base.start(C::CoolLexCombinations) +function Base.iterate(C::CoolLexCombinations) if C.n < 0 throw(DomainError(C.n)) end @@ -102,10 +102,13 @@ function Base.start(C::CoolLexCombinations) T = BigInt end - CoolLexIterState{T}(0, 0, T(1) << C.n, (T(1) << C.t) - 1) + state = CoolLexIterState{T}(0, 0, T(1) << C.n, (T(1) << C.t) - 1) + iterate(C, state) end -function Base.next(C::CoolLexCombinations, S::CoolLexIterState) +function Base.iterate(C::CoolLexCombinations, S::CoolLexIterState) + (S.R3 & S.R2 != 0) && return + R0 = S.R0 R1 = S.R1 R2 = S.R2 @@ -134,8 +137,6 @@ function _cool_lex_visit(X::Integer) subset end -Base.done(C::CoolLexCombinations, S::CoolLexIterState) = (S.R3 & S.R2 != 0) - Base.length(C::CoolLexCombinations) = max(0, binomial(C.n, C.t)) @@ -189,8 +190,9 @@ function multiset_combinations(a, t::Integer) multiset_combinations(m, f, t) end -Base.start(c::MultiSetCombinations) = c.ref -function Base.next(c::MultiSetCombinations, s) +function Base.iterate(c::MultiSetCombinations, s = c.ref) + ((!isempty(s) && max(s[1], c.t) > length(c.ref)) || (isempty(s) && c.t > 0)) && return + ref = c.ref n = length(ref) t = c.t @@ -218,8 +220,6 @@ function Base.next(c::MultiSetCombinations, s) end (comb, s) end -Base.done(c::MultiSetCombinations, s) = - (!isempty(s) && max(s[1], c.t) > length(c.ref)) || (isempty(s) && c.t > 0) struct WithReplacementCombinations{T} a::T @@ -237,8 +237,9 @@ Generate all combinations with replacement of size `t` from an array `a`. """ with_replacement_combinations(a, t::Integer) = WithReplacementCombinations(a, t) -Base.start(c::WithReplacementCombinations) = [1 for i in 1:c.t] -function Base.next(c::WithReplacementCombinations, s) +function Base.iterate(c::WithReplacementCombinations, s = [1 for i in 1:c.t]) + (!isempty(s) && s[1] > length(c.a) || c.t < 0) && return + n = length(c.a) t = c.t comb = [c.a[si] for si in s] @@ -261,7 +262,6 @@ function Base.next(c::WithReplacementCombinations, s) end (comb, s) end -Base.done(c::WithReplacementCombinations, s) = !isempty(s) && s[1] > length(c.a) || c.t < 0 ## Power set @@ -276,5 +276,5 @@ subsets. function powerset(a, min::Integer=0, max::Integer=length(a)) itrs = [combinations(a, k) for k = min:max] min < 1 && append!(itrs, eltype(a)[]) - IterTools.chain(itrs...) + Iterators.flatten(itrs) end diff --git a/src/multinomials.jl b/src/multinomials.jl index f43191c..3f2dfd2 100644 --- a/src/multinomials.jl +++ b/src/multinomials.jl @@ -8,12 +8,12 @@ struct MultiExponents{T} nterms::Int end -Base.start(m::MultiExponents) = start(m.c) - # Standard stars and bars: # https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics) -function Base.next(m::MultiExponents, s) - stars, ss = next(m.c, s) +function Base.iterate(m::MultiExponents, s = nothing) + next = s === nothing ? iterate(m.c) : iterate(m.c, s) + next === nothing && return + stars, ss = next # stars minus their consecutive # position becomes their index @@ -25,8 +25,6 @@ function Base.next(m::MultiExponents, s) result, ss end -Base.done(m::MultiExponents, s) = done(m.c, s) - Base.length(m::MultiExponents) = length(m.c) """ diff --git a/src/partitions.jl b/src/partitions.jl index 78f2630..f84ead1 100644 --- a/src/partitions.jl +++ b/src/partitions.jl @@ -16,9 +16,11 @@ end Base.length(p::IntegerPartitions) = npartitions(p.n) -Base.start(p::IntegerPartitions) = Int[] -Base.done(p::IntegerPartitions, xs) = length(xs) == p.n -Base.next(p::IntegerPartitions, xs) = (xs = nextpartition(p.n,xs); (xs,xs)) +function Base.iterate(p::IntegerPartitions, xs = Int[]) + length(xs) == p.n && return + xs = nextpartition(p.n,xs) + (xs, xs) +end """ partitions(n) @@ -105,13 +107,15 @@ partitions(n::Integer, m::Integer) = FixedPartitions(n, m) : throw(DomainError((n, m), "n and m must be positive")) -Base.start(f::FixedPartitions) = Int[] -function Base.done(f::FixedPartitions, s::Vector{Int}) - f.m <= f.n || return true - isempty(s) && return false - return f.m == 1 || s[1]-1 <= s[end] +function Base.iterate(f::FixedPartitions, s::Vector{Int} = Int[]) + f.m <= f.n || return + if !isempty(s) + (f.m == 1 || s[1]-1 <= s[end]) && return + end + + xs = nextfixedpartition(f.n,f.m,s) + (xs, xs) end -Base.next(f::FixedPartitions, s::Vector{Int}) = (xs = nextfixedpartition(f.n,f.m,s); (xs,xs)) function nextfixedpartition(n, m, bs) as = copy(bs) @@ -177,9 +181,14 @@ number of partitions to generate can be efficiently computed using """ partitions(s::AbstractVector) = SetPartitions(s) -Base.start(p::SetPartitions) = (n = length(p.s); (zeros(Int32, n), ones(Int32, n-1), n, 1)) -Base.done(p::SetPartitions, s) = s[1][1] > 0 -Base.next(p::SetPartitions, s) = nextsetpartition(p.s, s...) +function Base.iterate(p::SetPartitions) + n = length(p.s) + iterate(p, (zeros(Int32, n), ones(Int32, n-1), n, 1)) +end +function Base.iterate(p::SetPartitions, s) + s[1][1] > 0 && return + nextsetpartition(p.s, s...) +end function nextsetpartition(s::AbstractVector, a, b, n, m) function makeparts(s, a, m) @@ -255,18 +264,22 @@ partitions(s::AbstractVector, m::Int) = FixedSetPartitions(s, m) : throw(DomainError((length(s), m), "length(s) and m must be positive")) -function Base.start(p::FixedSetPartitions) +function Base.iterate(p::FixedSetPartitions) n = length(p.s) m = p.m - m <= n ? (vcat(ones(Int, n-m),1:m), vcat(1,n-m+2:n), n) : (Int[], Int[], n) + state = m <= n ? (vcat(ones(Int, n-m),1:m), vcat(1,n-m+2:n), n) : (Int[], Int[], n) + # state consists of: + # vector a of length n describing to which partition every element of s belongs + # vector b of length n describing the first index b[i] that belongs to partition i + # integer n + + iterate(p, state) end -# state consists of: -# vector a of length n describing to which partition every element of s belongs -# vector b of length n describing the first index b[i] that belongs to partition i -# integer n -Base.done(p::FixedSetPartitions, s) = isempty(s[1]) || s[1][1] > 1 -Base.next(p::FixedSetPartitions, s) = nextfixedsetpartition(p.s,p.m, s...) +function Base.iterate(p::FixedSetPartitions, s) + (isempty(s[1]) || s[1][1] > 1) && return + nextfixedsetpartition(p.s,p.m, s...) +end function nextfixedsetpartition(s::AbstractVector, m, a, b, n) function makeparts(s, a) @@ -310,7 +323,7 @@ function nextfixedsetpartition(s::AbstractVector, m, a, b, n) end b[k] -= 1 b[k+1:m] = n-m+k+1:n - a[1:n] = 1 + a[1:n] .= 1 a[b] = 1:m end end @@ -496,4 +509,3 @@ function _ncpart!(a::Int, b::Int, nn::Int, x::Vector, partitions::Vector) end end end - diff --git a/src/permutations.jl b/src/permutations.jl index 7d3bf80..e1035b0 100644 --- a/src/permutations.jl +++ b/src/permutations.jl @@ -39,8 +39,10 @@ function permutations(a, t::Integer) Permutations(a, t) end -Base.start(p::Permutations) = collect(1:length(p.a)) -Base.next(p::Permutations, s) = nextpermutation(p.a, p.t ,s) +function Base.iterate(p::Permutations, s = collect(1:length(p.a))) + (!isempty(s) && max(s[1], p.t) > length(p.a) || (isempty(s) && p.t > 0)) && return + nextpermutation(p.a, p.t ,s) +end function nextpermutation(m, t, state) perm = [m[state[i]] for i in 1:t] @@ -73,8 +75,6 @@ function nextpermutation(m, t, state) return (perm, s) end -Base.done(p::Permutations, s) = !isempty(s) && max(s[1], p.t) > length(p.a) || (isempty(s) && p.t > 0) - struct MultiSetPermutations{T} m::T f::Vector{Int} @@ -134,11 +134,10 @@ function multiset_permutations(m, f::Vector{<:Integer}, t::Integer) MultiSetPermutations(m, f, t, ref) end -Base.start(p::MultiSetPermutations) = p.ref -Base.next(p::MultiSetPermutations, s) = nextpermutation(p.m, p.t, s) -Base.done(p::MultiSetPermutations, s) = - !isempty(s) && max(s[1], p.t) > length(p.ref) || (isempty(s) && p.t > 0) - +function Base.iterate(p::MultiSetPermutations, s = p.ref) + (!isempty(s) && max(s[1], p.t) > length(p.ref) || (isempty(s) && p.t > 0)) && return + nextpermutation(p.m, p.t, s) +end """ @@ -195,9 +194,9 @@ end # Parity of permutations -const levicivita_lut = cat(3, [0 0 0; 0 0 1; 0 -1 0], - [0 0 -1; 0 0 0; 1 0 0], - [0 1 0; -1 0 0; 0 0 0]) +const levicivita_lut = cat([0 0 0; 0 0 1; 0 -1 0], + [0 0 -1; 0 0 0; 1 0 0], + [0 1 0; -1 0 0; 0 0 0]; dims=3) """ levicivita(p) diff --git a/src/youngdiagrams.jl b/src/youngdiagrams.jl index c123ed5..232f6a3 100644 --- a/src/youngdiagrams.jl +++ b/src/youngdiagrams.jl @@ -52,10 +52,10 @@ function isrimhook(ξ::SkewDiagram) l = maximum(λ.x) youngdiagram = zeros(Int, m, l) for i = 1:n - youngdiagram[i, μ[i]+1:λ[i]] = 1 + youngdiagram[i, μ[i]+1:λ[i]] .= 1 end for i = n+1:m - youngdiagram[i, 1:λ[i]] = 1 + youngdiagram[i, 1:λ[i]] .= 1 end #Condition 1. Must be edgewise connected youngdiagramList = Any[] @@ -114,10 +114,10 @@ function leglength(ξ::SkewDiagram) l = maximum(λ.x) youngdiagram = zeros(Int, m, l) for i = 1:n - youngdiagram[i, μ[i]+1:λ[i]] = 1 + youngdiagram[i, μ[i]+1:λ[i]] .= 1 end for i = n+1:m - youngdiagram[i, 1:λ[i]] = 1 + youngdiagram[i, 1:λ[i]] .= 1 end for i = m:-1:1 any(==(1), youngdiagram[i,:]) && return i-1 diff --git a/test/combinations.jl b/test/combinations.jl index 2d9af48..ea5c655 100644 --- a/test/combinations.jl +++ b/test/combinations.jl @@ -1,7 +1,3 @@ -using Combinatorics -using Compat -using Compat.Test - @test [combinations([])...] == [] @test [combinations(['a', 'b', 'c'])...] == Any[['a'],['b'],['c'],['a','b'],['a','c'],['b','c'],['a','b','c']] @@ -38,7 +34,7 @@ using Compat.Test @test_throws DomainError [CoolLexCombinations(-1, 1)...] @test_throws DomainError [CoolLexCombinations(5, 0)...] @test [CoolLexCombinations(4,2)...] == Vector[[1,2], [2,3], [1,3], [2,4], [3,4], [1,4]] -@test isa(start(CoolLexCombinations(1000, 20)), Combinatorics.CoolLexIterState{BigInt}) +@test isa(iterate(CoolLexCombinations(1000, 20))[2], Combinatorics.CoolLexIterState{BigInt}) # Power set @test collect(powerset([])) == Any[[]] diff --git a/test/factorials.jl b/test/factorials.jl index 8c00508..8188e02 100644 --- a/test/factorials.jl +++ b/test/factorials.jl @@ -1,7 +1,3 @@ -using Combinatorics -using Compat -using Compat.Test - @test factorial(7,3) == 7*6*5*4 @test_throws DomainError factorial(3,7) @test_throws DomainError factorial(-3,-7) diff --git a/test/multinomials.jl b/test/multinomials.jl index b7a4a90..141f72b 100644 --- a/test/multinomials.jl +++ b/test/multinomials.jl @@ -1,7 +1,4 @@ -using Combinatorics -using Compat -using Compat.Test -using Compat.LinearAlgebra +using LinearAlgebra # degenerate cases (x₁ + x₂ + ⋯ + xₘ)¹ @test [multiexponents(1,1)...] == [[1]] diff --git a/test/numbers.jl b/test/numbers.jl index 0db8c28..893a041 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1,7 +1,3 @@ -using Combinatorics -using Compat -using Compat.Test - # catalan @test catalannum(5) == 42 @test catalannum(30) == parse(BigInt,"3814986502092304") diff --git a/test/partitions.jl b/test/partitions.jl index a60e290..bc06805 100644 --- a/test/partitions.jl +++ b/test/partitions.jl @@ -1,7 +1,3 @@ -using Combinatorics -using Compat -using Compat.Test - @test collect(partitions(4)) == Any[[4], [3,1], [2,2], [2,1,1], [1,1,1,1]] @test collect(partitions(8,3)) == Any[[6,1,1], [5,2,1], [4,3,1], [4,2,2], [3,3,2]] @test collect(partitions(8, 1)) == Any[[8]] diff --git a/test/permutations.jl b/test/permutations.jl index b7ff7ba..b30251b 100644 --- a/test/permutations.jl +++ b/test/permutations.jl @@ -1,13 +1,9 @@ -using Combinatorics -using Compat -using Compat.Test - # permutations @test collect(permutations("abc")) == Any[['a','b','c'],['a','c','b'],['b','a','c'], ['b','c','a'],['c','a','b'],['c','b','a']] -@test collect(Compat.Iterators.filter(x->(iseven(x[1])),permutations([1,2,3]))) == Any[[2,1,3],[2,3,1]] -@test collect(Compat.Iterators.filter(x->(iseven(x[3])),permutations([1,2,3]))) == Any[[1,3,2],[3,1,2]] +@test collect(Iterators.filter(x->(iseven(x[1])),permutations([1,2,3]))) == Any[[2,1,3],[2,3,1]] +@test collect(Iterators.filter(x->(iseven(x[3])),permutations([1,2,3]))) == Any[[1,3,2],[3,1,2]] @test length(permutations(0)) == 1 diff --git a/test/runtests.jl b/test/runtests.jl index e2bcf72..d790670 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,5 @@ using Combinatorics -using Compat -using Compat.Test +using Test include("numbers.jl") include("factorials.jl") diff --git a/test/youngdiagrams.jl b/test/youngdiagrams.jl index 4948115..9a19684 100644 --- a/test/youngdiagrams.jl +++ b/test/youngdiagrams.jl @@ -1,7 +1,3 @@ -using Combinatorics -using Compat -using Compat.Test - let λ = Partition([5,4,2,2]), μ = Partition([2,1]) @test λ \ μ == SkewDiagram(λ, μ) @test leglength(λ, μ) == leglength(λ \ μ) == 3