lib/dither/ipog.rb in dither-0.0.1 vs lib/dither/ipog.rb in dither-0.0.2

- old
+ new

@@ -1,31 +1,39 @@ module Dither class IPOG - attr_reader :params, :t, :prng - private :params, :t, :prng + attr_reader :params, :t, :prng, :constraints + private :params, :t, :prng, :constraints - def initialize(params, t) + def initialize(params, t, opts = {}) @params = params @t = t + @constraints = opts[:constraints] + unless constraints.nil? + @constraints = constraints.map(&:to_a) + .map { |a| a.map { |b| Param.new(*b) } } + .map(&:to_set) + end @prng = Random.new raise 't must be >= 2' if t < 2 raise 't must be <= params.length' if t > params.length params.each do |param| raise 'param length must be > 1' if param.length < 2 end end def run - ts = comb((0...t)) + ts = comb (t...params.length).each do |i| - ts = ts.zip(params[i].cycle).map { |a| a[0] << Param.new(i, a[1]) } + ts = ts.zip((0...params[i].length).cycle) + .map { |a| a[0] << Param.new(i, a[1]) } + .delete_if { |a| violates_constraints?(a) } comb_i(i).each do |a| - in_ts = ts.any? { |test| a.subset?(test) } + next if violates_constraints?(a) + next if ts.any? { |test| a.subset?(test) } - next if in_ts existing_test = false ts.select { |c| c.length <= i } .each do |b| unbound = find_unbound(a, b) @@ -40,19 +48,29 @@ ts << a unless existing_test end end ts.map { |a| fill_unbound(a) } + .delete_if(&:nil?) end - def comb(range) - range.to_a.combination(t).to_a.inject([]) do |result, a| - result + a[1..-1] - .inject((0...params[a[0]].length).map { |b| Param.new(0, b) }) { |p, i| p.product((0...params[i].length).to_a.map { |b| Param.new(i, b) }) } - .map(&:flatten) - .map(&:to_set) + def violates_constraints?(params) + return false if constraints.nil? + constraints.any? { |b| b.subset?(params) } + end + + def comb + ranges = (0...t).to_a.inject([]) do |a, i| + a << (0...params[i].length).map { |j| Param.new(i, j) } end + + products = ranges[1..-1].inject(ranges[0]) do |a, b| + a = a.product(b) + end + + products.map(&:flatten) + .map(&:to_set) end def comb_i(param_i) values = (0...param_i).to_a.combination((t-1)).to_a values.each do |a| @@ -75,11 +93,16 @@ data.each do |param| arr[param.i] = params[param.i][param.j] end arr.each_with_index do |e, i| - arr[i] = params[i][prng.rand(0...params[i].length)] if e.nil? + if e.nil? + j = prng.rand(0...params[i].length) + arr[i] = params[i][j] + data << Param.new(i,j) + end end + return nil if violates_constraints?(data) arr end def find_unbound(param_array, stuff) data = {}