dither 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd7dc97ac31f5097009170b509d7ce2e86dd451a
4
- data.tar.gz: 37986e3680cb1e927794e307bf17eec619b22f7e
3
+ metadata.gz: 8544177ee83d6cbef836448d4e0d550cff9affc5
4
+ data.tar.gz: 91019ef4fc9f4cdaada74fddf41e4a9b4007f41a
5
5
  SHA512:
6
- metadata.gz: 3f6cfd8559eea4bba2f626c6c050a20379e61a2cfbe58907a8143acc7007abe2fe7b521bebcd639d6006e4680c7ee93400c86b8d58915e41e7da6df4e95537a5
7
- data.tar.gz: b0d9d084bd338c6d473a7fd095c0598bae59ed0fd4fcf1e5063181e8dc503b9619666c272cfc0c9a7c3f530761ac51693deefc6f81f7459528609d997cb0883e
6
+ metadata.gz: 0aa18ecaf1bf5e84690ef817f5b3b2607389359b9d6233af3beb7a74d3e79c3768d43b982766390b346be8430b3dd9334295a644f4004b750422fc7271a07eed
7
+ data.tar.gz: 192d58cfe5c72c8a1c177791a406779583084732d9f276cca1b3c4607d5c189901de369c80dc8fc4ebbf89cc65227df16d3ab184d6082318fea4aaa4829745ca
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dither (0.0.1)
4
+ dither (0.0.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -23,7 +23,6 @@ GEM
23
23
  rspec-support (3.2.2)
24
24
 
25
25
  PLATFORMS
26
- java
27
26
  ruby
28
27
 
29
28
  DEPENDENCIES
data/lib/dither/ipog.rb CHANGED
@@ -1,18 +1,19 @@
1
+ # coding: utf-8
1
2
 
2
3
  module Dither
3
4
  class IPOG
4
- attr_reader :params, :t, :constraints
5
- private :params, :t, :constraints
5
+ attr_reader :params, :t, :constraints, :test_set, :orig_params, :unbound_param_pool
6
+ private :params, :t, :constraints, :test_set, :orig_params
6
7
 
7
8
  def initialize(params, t, opts = {})
8
- @params = params
9
+ init_params(params)
9
10
  @t = t
10
- @constraints = opts[:constraints]
11
- unless constraints.nil?
12
- @constraints = constraints.map(&:to_a)
13
- .map { |a| a.map { |b| Param.new(*b) } }
11
+ unless opts[:constraints].nil?
12
+ @constraints = opts[:constraints].map(&:to_a)
13
+ .map { |a| a.map { |b| @params[@map_to_orig_index.key(b[0])][b[1]] } }
14
14
  .map(&:to_set)
15
15
  end
16
+
16
17
  raise 't must be >= 2' if t < 2
17
18
  raise 't must be <= params.length' if t > params.length
18
19
  params.each do |param|
@@ -20,37 +21,101 @@ module Dither
20
21
  end
21
22
  end
22
23
 
23
- def run
24
- ts = comb
25
- (t...params.length).each do |i|
26
- ts = ts.zip((0...params[i].length).cycle)
27
- .map { |a| a[0] << Param.new(i, a[1]) }
28
- .delete_if { |a| violates_constraints?(a) }
24
+ def init_params(user_params)
25
+ tmp = []
26
+ user_params.each_with_index { |e, i| tmp << [i, e] }
27
+ @orig_params = tmp.sort_by { |a| a[1].length }
28
+ .reverse!
29
29
 
30
- comb_i(i).each do |a|
31
- next if violates_constraints?(a)
32
- next if ts.any? { |test| a.subset?(test) }
30
+ @map_to_orig_index = {}
31
+ @orig_params.each_with_index do |e, i|
32
+ @map_to_orig_index[i] = e[0]
33
+ end
34
+
35
+ @params = []
36
+ @unbound_param_pool = []
37
+ orig_params.each_with_index do |e, i|
38
+ @params << (0...e[1].length).map { |j| Param.new(i, j) }
39
+ @unbound_param_pool << UnboundParam.new(i)
40
+ end
41
+ params
42
+ end
33
43
 
34
- existing_test = false
35
- ts.select { |c| c.length <= i }
36
- .each do |b|
44
+ # return nil if unable to satisfy constraints
45
+ def maximize_coverage(i, test_case, pi)
46
+ current_max = 0
47
+ current_max_j = 0
48
+ current_matches = []
49
+
50
+ (0...params[i].length).each do |j|
51
+ current_param = params[i][j]
52
+ test_case << current_param
53
+ unless violates_constraints?(test_case)
54
+ matches = pi.select { |a| a.subset?(test_case) }
55
+ count = matches.count
56
+
57
+ if count > current_max
58
+ current_max = count
59
+ current_max_j = j
60
+ current_matches = matches
61
+ end
62
+ end
63
+ test_case.delete(current_param)
64
+ end
37
65
 
38
- unbound = find_unbound(a, b)
66
+ test_case << params[i][current_max_j]
67
+ return nil if violates_constraints?(test_case)
39
68
 
40
- if unbound
41
- unbound.each { |c| b << c }
42
- existing_test = true
43
- break
44
- end
69
+ current_matches
70
+ end
71
+
72
+ def run
73
+ # add into test set a test for each combination of values
74
+ # of the first t parameter
75
+ test_set = comb
76
+
77
+ (t...params.length).each do |i|
78
+ # let pi
79
+ # be the set of t-way combinations of values involving
80
+ # parameter Pi and t -1 parameters among the first i – 1
81
+ # parameters
82
+ pi = comb_i(i)
83
+
84
+ # horizontal extension for parameter i
85
+ test_set.each do |test_case|
86
+ cover = maximize_coverage(i, test_case, pi)
87
+
88
+ if cover.nil?
89
+ test_set.delete(test_case)
90
+ else
91
+ pi -= cover
45
92
  end
93
+ end
94
+
95
+ # vertical extension for parameter i
96
+ pi.each do |a|
97
+ if test_set.any? { |test_case| a.subset?(test_case) }
98
+ pi.delete(a)
99
+ else
100
+
101
+ test_case = nil
102
+ test_set.each do |b|
103
+ test_case = b.merge_without_conflict(i, a) do |a|
104
+ violates_constraints?(a)
105
+ end
106
+ break unless test_case.nil?
107
+ end
46
108
 
47
- ts << a unless existing_test
109
+ if test_case.nil?
110
+ test_set << a.create_unbound(i)
111
+ end
112
+ pi.delete(a)
113
+ end
48
114
  end
49
115
  end
50
116
 
51
- ts.map { |a| fill_unbound(a) }
117
+ test_set.map { |a| fill_unbound(a) }
52
118
  .delete_if(&:nil?)
53
- .to_set
54
119
  .to_a
55
120
  end
56
121
 
@@ -61,7 +126,7 @@ module Dither
61
126
 
62
127
  def comb
63
128
  ranges = (0...t).to_a.inject([]) do |a, i|
64
- a << (0...params[i].length).map { |j| Param.new(i, j) }
129
+ a << (0...params[i].length).map { |j| params[i][j] }
65
130
  end
66
131
 
67
132
  products = ranges[1..-1].inject(ranges[0]) do |a, b|
@@ -69,7 +134,7 @@ module Dither
69
134
  end
70
135
 
71
136
  products.map(&:flatten)
72
- .map(&:to_set)
137
+ .map { |a| TestCase.create(params, unbound_param_pool, a) }
73
138
  end
74
139
 
75
140
  def comb_i(param_i)
@@ -80,9 +145,9 @@ module Dither
80
145
  result = []
81
146
  values.each do |a|
82
147
  result += a[1..-1]
83
- .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) }) }
148
+ .inject((0...params[a[0]].length).map { |b| params[0][b] }) { |p, i| p.product((0...params[i].length).to_a.map { |b| params[i][b] }) }
84
149
  .map(&:flatten)
