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 = {}