|
| 1 | +#Generative algorithms |
| 2 | + |
| 3 | +import Base: integer_partitions |
| 4 | + |
| 5 | +export cool_lex, ncpartitions |
| 6 | + |
| 7 | +# Lists the partitions of the number n, the order is consistent with GAP |
| 8 | +function integer_partitions(n::Integer) |
| 9 | + if n < 0 |
| 10 | + throw(DomainError()) |
| 11 | + elseif n == 0 |
| 12 | + return Vector{Int}[] |
| 13 | + elseif n == 1 |
| 14 | + return Vector{Int}[[1]] |
| 15 | + end |
| 16 | + |
| 17 | + list = Vector{Int}[] |
| 18 | + |
| 19 | + for p in integer_partitions(n-1) |
| 20 | + push!(list, [p, 1]) |
| 21 | + if length(p) == 1 || p[end] < p[end-1] |
| 22 | + push!(list, [p[1:end-1], p[end]+1]) |
| 23 | + end |
| 24 | + end |
| 25 | + |
| 26 | + list |
| 27 | +end |
| 28 | + |
| 29 | +# Produces (n,k)-combinations in cool-lex order |
| 30 | +# |
| 31 | +#Implements the cool-lex algorithm to generate (n,k)-combinations |
| 32 | +#@article{Ruskey:2009fk, |
| 33 | +# Author = {Frank Ruskey and Aaron Williams}, |
| 34 | +# Doi = {10.1016/j.disc.2007.11.048}, |
| 35 | +# Journal = {Discrete Mathematics}, |
| 36 | +# Month = {September}, |
| 37 | +# Number = {17}, |
| 38 | +# Pages = {5305-5320}, |
| 39 | +# Title = {The coolest way to generate combinations}, |
| 40 | +# Url = {http://www.sciencedirect.com/science/article/pii/S0012365X07009570}, |
| 41 | +# Volume = {309}, |
| 42 | +# Year = {2009}} |
| 43 | +function cool_lex(n::Integer, t::Integer) |
| 44 | + s = n-t |
| 45 | + if n > 64 error("Not implemented for n > 64") end |
| 46 | + if t < 1 error("Need t>1") end |
| 47 | + R0::Int64=R1::Int64=0 |
| 48 | + R2::Int64 = 1 << (s+t) |
| 49 | + R3::Int64 = (1 << t) - 1 |
| 50 | + while R3 & R2 == 0 |
| 51 | + produce(visit(R3)) |
| 52 | + R0 = R3 & (R3 + 1) |
| 53 | + R1 = R0 $ (R0 - 1) |
| 54 | + R0 = R1 + 1 |
| 55 | + R1 &= R3 |
| 56 | + R0 = max((R0 & R3) - 1, 0) |
| 57 | + R3 += R1 - R0 |
| 58 | + end |
| 59 | +end |
| 60 | + |
| 61 | +#Converts an integer word X into a subset |
| 62 | +#If X & 2^k == 1, then k is in the subset |
| 63 | +function visit(X::Integer) |
| 64 | + subset = Int[] |
| 65 | + n::Int=1 |
| 66 | + while X != 0 |
| 67 | + if X & 1 == 1 push!(subset, n) end |
| 68 | + X >>= 1 |
| 69 | + n += 1 |
| 70 | + end |
| 71 | + subset |
| 72 | +end |
| 73 | + |
| 74 | +#Produces noncrossing partitions of length n |
| 75 | +ncpartitions(n::Integer)=ncpart(1,n,n,{}) |
| 76 | +function ncpart(a::Integer, b::Integer, nn::Integer, |
| 77 | + x::Array{Any,1}) |
| 78 | + n=b-a+1 |
| 79 | + for k=1:n |
| 80 | + for root in @task cool_lex(n, k) |
| 81 | + root += a-1 |
| 82 | + #Abort if construction is out of lex order |
| 83 | + if length(x)>0 && x[end] > root return end |
| 84 | + #Produce if we've filled all the holes |
| 85 | + sofar = {x..., root} |
| 86 | + ssofaru = sort(union(sofar...)) |
| 87 | + if length(ssofaru)==nn && ssofaru==[1:nn] |
| 88 | + produce(sofar) |
| 89 | + return |
| 90 | + end |
| 91 | + #otherwise patch all remaining holes |
| 92 | + blob = [ssofaru; nn+1] |
| 93 | + for l=1:length(blob)-1 |
| 94 | + ap, bp = blob[l]+1, blob[l+1]-1 |
| 95 | + if ap <= bp ncpart(ap, bp, nn, sofar) end |
| 96 | + end |
| 97 | + end |
| 98 | + end |
| 99 | +end |
| 100 | + |
0 commit comments