85
- .map(&:to_set)
150
+ .map { |a| TestCase.create(params, unbound_param_pool, a) }
86
151
  end
87
152
  result
88
153
  end
@@ -90,22 +155,22 @@ module Dither
90
155
  private
91
156
 
92
157
  def fill_unbound(data)
93
- @bound_sets ||= []
94
- return nil if @bound_sets.any? { |a| data.subset?(a) }
95
-
96
158
  arr = Array.new(params.length)
97
159
  data.each do |param|
98
- arr[param.i] = params[param.i][param.j]
160
+ unless param.unbound?
161
+ orig_param = orig_params[param.i]
162
+ arr[orig_param[0]] = orig_param[1][param.j]
163
+ end
99
164
  end
100
165
 
101
166
  arr.each_with_index do |e, i|
102
167
  if e.nil?
103
168
  j = 0
104
- arr[i] = params[i][j]
105
- data << Param.new(i, j)
169
+ orig_param = orig_params.find { |a| a[0] = i }
170
+ arr[i] = orig_param[1][j]
106
171
  end
107
172
  end
108
- @bound_sets << data
173
+
109
174
  return nil if violates_constraints?(data)
110
175
  arr
111
176
  end
data/lib/dither/param.rb CHANGED
@@ -1,4 +1,19 @@
1
1
 
