dither 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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