dither 0.2.2 → 0.2.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/Rakefile +8 -2
- data/dither.gemspec +1 -3
- data/ext/dither/Aetg.java +51 -0
- data/ext/dither/AetgPairwise.java +258 -0
- data/ext/dither/ArrayLengthComparator.java +30 -0
- data/ext/dither/CombinatoricHelper.java +143 -0
- data/ext/dither/ConstraintHandler.java +120 -0
- data/ext/dither/Dither.java +155 -0
- data/ext/dither/DitherError.java +45 -0
- data/ext/dither/IndexArrayPair.java +40 -0
- data/ext/dither/Ipog.java +405 -0
- data/ext/dither/Pair.java +61 -0
- data/ext/dither/base_constraint_handler.h +4 -1
- data/ext/dither/combinations.h +21 -12
- data/ext/dither/ipog.cc +71 -37
- data/ext/dither/ipog.h +12 -7
- data/ext/dither/simple_constraint_handler.cc +14 -2
- data/ext/dither/simple_constraint_handler.h +2 -1
- data/lib/dither.rb +1 -2
- data/lib/dither/version.rb +1 -1
- metadata +13 -3
@@ -0,0 +1,61 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
/*
|
4
|
+
* #%L
|
5
|
+
* dither
|
6
|
+
* %%
|
7
|
+
* Copyright (C) 2015 Jason Gowan
|
8
|
+
* %%
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
* you may not use this file except in compliance with the License.
|
11
|
+
* You may obtain a copy of the License at
|
12
|
+
*
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
*
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
* See the License for the specific language governing permissions and
|
19
|
+
* limitations under the License.
|
20
|
+
* #L%
|
21
|
+
*/
|
22
|
+
|
23
|
+
class Pair {
|
24
|
+
final int i;
|
25
|
+
final int j;
|
26
|
+
|
27
|
+
Pair(final int i, final int j) {
|
28
|
+
this.i = i;
|
29
|
+
this.j = j;
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
@Override
|
34
|
+
public int hashCode() {
|
35
|
+
final int prime = 31;
|
36
|
+
int result = 1;
|
37
|
+
result = prime * result + i;
|
38
|
+
result = prime * result + j;
|
39
|
+
return result;
|
40
|
+
}
|
41
|
+
|
42
|
+
@Override
|
43
|
+
public boolean equals(Object obj) {
|
44
|
+
if (this == obj)
|
45
|
+
return true;
|
46
|
+
if (obj == null)
|
47
|
+
return false;
|
48
|
+
if (getClass() != obj.getClass())
|
49
|
+
return false;
|
50
|
+
Pair other = (Pair) obj;
|
51
|
+
if (j != other.j)
|
52
|
+
return false;
|
53
|
+
if (i != other.i)
|
54
|
+
return false;
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
|
58
|
+
public String toString() {
|
59
|
+
return "Pair i: " + i + " j: " + j;
|
60
|
+
}
|
61
|
+
}
|
@@ -20,7 +20,10 @@ namespace dither {
|
|
20
20
|
BaseConstraintHandler(){};
|
21
21
|
virtual ~BaseConstraintHandler(){};
|
22
22
|
virtual bool violate_constraints(const dtest_case &test_case) { return false; }
|
23
|
-
virtual bool violate_constraints(const std::vector<param
|
23
|
+
virtual bool violate_constraints(const std::vector<param*> &test_case) {
|
24
|
+
return false;
|
25
|
+
}
|
26
|
+
virtual bool violate_constraints(param** test_case, const std::size_t length) {
|
24
27
|
return false;
|
25
28
|
}
|
26
29
|
virtual bool ground(dtest_case &test_case) {
|
data/ext/dither/combinations.h
CHANGED
@@ -12,6 +12,8 @@
|
|
12
12
|
|
13
13
|
#include <vector>
|
14
14
|
#include <forward_list>
|
15
|
+
#include <algorithm>
|
16
|
+
#include <memory>
|
15
17
|
#include "dither_types.h"
|
16
18
|
|
17
19
|
namespace dither {
|
@@ -157,33 +159,40 @@ inline void product3(
|
|
157
159
|
}
|
158
160
|
}
|
159
161
|
|
160
|
-
inline
|
161
|
-
std::forward_list<
|
162
|
-
|
162
|
+
inline std::size_t product4(
|
163
|
+
std::forward_list<param**>& results,
|
164
|
+
param** param_cache,
|
165
|
+
std::vector<std::vector<param>*>& param_matrix) {
|
163
166
|
std::vector<int> ranges;
|
164
|
-
std::
|
165
|
-
|
166
|
-
|
167
|
-
|
167
|
+
std::unique_ptr<param*[]> scratch_ptr(new param*[param_matrix.size()]);
|
168
|
+
auto scratch = scratch_ptr.get();
|
169
|
+
for(std::size_t j = 0; j < param_matrix.size(); j++) {
|
170
|
+
ranges.push_back(param_matrix[j]->size() - 1);
|
171
|
+
scratch[j] = &(*param_matrix[j])[0];
|
168
172
|
}
|
169
|
-
std::vector<int> indexes(
|
173
|
+
std::vector<int> indexes(ranges.size(), 0);
|
170
174
|
|
171
175
|
const std::size_t max = ranges.size() - 1;
|
176
|
+
const std::size_t length = ranges.size();
|
177
|
+
std::size_t j = 0;
|
172
178
|
for(std::size_t i = max;;) {
|
173
179
|
|
174
180
|
if(i == max) {
|
175
181
|
for(std::size_t val = 0; val <= ranges[i]; val++) {
|
176
|
-
scratch[i] = param_matrix[i][indexes[i]];
|
177
|
-
|
182
|
+
scratch[i] = &(*param_matrix[i])[indexes[i]];
|
183
|
+
std::copy(scratch, scratch+length, param_cache);
|
184
|
+
results.push_front(param_cache);
|
185
|
+
param_cache += length;
|
178
186
|
indexes[i]++;
|
187
|
+
j++;
|
179
188
|
}
|
180
189
|
indexes[i] = 0;
|
181
190
|
i--;
|
182
191
|
} else if(i == 0 && indexes[i] >= ranges[i]) {
|
183
|
-
return;
|
192
|
+
return j;
|
184
193
|
} else if(indexes[i] < ranges[i]) {
|
185
194
|
indexes[i]++;
|
186
|
-
scratch[i] = param_matrix[i][indexes[i]];
|
195
|
+
scratch[i] = &(*param_matrix[i])[indexes[i]];
|
187
196
|
i++;
|
188
197
|
} else {
|
189
198
|
indexes[i] = -1;
|
data/ext/dither/ipog.cc
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
#include <tuple>
|
15
15
|
#include <limits.h>
|
16
16
|
#include <cstddef>
|
17
|
+
#include <memory>
|
17
18
|
|
18
19
|
namespace dither {
|
19
20
|
|
@@ -27,9 +28,7 @@ Ipog::Ipog() {
|
|
27
28
|
t_ = 2;
|
28
29
|
}
|
29
30
|
|
30
|
-
Ipog::Ipog(const unsigned int t) {
|
31
|
-
t_ = t;
|
32
|
-
}
|
31
|
+
Ipog::Ipog(const unsigned int t) : t_(t) {}
|
33
32
|
|
34
33
|
void Ipog::init_bound() {
|
35
34
|
using dither::product3;
|
@@ -56,7 +55,7 @@ void Ipog::init_bound() {
|
|
56
55
|
}
|
57
56
|
}
|
58
57
|
|
59
|
-
|
58
|
+
inline param** Ipog::cover(const int k, std::forward_list<param**> &coverage) {
|
60
59
|
std::vector<int> input(k);
|
61
60
|
for (std::size_t i = 0; i < k; i++) {
|
62
61
|
input[i] = i;
|
@@ -64,30 +63,35 @@ std::forward_list<std::vector<param>> Ipog::cover(const int k) {
|
|
64
63
|
|
65
64
|
std::forward_list<std::vector<int>> output;
|
66
65
|
combinations(t_ - 1, input, output);
|
67
|
-
std::forward_list<std::vector<std::vector<param
|
68
|
-
|
66
|
+
std::forward_list<std::vector<std::vector<param>*>> product_input;
|
67
|
+
int count = 0;
|
69
68
|
for (auto it = output.begin(); it != output.end(); ++it) {
|
70
|
-
std::vector<std::vector<param
|
69
|
+
std::vector<std::vector<param>*> param_tuple;
|
71
70
|
(*it).push_back(k);
|
71
|
+
int inner_count = 1;
|
72
72
|
for (auto iit = (*it).begin(); iit != (*it).end(); ++iit) {
|
73
|
-
|
74
|
-
|
73
|
+
param_tuple.push_back(¶m_cache_[*iit]);
|
74
|
+
inner_count *= param_cache_[*iit].size();
|
75
75
|
}
|
76
|
+
count += inner_count;
|
76
77
|
product_input.push_front(param_tuple);
|
77
78
|
}
|
78
79
|
|
79
|
-
|
80
|
+
param **local_param_cache = new param*[count*t_];
|
81
|
+
std::size_t j = 0;
|
80
82
|
for (auto it = product_input.begin(); it != product_input.end(); ++it) {
|
81
|
-
product4(coverage, *it);
|
83
|
+
j += t_*product4(coverage, local_param_cache+j, *it);
|
82
84
|
}
|
83
|
-
coverage.remove_if([this](
|
84
|
-
return
|
85
|
+
coverage.remove_if([this](param **a) { return has_previously_tested(a); });
|
86
|
+
return local_param_cache;
|
85
87
|
}
|
86
88
|
|
87
89
|
void Ipog::run() {
|
88
90
|
init_bound();
|
89
91
|
for (auto k = t_; k < input_params_.size(); k++) {
|
90
|
-
std::forward_list<
|
92
|
+
std::forward_list<param**> pi;
|
93
|
+
param **params = cover(k, pi);
|
94
|
+
std::unique_ptr<param*[]> params_ptr(params);
|
91
95
|
|
92
96
|
{
|
93
97
|
auto prev = bound_.cbefore_begin();
|
@@ -105,8 +109,8 @@ void Ipog::run() {
|
|
105
109
|
|
106
110
|
/* vertical extension */
|
107
111
|
for (auto pairs = pi.cbegin(); pairs != pi.cend(); ++pairs) {
|
108
|
-
|
109
|
-
bool case_covered = constraint_handler->violate_constraints(test_case);
|
112
|
+
param **test_case = *pairs;
|
113
|
+
bool case_covered = constraint_handler->violate_constraints(test_case, t_);
|
110
114
|
|
111
115
|
if(!case_covered) {
|
112
116
|
for (auto it = unbound_.cbegin(); it != unbound_.cend(); ++it) {
|
@@ -125,8 +129,9 @@ void Ipog::run() {
|
|
125
129
|
|
126
130
|
if (merge_result > 0) {
|
127
131
|
dtest_case tmp = *next;
|
128
|
-
for
|
129
|
-
|
132
|
+
for(std::size_t i = 0; i < t_; i++) {
|
133
|
+
const param *it = test_case[i];
|
134
|
+
tmp[it->first] = it->second;
|
130
135
|
}
|
131
136
|
is_merged = true;
|
132
137
|
break;
|
@@ -135,8 +140,9 @@ void Ipog::run() {
|
|
135
140
|
|
136
141
|
if (!is_merged) {
|
137
142
|
dtest_case unbound_test_case(param_cache_.size(), -1);
|
138
|
-
for
|
139
|
-
|
143
|
+
for(std::size_t i = 0; i < t_; i++) {
|
144
|
+
const param *it = test_case[i];
|
145
|
+
unbound_test_case[it->first] = it->second;
|
140
146
|
}
|
141
147
|
if (!constraint_handler->violate_constraints(unbound_test_case)) {
|
142
148
|
unbound_.push_front(unbound_test_case);
|
@@ -150,18 +156,20 @@ void Ipog::run() {
|
|
150
156
|
|
151
157
|
/* -1 no merge, 0 perfect merge (no unbound), 1 partial merge */
|
152
158
|
inline const int Ipog::merge(const int k, dtest_case &test_case,
|
153
|
-
|
154
|
-
for
|
155
|
-
|
156
|
-
|
159
|
+
param** pairs) {
|
160
|
+
for(std::size_t i = 0; i < t_; i++) {
|
161
|
+
const param *it = pairs[i];
|
162
|
+
auto value = test_case[it->first];
|
163
|
+
if (!(value == -1 || value == it->second)) {
|
157
164
|
return -1;
|
158
165
|
}
|
159
166
|
}
|
160
167
|
|
161
168
|
std::copy(test_case.cbegin(), test_case.cend(), merge_scratch_.begin());
|
162
169
|
|
163
|
-
for
|
164
|
-
|
170
|
+
for(std::size_t i = 0; i < t_; i++) {
|
171
|
+
const param *it = pairs[i];
|
172
|
+
merge_scratch_[it->first] = it->second;
|
165
173
|
}
|
166
174
|
|
167
175
|
if (constraint_handler->violate_constraints(merge_scratch_)) {
|
@@ -178,24 +186,34 @@ inline const int Ipog::merge(const int k, dtest_case &test_case,
|
|
178
186
|
}
|
179
187
|
|
180
188
|
inline bool Ipog::is_covered(const dtest_case &test_case,
|
181
|
-
|
189
|
+
param** params) {
|
190
|
+
for(std::size_t i = 0; i < t_; i++) {
|
191
|
+
const param *my_param = params[i];
|
192
|
+
if (test_case[my_param->first] != my_param->second) {
|
193
|
+
return false;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
return true;
|
197
|
+
}
|
198
|
+
inline bool Ipog::is_covered(const dtest_case &test_case,
|
199
|
+
const std::vector<param*> ¶ms) {
|
182
200
|
for (auto param = params.cbegin(); param != params.cend(); ++param) {
|
183
|
-
if (test_case[(*param)
|
201
|
+
if (test_case[(*param)->first] != (*param)->second) {
|
184
202
|
return false;
|
185
203
|
}
|
186
204
|
}
|
187
205
|
return true;
|
188
206
|
}
|
189
207
|
|
190
|
-
const int Ipog::maximize_coverage(const int k, dtest_case &test_case,
|
191
|
-
std::forward_list<
|
208
|
+
inline const int Ipog::maximize_coverage(const int k, dtest_case &test_case,
|
209
|
+
std::forward_list<param**> &pi) {
|
192
210
|
const std::vector<param> ¶m_range = param_cache_[k];
|
193
211
|
int current_max = -1;
|
194
212
|
param max_param = param_range[0];
|
195
|
-
std::forward_list<std::forward_list<
|
213
|
+
std::forward_list<std::forward_list<param**>::iterator> covered;
|
196
214
|
|
197
215
|
for (auto it = param_range.cbegin(); it != param_range.cend(); ++it) {
|
198
|
-
std::forward_list<std::forward_list<
|
216
|
+
std::forward_list<std::forward_list<param**>::iterator>
|
199
217
|
tmp_covered;
|
200
218
|
const param current_param = *it;
|
201
219
|
|
@@ -203,12 +221,11 @@ const int Ipog::maximize_coverage(const int k, dtest_case &test_case,
|
|
203
221
|
if (!constraint_handler->violate_constraints(test_case)) {
|
204
222
|
int count = 0;
|
205
223
|
auto prev = pi.before_begin();
|
206
|
-
for (auto params = pi.
|
224
|
+
for (auto params = pi.begin(); params != pi.end(); ++params, ++prev) {
|
207
225
|
if (is_covered(test_case, *params)) {
|
208
226
|
tmp_covered.push_front(prev);
|
209
227
|
count++;
|
210
228
|
}
|
211
|
-
++prev;
|
212
229
|
}
|
213
230
|
|
214
231
|
if (count > current_max) {
|
@@ -367,7 +384,7 @@ std::string *Ipog::header() {
|
|
367
384
|
constraints.push_back(tmp);
|
368
385
|
}
|
369
386
|
|
370
|
-
void Ipog::ground_solutions() {
|
387
|
+
inline void Ipog::ground_solutions() {
|
371
388
|
std::size_t solution_count = 0;
|
372
389
|
std::vector<dval> transform_scratch(param_cache_.size(), 0);
|
373
390
|
|
@@ -414,11 +431,28 @@ void Ipog::add_previously_tested(const int values[], const std::size_t length) {
|
|
414
431
|
original_previously_tested_.push_back(tmp);
|
415
432
|
}
|
416
433
|
|
417
|
-
inline bool Ipog::has_previously_tested(std::vector<param
|
434
|
+
inline bool Ipog::has_previously_tested(std::vector<param*>& test_case) {
|
418
435
|
for(auto it = previously_tested_.cbegin(); it != previously_tested_.cend(); ++it) {
|
419
436
|
bool flag = true;
|
420
437
|
for(auto iit = test_case.cbegin(); iit != test_case.cend(); ++iit) {
|
421
|
-
if((*it)[(*iit)
|
438
|
+
if((*it)[(*iit)->first] != (*iit)->second) {
|
439
|
+
flag = false;
|
440
|
+
break;
|
441
|
+
}
|
442
|
+
}
|
443
|
+
if(flag) {
|
444
|
+
return true;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
return false;
|
448
|
+
}
|
449
|
+
|
450
|
+
inline bool Ipog::has_previously_tested(param **params) {
|
451
|
+
for(auto it = previously_tested_.cbegin(); it != previously_tested_.cend(); ++it) {
|
452
|
+
bool flag = true;
|
453
|
+
for(std::size_t i = 0; i < t_; i++) {
|
454
|
+
const param *iit = params[i];
|
455
|
+
if((*it)[iit->first] != iit->second) {
|
422
456
|
flag = false;
|
423
457
|
break;
|
424
458
|
}
|
data/ext/dither/ipog.h
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
#include <algorithm>
|
17
17
|
#include <string>
|
18
18
|
#include <unordered_map>
|
19
|
+
#include <memory>
|
19
20
|
#include "combinations.h"
|
20
21
|
#include "dither_types.h"
|
21
22
|
#include "base_constraint_handler.h"
|
@@ -52,9 +53,10 @@ class Ipog {
|
|
52
53
|
std::copy(scratch.cbegin(), scratch.cend(), test_case.begin());
|
53
54
|
}
|
54
55
|
|
55
|
-
inline bool has_previously_tested(std::vector<param
|
56
|
+
inline bool has_previously_tested(std::vector<param*>& test_case);
|
56
57
|
inline bool has_previously_tested(dtest_case& test_case);
|
57
58
|
inline bool has_previously_tested(const int, dtest_case& test_case);
|
59
|
+
inline bool has_previously_tested(param **params);
|
58
60
|
|
59
61
|
public:
|
60
62
|
Ipog();
|
@@ -69,17 +71,20 @@ class Ipog {
|
|
69
71
|
void run();
|
70
72
|
int size();
|
71
73
|
std::string *header();
|
72
|
-
void ground_solutions();
|
74
|
+
inline void ground_solutions();
|
73
75
|
inline bool is_valid() { return t_ <= param_cache_.size(); }
|
74
|
-
std::forward_list<
|
75
|
-
const int maximize_coverage(const int, dtest_case &,
|
76
|
-
std::forward_list<
|
76
|
+
inline param** cover(int,std::forward_list<param**>&);
|
77
|
+
inline const int maximize_coverage(const int, dtest_case &,
|
78
|
+
std::forward_list<param**> &);
|
77
79
|
void add_constraint(const int[], const unsigned int);
|
78
80
|
void add_previously_tested(const int[], const std::size_t);
|
79
81
|
inline bool is_covered(const dtest_case &test_case,
|
80
|
-
|
82
|
+
param** params);
|
83
|
+
inline bool is_covered(const param** params);
|
84
|
+
inline bool is_covered(const dtest_case &test_case,
|
85
|
+
const std::vector<param*> ¶ms);
|
81
86
|
inline bool is_covered(const std::vector<param> ¶ms);
|
82
|
-
inline const int merge(const int, dtest_case &,
|
87
|
+
inline const int merge(const int, dtest_case &, param**);
|
83
88
|
void display_raw_solution();
|
84
89
|
void fill(int[]);
|
85
90
|
inline void display_header() {
|
@@ -53,10 +53,22 @@ namespace dither {
|
|
53
53
|
return true;
|
54
54
|
}
|
55
55
|
|
56
|
-
bool SimpleConstraintHandler::violate_constraints(const std::
|
56
|
+
bool SimpleConstraintHandler::violate_constraints(param** test_case, const std::size_t length) {
|
57
|
+
std::fill(scratch.begin(), scratch.end(), -1);
|
58
|
+
for(std::size_t i = 0; i < length; i++) {
|
59
|
+
const param *p = test_case[i];
|
60
|
+
scratch[p->first] = p->second;
|
61
|
+
}
|
62
|
+
if(violate_constraints_(scratch)) {
|
63
|
+
return true;
|
64
|
+
}
|
65
|
+
return !ground(scratch);
|
66
|
+
}
|
67
|
+
|
68
|
+
bool SimpleConstraintHandler::violate_constraints(const std::vector<param*> &test_case) {
|
57
69
|
std::fill(scratch.begin(), scratch.end(), -1);
|
58
70
|
for(auto p : test_case) {
|
59
|
-
scratch[p
|
71
|
+
scratch[p->first] = p->second;
|
60
72
|
}
|
61
73
|
if(violate_constraints_(scratch)) {
|
62
74
|
return true;
|
@@ -30,7 +30,8 @@ namespace dither {
|
|
30
30
|
public:
|
31
31
|
SimpleConstraintHandler(std::vector<dval>& ranges, std::vector<std::vector<dval>>& pconstraints);
|
32
32
|
bool violate_constraints(const dtest_case &test_case);
|
33
|
-
bool violate_constraints(const std::vector<param
|
33
|
+
bool violate_constraints(const std::vector<param*> &test_case);
|
34
|
+
bool violate_constraints(param** test_case, const std::size_t length);
|
34
35
|
bool ground(dtest_case &test_case);
|
35
36
|
};
|
36
37
|
}
|
data/lib/dither.rb
CHANGED