2
2
  module Dither
3
- Param = Struct.new(:i, :j)
4
- end
3
+ Param = Struct.new(:i, :j) do
4
+ def <=>(param)
5
+ return 1 if param.unbound?
6
+
7
+ a = i <=> param.i
8
+ if a == 0
9
+ return j <=> param.j
10
+ else
11
+ return a
12
+ end
13
+ end
14
+
15
+ def unbound?
16
+ false
17
+ end
18
+ end # Param
19
+ end # Dither
@@ -0,0 +1,86 @@
1
+
2
+ module Dither
3
+ class TestCase < Set
4
+
5
+ attr_accessor :bound_param_pool, :unbound_param_pool
6
+
7
+ def self.create(bound_param_pool, unbound_param_pool, params)
8
+ test_case = TestCase.new(params)
9
+ test_case.bound_param_pool = bound_param_pool
10
+ test_case.unbound_param_pool = unbound_param_pool
11
+ test_case
12
+ end
13
+
14
+ def contains_unbound?
15
+ self.any?(&:unbound?)
16
+ end
17
+
18
+ def unbound
19
+ self.select(&:unbound?)
20
+ end
21
+
22
+ def <=>(test_case)
23
+ result = 0
24
+ l = length <= test_case.length ? length : test_case.length
25
+ self.zip(test_case)[0...l].each do |arr|
26
+ first, second = arr
27
+ result = first <=> second
28
+ break if result != 0
29
+ end
30
+ result
31
+ end
32
+
33
+ def create_unbound(i)
34
+ bound_params = self.reject(&:unbound?).map(&:i)
35
+ ((0..i).to_a - bound_params).each do |a|
36
+ self << unbound_param_pool[a]
37
+ end
38
+ self
39
+ end
40
+
41
+ def to_ipog_array(i)
42
+ arr = Array.new(i)
43
+ self.each do |param|
44
+ arr[param.i] = param.j unless param.unbound?
45
+ end
46
+ arr
47
+ end
48
+
49
+ def self.from_array(arr)
50
+ test_case = TestCase.new
51
+ arr.each_with_index do |i, e|
52
+ if e.nil?
53
+ test_case << unbound_param_pool[i]
54
+ else
55
+ test_case << bound_param_pool[i][e]
56
+ end
57
+ end
58
+ test_case
59
+ end
60
+
61
+ # return nil if there is a conflict
62
+ # return self if no conflict
63
+ def merge_without_conflict(i, test_case, &block)
64
+ new_elements = []
65
+ self.to_ipog_array(i).zip(test_case.to_ipog_array(i))
66
+ .each_with_index do |arr, a|
67
+ first, second = arr
68
+
69
+ next if (first == second) || second.nil?
70
+ if first.nil? && second.nil?
71
+ new_elements << unbound_param_pool[a]
72
+ elsif first.nil?
73
+ new_elements << bound_param_pool[a][second]
74
+ else
75
+ return nil
76
+ end
77
+ end
78
+
79
+ new_self = self.clone
80
+ new_elements.each { |a| new_self << a }
81
+
82
+ return nil if block_given? && block.call(new_self)
83
+ new_self
84
+ end
85
+ end # TestCase
86
+ end # Dither
@@ -0,0 +1,17 @@
1
+
2
+ module Dither
3
+ UnboundParam = Struct.new(:i) do
4
+ def <=>(param)
5
+ return -1 unless param.unbound?
6
+ i <=> param.i
7
+ end
8
+
9
+ def unbound?
10
+ true
11
+ end
12
+
13
+ def create_params(j)
14
+ (0...j).map { |a| Param.new(i, a) }
15
+ end
16
+ end # UnboundParam
17
+ end # Dither
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Dither
3
- VERSION = '0.0.4'
3
+ VERSION = '0.0.5'
4
4
  end
