Skip to content

Commit 3da9f40

Browse files
committed
Rewrite cool_lex using iterator protocol
1 parent 7045289 commit 3da9f40

File tree

3 files changed

+92
-49
lines changed

3 files changed

+92
-49
lines changed

src/combinations.jl

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export combinations
1+
export combinations, CoolLexCombinations
22

33
#The Combinations iterator
44

@@ -50,3 +50,85 @@ but sequence at each order is lazy
5050
"""
5151
combinations(a) = chain([combinations(a,k) for k=1:length(a)]...)
5252

53+
54+
55+
# cool-lex combinations iterator
56+
57+
"""
58+
Produces (n,k)-combinations in cool-lex order
59+
60+
Implements the cool-lex algorithm to generate (n,k)-combinations
61+
@article{Ruskey:2009fk,
62+
Author = {Frank Ruskey and Aaron Williams},
63+
Doi = {10.1016/j.disc.2007.11.048},
64+
Journal = {Discrete Mathematics},
65+
Month = {September},
66+
Number = {17},
67+
Pages = {5305-5320},
68+
Title = {The coolest way to generate combinations},
69+
Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570},
70+
Volume = {309},
71+
Year = {2009}}
72+
"""
73+
immutable CoolLexCombinations
74+
n :: Int
75+
t :: Int
76+
end
77+
78+
immutable CoolLexIterState{T<:Integer}
79+
R0:: T
80+
R1:: T
81+
R2:: T
82+
R3:: T
83+
end
84+
85+
function start(C::CoolLexCombinations)
86+
if C.n < 0
87+
throw(DomainError())
88+
end
89+
if C.t 0
90+
throw(DomainError())
91+
end
92+
93+
#What integer size should I use?
94+
if C.n < 8sizeof(Int)
95+
T = Int
96+
else
97+
T = BigInt
98+
end
99+
100+
CoolLexIterState{T}(0, 0, T(1) << C.n, (T(1) << C.t) - 1)
101+
end
102+
103+
function next(C::CoolLexCombinations, S::CoolLexIterState)
104+
R0 = S.R0
105+
R1 = S.R1
106+
R2 = S.R2
107+
R3 = S.R3
108+
109+
R0 = R3 & (R3 + 1)
110+
R1 = R0 $ (R0 - 1)
111+
R0 = R1 + 1
112+
R1 &= R3
113+
R0 = max((R0 & R3) - 1, 0)
114+
R3 += R1 - R0
115+
116+
_cool_lex_visit(S.R3), CoolLexIterState(R0, R1, R2, R3)
117+
end
118+
119+
#Converts an integer bit pattern X into a subset
120+
#If X & 2^k == 1, then k is in the subset
121+
function _cool_lex_visit(X::Int)
122+
subset = Int[]
123+
n=1
124+
while X != 0
125+
if X & 1 == 1 push!(subset, n) end
126+
X >>= 1
127+
n += 1
128+
end
129+
subset
130+
end
131+
132+
done(C::CoolLexCombinations, S::CoolLexIterState) = (S.R3 & S.R2 != 0)
133+
134+
length(C::CoolLexCombinations) = max(0, binomial(C.n, C.t))

src/partitions.jl

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#Partitions
22

33
export
4-
cool_lex,
54
integer_partitions,
65
ncpartitions,
76
partitions,
@@ -412,52 +411,9 @@ function integer_partitions(n::Integer)
412411
list
413412
end
414413

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-
"""
431-
function cool_lex(n::Integer, t::Integer)
432-
s = n-t
433-
if n > 64 error("Not implemented for n > 64") end
434-
if t < 1 error("Need t>1") end
435-
R0::Int64=R1::Int64=0
436-
R2::Int64 = 1 << (s+t)
437-
R3::Int64 = (1 << t) - 1
438-
while R3 & R2 == 0
439-
produce(visit(R3))
440-
R0 = R3 & (R3 + 1)
441-
R1 = R0 $ (R0 - 1)
442-
R0 = R1 + 1
443-
R1 &= R3
444-
R0 = max((R0 & R3) - 1, 0)
445-
R3 += R1 - R0
446-
end
447-
end
448414

449-
#Converts an integer word X into a subset
450-
#If X & 2^k == 1, then k is in the subset
451-
function visit(X::Integer)
452-
subset = Int[]
453-
n::Int=1
454-
while X != 0
455-
if X & 1 == 1 push!(subset, n) end
456-
X >>= 1
457-
n += 1
458-
end
459-
subset
460-
end
415+
416+
#Noncrossing partitions
461417

462418
#Produces noncrossing partitions of length n
463419
ncpartitions(n::Integer)=ncpart(1,n,n,Any[])

test/combinations.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import Combinatorics: combinations
1010
@test collect(combinations("abc",3)) == Any[['a','b','c']]
1111
@test collect(combinations("abc",2)) == Any[['a','b'],['a','c'],['b','c']]
1212
@test collect(combinations("abc",1)) == Any[['a'],['b'],['c']]
13-
@test collect(combinations("abc",0)) == Any[Char[]]
14-
@test collect(combinations("abc",-1)) == Any[]
13+
@test collect(combinations("abc",0)) == Any[[]]
14+
@test collect(combinations("abc",-1)) == []
1515

1616
@test collect(filter(x->(iseven(x[1])),combinations([1,2,3],2))) == Any[[2,3]]
1717

18+
#cool-lex iterator
19+
@test_throws DomainError collect(CoolLexCombinations(-1, 1))
20+
@test_throws DomainError collect(CoolLexCombinations(5, 0))
21+
@test collect(CoolLexCombinations(4,2)) == Vector[[1,2], [2,3], [1,3], [2,4], [3,4], [1,4]]
22+

0 commit comments

Comments
 (0)