dither 0.0.10-java → 0.0.11-java
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/README.md +44 -0
- data/lib/dither/chinese_postman_problem.rb +220 -0
- data/lib/dither/version.rb +1 -1
- data/lib/dither.rb +1 -0
- data/spec/dither/chinese_postman_problem_spec.rb +77 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e5528867e133a68bb9a429ae778153f59d7fa07
|
4
|
+
data.tar.gz: 06470e7386b123b3a6642fb48761318ad9bfc0be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70072c1bcfe0006bb632bf33542e700c8dd1036c2946b3d8bed6f4f752d1feffdbbf850a45eae283ab0651019c10b4ca03551f72741a6e9fe8dd8ae90b210741
|
7
|
+
data.tar.gz: 630cc4a6cef209358550c04242a82093ddf7729de981ccd3eeb942b8b144286da4c20a4bebe31c07dc2fada801b21e2327fd8b8f59d8b881ac59e097cba0ab9c
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@ Collection of combinatorial test generation strategies.
|
|
3
3
|
|
4
4
|
# Usage
|
5
5
|
|
6
|
+
## Pairwise Testing
|
6
7
|
```ruby
|
7
8
|
require 'dither'
|
8
9
|
|
@@ -31,6 +32,49 @@ Dither.ipog([[true, false],
|
|
31
32
|
|
32
33
|
```
|
33
34
|
|
35
|
+
## Graph Models (Experimental)
|
36
|
+
```ruby
|
37
|
+
raw_graph = {
|
38
|
+
:origin => 0,
|
39
|
+
:edges => [
|
40
|
+
{
|
41
|
+
:name => :a,
|
42
|
+
:src_vertex => 0,
|
43
|
+
:dst_vertex => 1,
|
44
|
+
},
|
45
|
+
{
|
46
|
+
:name => :b,
|
47
|
+
:src_vertex => 0,
|
48
|
+
:dst_vertex => 2,
|
49
|
+
},
|
50
|
+
{
|
51
|
+
:name => :c,
|
52
|
+
:src_vertex => 1,
|
53
|
+
:dst_vertex => 2,
|
54
|
+
},
|
55
|
+
{
|
56
|
+
:name => :d,
|
57
|
+
:src_vertex => 1,
|
58
|
+
:dst_vertex => 3,
|
59
|
+
},
|
60
|
+
{
|
61
|
+
:name => :e,
|
62
|
+
:src_vertex => 2,
|
63
|
+
:dst_vertex => 3,
|
64
|
+
},
|
65
|
+
{
|
66
|
+
:name => :f,
|
67
|
+
:src_vertex => 3,
|
68
|
+
:dst_vertex => 0,
|
69
|
+
}
|
70
|
+
]
|
71
|
+
}
|
72
|
+
|
73
|
+
# shortest path to cover all edges at least once
|
74
|
+
Dither.all_edges(raw_graph)
|
75
|
+
```
|
76
|
+
|
77
|
+
|
34
78
|
# Note on Patches/Pull Requests
|
35
79
|
|
36
80
|
* Fork the project.
|
@@ -0,0 +1,220 @@
|
|
1
|
+
|
2
|
+
# implement thimbleby's solution to the chinese @postman problem
|
3
|
+
# http://www.cs.swansea.ac.uk/~csharold/cv/files/cpp.pdf
|
4
|
+
|
5
|
+
module Dither
|
6
|
+
module Cpp
|
7
|
+
class Graph
|
8
|
+
|
9
|
+
attr_accessor :n, :neg, :pos, :degree, :path, :edges, :cheapest_edge, :f, :defined, :label, :c, :initialized, :origin
|
10
|
+
|
11
|
+
Edge = Struct.new(:name, :src_vertex, :dst_vertex)
|
12
|
+
|
13
|
+
def initialize(n)
|
14
|
+
|
15
|
+
@n = n
|
16
|
+
@degree = Array.new(n).fill(0)
|
17
|
+
@defined = Array.new(n).fill { |_| Array.new(n).fill(false) }
|
18
|
+
@label = Array.new(n).fill { |_| Array.new(n).fill { |_| [] } }
|
19
|
+
@c = Array.new(n).fill { |_| Array.new(n).fill(0.0) }
|
20
|
+
@f = Array.new(n).fill { |_| Array.new(n).fill(0) }
|
21
|
+
@edges = Array.new(n).fill { |_| Array.new(n).fill(0) }
|
22
|
+
@cheapest_edge = Array.new(n).fill { |_| Array.new(n).fill(0) }
|
23
|
+
@path = Array.new(n).fill { |_| Array.new(n).fill(0) }
|
24
|
+
@initialized = true
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def cpp
|
29
|
+
initialized?
|
30
|
+
least_cost_paths
|
31
|
+
check_valid
|
32
|
+
find_feasible
|
33
|
+
while improvments do
|
34
|
+
end
|
35
|
+
print(origin)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.create(raw_graph)
|
39
|
+
vertices = [].to_set
|
40
|
+
raw_graph[:edges].each do |edge|
|
41
|
+
vertices << edge[:src_vertex]
|
42
|
+
vertices << edge[:dst_vertex]
|
43
|
+
end
|
44
|
+
|
45
|
+
graph = Graph.new(vertices.length)
|
46
|
+
|
47
|
+
raw_graph[:edges].each do |edge|
|
48
|
+
graph.add_edge(edge[:name], edge[:src_vertex], edge[:dst_vertex], 1)
|
49
|
+
end
|
50
|
+
graph.origin = raw_graph[:origin]
|
51
|
+
graph
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_edge(lab, u, v, cost)
|
55
|
+
@label[u][v] = [] unless defined[u][v]
|
56
|
+
@label[u][v] << lab
|
57
|
+
if !defined[u][v] || c[u][v] > cost
|
58
|
+
@c[u][v] = cost
|
59
|
+
@cheapest_edge[u][v] = edges[u][v]
|
60
|
+
@defined[u][v] = true
|
61
|
+
@path[u][v] = v
|
62
|
+
end
|
63
|
+
@edges[u][v] += 1
|
64
|
+
@degree[u] += 1
|
65
|
+
@degree[v] -= 1
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_valid
|
70
|
+
(0...n).each do |i|
|
71
|
+
raise Dither::Error, 'negative cycle' if c[i][i] < 0
|
72
|
+
(0...n).each do |j|
|
73
|
+
raise Dither::Error, 'not strongly connected' unless defined[i][j]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def least_cost_paths
|
79
|
+
(0...n).each do |k|
|
80
|
+
(0...n).each do |i|
|
81
|
+
if defined[i][k]
|
82
|
+
(0...n).each do |j|
|
83
|
+
if defined[k][j] && (!defined[i][j] || c[i][j] > c[i][k]+c[k][j])
|
84
|
+
@defined[i][j] = true
|
85
|
+
@path[i][j] = path[i][k]
|
86
|
+
@c[i][j] = c[i][k] + c[k][j]
|
87
|
+
# negative cycle
|
88
|
+
return if i == j && c[i][j] < 0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_feasible
|
97
|
+
nn, np = 0, 0
|
98
|
+
(0...n).each do |i|
|
99
|
+
if degree[i] < 0
|
100
|
+
nn += 1
|
101
|
+
elsif degree[i] > 0
|
102
|
+
np += 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
@neg = Array.new(nn)
|
107
|
+
@pos = Array.new(np)
|
108
|
+
nn, np = 0, 0
|
109
|
+
(0...n).each do |i|
|
110
|
+
if degree[i] < 0
|
111
|
+
@neg[nn] = i
|
112
|
+
nn += 1
|
113
|
+
elsif degree[i] > 0
|
114
|
+
@pos[np] = i
|
115
|
+
np += 1
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
(0...nn).each do |u|
|
120
|
+
i = neg[u]
|
121
|
+
(0...np).each do |v|
|
122
|
+
j = pos[v]
|
123
|
+
@f[i][j] = -degree[i] < degree[j] ? -degree[i] : degree[j]
|
124
|
+
@degree[i] += f[i][j]
|
125
|
+
@degree[j] -= f[i][j]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def improvments
|
131
|
+
r = Graph.new(n)
|
132
|
+
(0...neg.length).each do |u|
|
133
|
+
i = neg[u]
|
134
|
+
(0...pos.length).each do |v|
|
135
|
+
j = pos[v]
|
136
|
+
if edges[i][j] > 0
|
137
|
+
r.add_edge(nil, i, j, c[i][j])
|
138
|
+
end
|
139
|
+
if f[i][j] != 0
|
140
|
+
r.add_edge(nil, j, i, -c[i][j])
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
r.least_cost_paths
|
146
|
+
(0...n).each do |i|
|
147
|
+
if r.c[i][i] < 0
|
148
|
+
k = 0
|
149
|
+
kunset = true
|
150
|
+
u = i
|
151
|
+
begin
|
152
|
+
v = r.path[u][i]
|
153
|
+
if r.c[u][v] < 0 && (kunset || k > f[v][u])
|
154
|
+
k = f[v][u]
|
155
|
+
kunset = false
|
156
|
+
end
|
157
|
+
u = v
|
158
|
+
end while u != i
|
159
|
+
u = i
|
160
|
+
begin
|
161
|
+
v = r.path[u][i]
|
162
|
+
if r.c[u][v] < 0
|
163
|
+
@f[v][u] -= k
|
164
|
+
else
|
165
|
+
@f[u][v] += k
|
166
|
+
end
|
167
|
+
u = v
|
168
|
+
end while u != i
|
169
|
+
return true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
false
|
173
|
+
end
|
174
|
+
|
175
|
+
def print(start)
|
176
|
+
result = []
|
177
|
+
v = start
|
178
|
+
loop do
|
179
|
+
skip = false
|
180
|
+
u = v
|
181
|
+
(0...n).each do |i|
|
182
|
+
if f[u][i] > 0
|
183
|
+
v = i
|
184
|
+
@f[u][v] -= 1
|
185
|
+
while u != v
|
186
|
+
p = path[u][v]
|
187
|
+
result << Edge.new(label[u][p][cheapest_edge[u][p]], u, p)
|
188
|
+
u = p
|
189
|
+
end
|
190
|
+
skip = true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
next if skip
|
195
|
+
|
196
|
+
v = -1
|
197
|
+
(0...n).each do |i|
|
198
|
+
if edges[u][i] > 0
|
199
|
+
v = i if v == -1 || i != path[u][start]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
return result if v == -1
|
203
|
+
result << Edge.new(label[u][v][edges[u][v] - 1], u, v)
|
204
|
+
@edges[u][v] -= 1
|
205
|
+
end
|
206
|
+
result
|
207
|
+
end
|
208
|
+
|
209
|
+
def initialized?
|
210
|
+
raise Dither::Error, 'graph not initialized' unless initialized
|
211
|
+
raise Dither::Error, 'origin not set' unless origin
|
212
|
+
@initialized = false
|
213
|
+
end
|
214
|
+
end # Graph
|
215
|
+
end # Cpp
|
216
|
+
|
217
|
+
def self.all_edges(raw_graph)
|
218
|
+
Dither::Cpp::Graph.create(raw_graph).cpp
|
219
|
+
end
|
220
|
+
end # Dither
|
data/lib/dither/version.rb
CHANGED
data/lib/dither.rb
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Dither::Cpp::Graph do
|
4
|
+
let(:raw_graph) do
|
5
|
+
{
|
6
|
+
:origin => 0,
|
7
|
+
:edges => [
|
8
|
+
{
|
9
|
+
:name => :a,
|
10
|
+
:src_vertex => 0,
|
11
|
+
:dst_vertex => 1,
|
12
|
+
},
|
13
|
+
{
|
14
|
+
:name => :b,
|
15
|
+
:src_vertex => 0,
|
16
|
+
:dst_vertex => 2,
|
17
|
+
},
|
18
|
+
{
|
19
|
+
:name => :c,
|
20
|
+
:src_vertex => 1,
|
21
|
+
:dst_vertex => 2,
|
22
|
+
},
|
23
|
+
{
|
24
|
+
:name => :d,
|
25
|
+
:src_vertex => 1,
|
26
|
+
:dst_vertex => 3,
|
27
|
+
},
|
28
|
+
{
|
29
|
+
:name => :e,
|
30
|
+
:src_vertex => 2,
|
31
|
+
:dst_vertex => 3,
|
32
|
+
},
|
33
|
+
{
|
34
|
+
:name => :f,
|
35
|
+
:src_vertex => 3,
|
36
|
+
:dst_vertex => 0,
|
37
|
+
}
|
38
|
+
]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can compute chinese postman problem' do
|
43
|
+
expected = [
|
44
|
+
[:b, 0, 2],
|
45
|
+
[:e, 2, 3],
|
46
|
+
[:f, 3, 0],
|
47
|
+
[:a, 0, 1],
|
48
|
+
[:c, 1, 2],
|
49
|
+
[:e, 2, 3],
|
50
|
+
[:f, 3, 0],
|
51
|
+
[:a, 0, 1],
|
52
|
+
[:d, 1, 3],
|
53
|
+
[:f, 3, 0]].map { |a| Dither::Cpp::Graph::Edge.new(*a) }
|
54
|
+
expect(Dither.all_edges(raw_graph)).to eq(expected)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'verify origin is set' do
|
58
|
+
raw_graph.delete(:origin)
|
59
|
+
expect { Dither.all_edges(raw_graph) }.to raise_error
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raise error when calling cpp twice' do
|
63
|
+
graph = Dither::Cpp::Graph.create(raw_graph)
|
64
|
+
graph.cpp
|
65
|
+
expect { graph.cpp }.to raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raise error when graph is not strongly connected' do
|
69
|
+
raw_graph[:edges] << {
|
70
|
+
:name => :w,
|
71
|
+
:src_vertex => 23,
|
72
|
+
:dst_vertex => 78
|
73
|
+
}
|
74
|
+
|
75
|
+
expect { Dither.all_edges(raw_graph) }.to raise_error
|
76
|
+
end
|
77
|
+
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.11
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Jason Gowan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- dither.gemspec
|
71
71
|
- lib/dither.jar
|
72
72
|
- lib/dither.rb
|
73
|
+
- lib/dither/chinese_postman_problem.rb
|
73
74
|
- lib/dither/ipog.rb
|
74
75
|
- lib/dither/ipog_helper.rb
|
75
76
|
- lib/dither/java_ext/dither.rb
|
@@ -78,6 +79,7 @@ files:
|
|
78
79
|
- lib/dither/test_case.rb
|
79
80
|
- lib/dither/unbound_param.rb
|
80
81
|
- lib/dither/version.rb
|
82
|
+
- spec/dither/chinese_postman_problem_spec.rb
|
81
83
|
- spec/dither/dither_spec.rb
|
82
84
|
- spec/spec_helper.rb
|
83
85
|
homepage: https://github.com/jesg/dither
|
@@ -100,10 +102,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
102
|
version: '0'
|
101
103
|
requirements: []
|
102
104
|
rubyforge_project: dither
|
103
|
-
rubygems_version: 2.4.
|
105
|
+
rubygems_version: 2.4.6
|
104
106
|
signing_key:
|
105
107
|
specification_version: 4
|
106
108
|
summary: Collection of test generation strategies
|
107
109
|
test_files:
|
110
|
+
- spec/dither/chinese_postman_problem_spec.rb
|
108
111
|
- spec/dither/dither_spec.rb
|
109
112
|
- spec/spec_helper.rb
|