data/lib/dither.rb CHANGED
@@ -6,7 +6,9 @@ module Dither
6
6
  def self.all_pairs(params, t = 2, opts = {})
7
7
  IPOG.new(params, t, opts).run
8
8
  end
9
- end
9
+ end # Dither
10
10
 
11
11
  require 'dither/param'
12
+ require 'dither/unbound_param'
13
+ require 'dither/test_case'
12
14
  require 'dither/ipog'
@@ -7,7 +7,7 @@ describe Dither do
7
7
  end
8
8
 
9
9
  it 't must be <= params.length' do
10
- expect { Dither.all_pairs((0...3).to_a, 4) }.to raise_error('t must be <= params.length')
10
+ expect { Dither.all_pairs([(0...3).to_a], 4) }.to raise_error('t must be <= params.length')
11
11
  end
12
12
 
13
13
  it 'param length must be > 1' do
@@ -19,36 +19,24 @@ describe Dither do
19
19
  expect(Dither.all_pairs(params)).to eq([[:a, :d, :h],
20
20
  [:a, :e, :i],
21
21
  [:a, :f, :h],
22
- [:b, :d, :i],
23
- [:b, :e, :h],
24
- [:b, :f, :i],
22
+ [:b, :d, :h],
23
+ [:b, :e, :i],
24
+ [:b, :f, :h],
25
25
  [:c, :d, :h],
26
26
  [:c, :e, :i],
27
27
  [:c, :f, :h]])
28
- results = Dither.all_pairs([
29
- (0...2).to_a,
30
- (0...2).to_a,
31
- (0...3).to_a,
32
- (0...3).to_a,
33
- (0...4).to_a,
34
- (0...6).to_a,
35
- (0...2).to_a,
36
- (0...7).to_a,
37
- (0...3).to_a,
38
- ], 2)
39
- puts results.count
40
28
  end
41
29
 
42
30
  it 'can compute 2-way ipog' do
43
31
  params = [(0...2).to_a, (0..3).to_a]
44
32
  expect(Dither.all_pairs(params)).to eq([
45
33
  [0, 0],
46
- [0, 1],
47
- [0, 2],
48
- [0, 3],
49
34
  [1, 0],
35
+ [0, 1],
50
36
  [1, 1],
37
+ [0, 2],
51
38
  [1, 2],
39
+ [0, 3],
52
40
  [1, 3],
53
41
  ])
54
42
  end
@@ -56,21 +44,22 @@ describe Dither do
56
44
  it 'can compute 3-way ipog' do
57
45
  params = [(0...2).to_a, (0...2).to_a, (0..3).to_a]
58
46
  expect(Dither.all_pairs(params, 3)).to eq([[0, 0, 0],
59
- [0, 0, 1],
60
- [0, 0, 2],
61
- [0, 0, 3],
62
- [0, 1, 0],
63
- [0, 1, 1],
64
- [0, 1, 2],
65
- [0, 1, 3],
66
47
  [1, 0, 0],
67
- [1, 0, 1],
68
- [1, 0, 2],
69
- [1, 0, 3],
48
+ [0, 1, 0],
70
49
  [1, 1, 0],
50
+ [0, 0, 1],
51
+ [1, 0, 1],
52
+ [0, 1, 1],
71
53
  [1, 1, 1],
54
+ [0, 0, 2],
55
+ [1, 0, 2],
56
+ [0, 1, 2],
72
57
  [1, 1, 2],
73
- [1, 1, 3]])
58
+ [0, 0, 3],
59
+ [1, 0, 3],
60
+ [0, 1, 3],
61
+ [1, 1, 3],
62
+ ])
74
63
  end
