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 +4 -4
- data/Gemfile.lock +1 -2
- data/lib/dither/ipog.rb +104 -39
- data/lib/dither/param.rb +17 -2
- data/lib/dither/test_case.rb +86 -0
- data/lib/dither/unbound_param.rb +17 -0
- data/lib/dither/version.rb +1 -1
- data/lib/dither.rb +3 -1
- data/spec/dither/dither_spec.rb +67 -49
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8544177ee83d6cbef836448d4e0d550cff9affc5
|
4
|
+
data.tar.gz: 91019ef4fc9f4cdaada74fddf41e4a9b4007f41a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0aa18ecaf1bf5e84690ef817f5b3b2607389359b9d6233af3beb7a74d3e79c3768d43b982766390b346be8430b3dd9334295a644f4004b750422fc7271a07eed
|
7
|
+
data.tar.gz: 192d58cfe5c72c8a1c177791a406779583084732d9f276cca1b3c4607d5c189901de369c80dc8fc4ebbf89cc65227df16d3ab184d6082318fea4aaa4829745ca
|
data/Gemfile.lock
CHANGED
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
|
-
|
9
|
+
init_params(params)
|
9
10
|
@t = t
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
66
|
+
test_case << params[i][current_max_j]
|
67
|
+
return nil if violates_constraints?(test_case)
|
39
68
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|
-
|
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|
|
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(
|
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|
|
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(
|
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
|
-
|
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
|
-
|
105
|
-
|
169
|
+
orig_param = orig_params.find { |a| a[0] = i }
|
170
|
+
arr[i] = orig_param[1][j]
|
106
171
|
end
|
107
172
|
end
|
108
|
-
|
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
|
-
|
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
|
data/lib/dither/version.rb
CHANGED
data/lib/dither.rb
CHANGED
data/spec/dither/dither_spec.rb
CHANGED
@@ -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, :
|
23
|
-
[:b, :e, :
|
24
|
-
[:b, :f, :
|
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
|
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
|
-
[
|
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
|
-
[
|
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
|
-
[
|
111
|
-
[
|
112
|
-
[
|
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
|
-
[
|
115
|
-
[1, 1, 1, 3],
|
106
|
+
[0, 1, 1, 1],
|
116
107
|
[0, 0, 0, 2],
|
117
|
-
[
|
118
|
-
[0, 1, 1, 0],
|
119
|
-
[0, 1, 1, 2],
|
108
|
+
[1, 1, 0, 2],
|
120
109
|
[1, 0, 1, 2],
|
121
|
-
[
|
122
|
-
[
|
123
|
-
[1, 1, 0,
|
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
|
+
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-
|
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
|