|
1 | | -export combinations |
| 1 | +export combinations, CoolLexCombinations |
2 | 2 |
|
3 | 3 | #The Combinations iterator |
4 | 4 |
|
@@ -50,3 +50,85 @@ but sequence at each order is lazy |
50 | 50 | """ |
51 | 51 | combinations(a) = chain([combinations(a,k) for k=1:length(a)]...) |
52 | 52 |
|
| 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)) |
0 commit comments