75
64
 
76
65
  it 'can compute 3-way ipog with constraints' do
@@ -83,18 +72,19 @@ describe Dither do
83
72
  1 => 1,
84
73
  2 => 0}
85
74
  ])).to eq([[0, 0, 0],
86
- [0, 0, 1],
87
- [0, 0, 3],
88
- [0, 1, 1],
89
- [0, 1, 3],
90
75
  [1, 0, 0],
91
- [1, 0, 1],
92
- [1, 0, 2],
93
- [1, 0, 3],
94
76
  [1, 1, 0],
77
+ [0, 0, 1],
78
+ [1, 0, 1],
79
+ [0, 1, 1],
95
80
  [1, 1, 1],
81
+ [1, 0, 2],
96
82
  [1, 1, 2],
97
- [1, 1, 3]])
83
+ [0, 0, 3],
84
+ [1, 0, 3],
85
+ [0, 1, 3],
86
+ [1, 1, 3],
87
+ ])
98
88
  end
99
89
 
100
90
  it 'another 3-way ipog with constraints' do
@@ -107,19 +97,47 @@ describe Dither do
107
97
  1 => 1,
108
98
  2 => 0}
109
99
  ])).to eq([[0, 0, 0, 0],
110
- [0, 0, 1, 1],
111
- [0, 1, 1, 3],
112
- [1, 0, 0, 0],
100
+ [1, 1, 0, 0],
101
+ [1, 0, 1, 0],
102
+ [0, 1, 1, 0],
103
+ [0, 0, 0, 1],
104
+ [1, 1, 0, 1],
113
105
  [1, 0, 1, 1],
114
- [1, 1, 0, 2],
115
- [1, 1, 1, 3],
106
+ [0, 1, 1, 1],
116
107
  [0, 0, 0, 2],
117
- [0, 0, 0, 3],
118
- [0, 1, 1, 0],
119
- [0, 1, 1, 2],
108
+ [1, 1, 0, 2],
120
109
  [1, 0, 1, 2],
121
- [1, 0, 0, 3],
122
- [1, 1, 1, 0],
123
- [1, 1, 0, 1]])
110
+ [0, 1, 1, 2],
111
+ [0, 0, 0, 3],
112
+ [1, 1, 0, 3],
113
+ [1, 0, 1, 3],
114
+ [0, 1, 1, 3],
115
+ ])
116
+ results = Dither.all_pairs([
117
+ (0...10).to_a,
118
+ (0...10).to_a,
119
+ (0...4).to_a,
120
+ (0...3).to_a,
121
+ (0...3).to_a,
122
+ (0...2).to_a,
123
+ (0...2).to_a,
124
+ (0...2).to_a,
125
+ (0...2).to_a,
126
+ (0...2).to_a,
127
+ (0...2).to_a,
128
+ (0...2).to_a,
129
+ ], 3)
130
+
131
+ # results = Dither.all_pairs([
132
+ # (0...2).to_a,
133
+ # (0...2).to_a,
134
+ # (0...2).to_a,
135
+ # (0...3).to_a,
136
+ # ], 3)
137
+ require 'csv'
138
+ results.each { |a| puts a.to_csv }
139
+ puts results.count
140
+
141
+
124
142
  end
125
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dither
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Gowan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-15 00:00:00.000000000 Z
11
+ date: 2015-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -57,6 +57,8 @@ files:
57
57
  - lib/dither.rb
58
58
  - lib/dither/ipog.rb
59
59
  - lib/dither/param.rb
60
+ - lib/dither/test_case.rb
61
+ - lib/dither/unbound_param.rb
60
62
  - lib/dither/version.rb
61
63
  - spec/dither/dither_spec.rb
62
64
  - spec/spec_helper.rb