dither 0.1.5-java → 0.2.0-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/Gemfile.lock +6 -1
- data/README.md +3 -0
- data/Rakefile +4 -0
- data/dither.gemspec +5 -1
- data/ext/dither/README.md +2 -0
- data/ext/dither/base_constraint_handler.h +36 -0
- data/ext/dither/combinations.h +127 -0
- data/ext/dither/dither.cc +47 -0
- data/ext/dither/dither.h +31 -0
- data/ext/dither/dither_types.h +32 -0
- data/ext/dither/extconf.rb +4 -0
- data/ext/dither/ipog.cc +451 -0
- data/ext/dither/ipog.h +128 -0
- data/ext/dither/simple_constraint_handler.cc +105 -0
- data/ext/dither/simple_constraint_handler.h +39 -0
- data/lib/dither/api.rb +21 -0
- data/lib/dither/version.rb +1 -1
- data/lib/{dither-0.1.3.jar → dither-0.1.4.jar} +0 -0
- data/lib/dither.rb +65 -14
- data/spec/dither/dither_spec.rb +28 -97
- metadata +42 -22
- data/lib/dither/ipog.rb +0 -58
- data/lib/dither/ipog_helper.rb +0 -161
- data/lib/dither/mipog.rb +0 -85
- data/lib/dither/param.rb +0 -19
- data/lib/dither/test_case.rb +0 -80
- data/lib/dither/unbound_param.rb +0 -17
data/ext/dither/ipog.cc
ADDED
@@ -0,0 +1,451 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright (C) 2015 Jason Gowan
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This software may be modified and distributed under the terms
|
7
|
+
* of the BSD license. See the LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "ipog.h"
|
11
|
+
#include <forward_list>
|
12
|
+
#include <iterator>
|
13
|
+
#include <utility>
|
14
|
+
#include <tuple>
|
15
|
+
#include <limits.h>
|
16
|
+
|
17
|
+
namespace dither {
|
18
|
+
|
19
|
+
Ipog::~Ipog() {
|
20
|
+
if(constraint_handler != NULL) {
|
21
|
+
delete constraint_handler;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
Ipog::Ipog() {
|
26
|
+
t_ = 2;
|
27
|
+
}
|
28
|
+
|
29
|
+
Ipog::Ipog(const unsigned int t) {
|
30
|
+
t_ = t;
|
31
|
+
}
|
32
|
+
|
33
|
+
void Ipog::init_bound() {
|
34
|
+
using dither::product;
|
35
|
+
dtest_case tmp;
|
36
|
+
|
37
|
+
product(bound_, tmp, input_params_.begin(), input_params_.begin() + t_);
|
38
|
+
auto size = param_cache_.size();
|
39
|
+
for (auto it = bound_.begin(); it != bound_.end(); ++it) {
|
40
|
+
(*it).resize(size, -1);
|
41
|
+
(*it).shrink_to_fit();
|
42
|
+
}
|
43
|
+
bound_.remove_if([this](dtest_case& a) { return has_previously_tested(a); });
|
44
|
+
|
45
|
+
merge_scratch_.resize(param_cache_.size(), -1);
|
46
|
+
|
47
|
+
if(constraints.size() > 0) {
|
48
|
+
for(auto it = param_cache_.cbegin(); it != param_cache_.cend(); ++it) {
|
49
|
+
const dval tmp = (*it).size() - 1;
|
50
|
+
ranges.push_back(tmp);
|
51
|
+
}
|
52
|
+
constraint_handler = new SimpleConstraintHandler(ranges, constraints);
|
53
|
+
} else {
|
54
|
+
constraint_handler = new BaseConstraintHandler();
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
std::forward_list<std::vector<param>> Ipog::cover(const int k) {
|
59
|
+
std::vector<int> input(k);
|
60
|
+
for (std::size_t i = 0; i < k; i++) {
|
61
|
+
input[i] = i;
|
62
|
+
}
|
63
|
+
|
64
|
+
std::forward_list<std::vector<int>> output;
|
65
|
+
combinations(t_ - 1, input, output);
|
66
|
+
std::forward_list<std::vector<std::vector<param>>> product_input;
|
67
|
+
const std::vector<param> k_param = param_cache_[k];
|
68
|
+
for (auto it = output.begin(); it != output.end(); ++it) {
|
69
|
+
std::vector<std::vector<param>> param_tuple;
|
70
|
+
(*it).push_back(k);
|
71
|
+
for (auto iit = (*it).begin(); iit != (*it).end(); ++iit) {
|
72
|
+
auto vals = param_cache_[*iit];
|
73
|
+
param_tuple.push_back(vals);
|
74
|
+
}
|
75
|
+
product_input.push_front(param_tuple);
|
76
|
+
}
|
77
|
+
|
78
|
+
std::forward_list<std::vector<param>> coverage;
|
79
|
+
for (auto it = product_input.begin(); it != product_input.end(); ++it) {
|
80
|
+
std::vector<param> tmp;
|
81
|
+
std::vector<std::vector<param>> x = *it;
|
82
|
+
product2(coverage, tmp, (*it).cbegin(), (*it).cend());
|
83
|
+
}
|
84
|
+
coverage.remove_if([this](std::vector<param>& a) { return has_previously_tested(a); });
|
85
|
+
return coverage;
|
86
|
+
}
|
87
|
+
|
88
|
+
void Ipog::run() {
|
89
|
+
init_bound();
|
90
|
+
for (auto k = t_; k < input_params_.size(); k++) {
|
91
|
+
std::forward_list<std::vector<param>> pi = cover(k);
|
92
|
+
|
93
|
+
{
|
94
|
+
auto prev = bound_.cbefore_begin();
|
95
|
+
auto next = bound_.begin();
|
96
|
+
auto end = bound_.cend();
|
97
|
+
while (next != end) {
|
98
|
+
if (maximize_coverage(k, *next, pi) == -1) {
|
99
|
+
next = bound_.erase_after(prev);
|
100
|
+
} else {
|
101
|
+
++prev;
|
102
|
+
++next;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
/* vertical extension */
|
108
|
+
for (auto pairs = pi.cbegin(); pairs != pi.cend(); ++pairs) {
|
109
|
+
const std::vector<param> &test_case = *pairs;
|
110
|
+
bool case_covered = constraint_handler->violate_constraints(test_case);
|
111
|
+
|
112
|
+
if (!case_covered) {
|
113
|
+
bool is_merged = false;
|
114
|
+
auto prev = unbound_.before_begin();
|
115
|
+
auto next = unbound_.begin();
|
116
|
+
auto end = unbound_.end();
|
117
|
+
while (next != end) {
|
118
|
+
const int merge_result = merge(k, *next, test_case);
|
119
|
+
if (merge_result == 0) {
|
120
|
+
bound_.push_front(*next);
|
121
|
+
unbound_.erase_after(prev);
|
122
|
+
is_merged = true;
|
123
|
+
break;
|
124
|
+
} else if (merge_result == 1) {
|
125
|
+
is_merged = true;
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
++prev;
|
129
|
+
++next;
|
130
|
+
}
|
131
|
+
|
132
|
+
if (!is_merged) {
|
133
|
+
dtest_case unbound_test_case(param_cache_.size(), -1);
|
134
|
+
for (auto it = test_case.cbegin(); it != test_case.cend(); ++it) {
|
135
|
+
unbound_test_case[(*it).first] = (*it).second;
|
136
|
+
}
|
137
|
+
if (!constraint_handler->violate_constraints(unbound_test_case)) {
|
138
|
+
unbound_.push_front(unbound_test_case);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
}
|
144
|
+
}
|
145
|
+
ground_solutions();
|
146
|
+
}
|
147
|
+
|
148
|
+
/* -1 no merge, 0 perfect merge (no unbound), 1 partial merge */
|
149
|
+
inline const int Ipog::merge(const int k, dtest_case &test_case,
|
150
|
+
const std::vector<param> &pairs) {
|
151
|
+
for (auto it = pairs.cbegin(); it != pairs.cend(); ++it) {
|
152
|
+
auto value = test_case[(*it).first];
|
153
|
+
if (!(value == -1 || value == (*it).second)) {
|
154
|
+
return -1;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
std::copy(test_case.cbegin(), test_case.cend(), merge_scratch_.begin());
|
159
|
+
|
160
|
+
for (auto it = pairs.cbegin(); it != pairs.cend(); ++it) {
|
161
|
+
merge_scratch_[(*it).first] = (*it).second;
|
162
|
+
}
|
163
|
+
|
164
|
+
if (constraint_handler->violate_constraints(merge_scratch_)) {
|
165
|
+
return -1;
|
166
|
+
}
|
167
|
+
|
168
|
+
for (auto it = pairs.cbegin(); it != pairs.cend(); ++it) {
|
169
|
+
test_case[(*it).first] = (*it).second;
|
170
|
+
}
|
171
|
+
|
172
|
+
for (auto i = 0; i < k; i++) {
|
173
|
+
if (test_case[i] == -1) {
|
174
|
+
return 1;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
return 0;
|
179
|
+
}
|
180
|
+
|
181
|
+
inline bool Ipog::is_covered(const dtest_case &test_case,
|
182
|
+
const std::vector<param> ¶ms) {
|
183
|
+
for (auto param = params.cbegin(); param != params.cend(); ++param) {
|
184
|
+
if (test_case[(*param).first] != (*param).second) {
|
185
|
+
return false;
|
186
|
+
}
|
187
|
+
}
|
188
|
+
return true;
|
189
|
+
}
|
190
|
+
|
191
|
+
const int Ipog::maximize_coverage(const int k, dtest_case &test_case,
|
192
|
+
std::forward_list<std::vector<param>> &pi) {
|
193
|
+
const std::vector<param> ¶m_range = param_cache_[k];
|
194
|
+
int current_max = -1;
|
195
|
+
param max_param = param_range[0];
|
196
|
+
std::forward_list<std::forward_list<std::vector<param>>::iterator> covered;
|
197
|
+
|
198
|
+
for (auto it = param_range.cbegin(); it != param_range.cend(); ++it) {
|
199
|
+
std::forward_list<std::forward_list<std::vector<param>>::iterator>
|
200
|
+
tmp_covered;
|
201
|
+
const param current_param = *it;
|
202
|
+
|
203
|
+
test_case[current_param.first] = current_param.second;
|
204
|
+
if (!constraint_handler->violate_constraints(test_case)) {
|
205
|
+
int count = 0;
|
206
|
+
auto prev = pi.before_begin();
|
207
|
+
for (auto params = pi.cbegin(); params != pi.cend(); ++params) {
|
208
|
+
if (is_covered(test_case, *params)) {
|
209
|
+
tmp_covered.push_front(prev);
|
210
|
+
count++;
|
211
|
+
}
|
212
|
+
++prev;
|
213
|
+
}
|
214
|
+
|
215
|
+
if (count > current_max) {
|
216
|
+
current_max = count;
|
217
|
+
max_param = current_param;
|
218
|
+
covered = tmp_covered;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
test_case[current_param.first] = -1;
|
222
|
+
}
|
223
|
+
|
224
|
+
if (current_max == -1) {
|
225
|
+
return -1;
|
226
|
+
}
|
227
|
+
|
228
|
+
/* remove covered */
|
229
|
+
for (auto it = covered.begin(); it != covered.end(); ++it) {
|
230
|
+
pi.erase_after(*it);
|
231
|
+
}
|
232
|
+
|
233
|
+
test_case[max_param.first] = max_param.second;
|
234
|
+
return current_max;
|
235
|
+
}
|
236
|
+
|
237
|
+
void Ipog::display_raw_solution() {
|
238
|
+
/* display_header(); */
|
239
|
+
for (auto it = bound_.cbegin(); it != bound_.cend(); ++it) {
|
240
|
+
display_test_case(*it);
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
void Ipog::add_parameter(const std::string name, const int *terms,
|
245
|
+
const unsigned int terms_length) {
|
246
|
+
std::vector<int> tmp(terms, terms + terms_length);
|
247
|
+
std::pair<std::string, std::vector<int>> key_value(name, tmp);
|
248
|
+
int_params_.insert(key_value);
|
249
|
+
ordered_param_names_.push_back(name);
|
250
|
+
}
|
251
|
+
|
252
|
+
void Ipog::add_parameter(const std::string name, const std::string *terms,
|
253
|
+
const unsigned int terms_length) {
|
254
|
+
std::vector<std::string> tmp(terms, terms + terms_length);
|
255
|
+
std::pair<std::string, std::vector<std::string>> key_value(name, tmp);
|
256
|
+
str_params_.insert(key_value);
|
257
|
+
ordered_param_names_.push_back(name);
|
258
|
+
}
|
259
|
+
|
260
|
+
void Ipog::add_parameter(const std::string name) {
|
261
|
+
const bool arr[] = {true, false};
|
262
|
+
std::vector<bool> tmp(arr, arr + 2);
|
263
|
+
std::pair<std::string, std::vector<bool>> key_value(name, tmp);
|
264
|
+
bool_params_.insert(key_value);
|
265
|
+
ordered_param_names_.push_back(name);
|
266
|
+
}
|
267
|
+
|
268
|
+
void Ipog::init_param_cache() {
|
269
|
+
std::vector<std::tuple<std::string, int, int>> tmp;
|
270
|
+
for (auto it = int_params_.cbegin(); it != int_params_.cend(); ++it) {
|
271
|
+
if ((*it).second.size() < 1) {
|
272
|
+
continue;
|
273
|
+
}
|
274
|
+
tmp.push_back(
|
275
|
+
std::make_tuple((*it).first, DITHER_INT_T, (*it).second.size()));
|
276
|
+
}
|
277
|
+
|
278
|
+
for (auto it = str_params_.cbegin(); it != str_params_.cend(); ++it) {
|
279
|
+
if ((*it).second.size() < 1) {
|
280
|
+
continue;
|
281
|
+
}
|
282
|
+
tmp.push_back(
|
283
|
+
std::make_tuple((*it).first, DITHER_STRING_T, (*it).second.size()));
|
284
|
+
}
|
285
|
+
|
286
|
+
for (auto it = bool_params_.cbegin(); it != bool_params_.cend(); ++it) {
|
287
|
+
if ((*it).second.size() < 1) {
|
288
|
+
continue;
|
289
|
+
}
|
290
|
+
tmp.push_back(
|
291
|
+
std::make_tuple((*it).first, DITHER_BOOL_T, (*it).second.size()));
|
292
|
+
}
|
293
|
+
|
294
|
+
std::sort(tmp.begin(), tmp.end(), [](std::tuple<std::string, int, int> a,
|
295
|
+
std::tuple<std::string, int, int> b) {
|
296
|
+
return std::get<2>(a) > std::get<2>(b);
|
297
|
+
});
|
298
|
+
|
299
|
+
std::unordered_map<std::string, int> original_name_to_index;
|
300
|
+
int count = 0;
|
301
|
+
for(auto it = ordered_param_names_.cbegin(); it != ordered_param_names_.cend(); ++it, count++) {
|
302
|
+
original_name_to_index.insert({{*it, count}});
|
303
|
+
}
|
304
|
+
ordered_param_index_.resize(tmp.size());
|
305
|
+
reverse_ordered_param_index_.resize(tmp.size());
|
306
|
+
|
307
|
+
count = 0;
|
308
|
+
for (auto it = tmp.cbegin(); it != tmp.cend(); ++it, count++) {
|
309
|
+
std::vector<param> params;
|
310
|
+
std::vector<dval> dvals;
|
311
|
+
auto name = std::get<0>(*it);
|
312
|
+
auto type = std::get<1>(*it);
|
313
|
+
reverse_param_index_.insert({{count, name}});
|
314
|
+
ordered_param_index_[count] = original_name_to_index.find(name)->second;
|
315
|
+
reverse_ordered_param_index_[original_name_to_index.find(name)->second] = count;
|
316
|
+
|
317
|
+
for (dval i = 0; i < SCHAR_MAX && i < std::get<2>(*it); i++) {
|
318
|
+
param my_param;
|
319
|
+
my_param.first = count;
|
320
|
+
my_param.second = i;
|
321
|
+
my_param.name = name;
|
322
|
+
my_param.type = type;
|
323
|
+
|
324
|
+
params.push_back(my_param);
|
325
|
+
dvals.push_back(i);
|
326
|
+
}
|
327
|
+
param_cache_.push_back(params);
|
328
|
+
input_params_.push_back(dvals);
|
329
|
+
}
|
330
|
+
|
331
|
+
std::vector<dval> scratch(param_cache_.size());
|
332
|
+
for(auto it = original_previously_tested_.cbegin(); it != original_previously_tested_.cend(); ++it) {
|
333
|
+
for(std::size_t i = 0; i < scratch.size(); i++) {
|
334
|
+
scratch[reverse_ordered_param_index_[i]] = (*it)[i];
|
335
|
+
}
|
336
|
+
previously_tested_.push_back(scratch);
|
337
|
+
}
|
338
|
+
|
339
|
+
// transform constraints
|
340
|
+
for(std::size_t j = 0; j < constraints.size(); j++) {
|
341
|
+
for(std::size_t i = 0; i < scratch.size(); i++) {
|
342
|
+
scratch[reverse_ordered_param_index_[i]] = constraints[j][i];
|
343
|
+
}
|
344
|
+
std::copy(scratch.begin(), scratch.end(), constraints[j].begin());
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
int Ipog::size() {
|
349
|
+
return solution_size;
|
350
|
+
}
|
351
|
+
|
352
|
+
std::string *Ipog::header() {
|
353
|
+
std::string *result = new std::string[param_cache_.size()];
|
354
|
+
for (std::size_t i = 0; i < param_cache_.size(); i++) {
|
355
|
+
result[i] = reverse_param_index_[i];
|
356
|
+
}
|
357
|
+
return result;
|
358
|
+
}
|
359
|
+
|
360
|
+
void Ipog::add_constraint(const int* constraint, const unsigned int length) {
|
361
|
+
std::vector<dval> tmp(length);
|
362
|
+
std::copy(constraint, constraint+length, tmp.begin());
|
363
|
+
for(auto it = tmp.cbegin(); it != tmp.cend(); ++it) {
|
364
|
+
if((*it) > SCHAR_MAX) {
|
365
|
+
std::cerr << "WARNING: constraint value > " << SCHAR_MAX << " behavior undefined" << std::endl;
|
366
|
+
}
|
367
|
+
}
|
368
|
+
constraints.push_back(tmp);
|
369
|
+
}
|
370
|
+
|
371
|
+
void Ipog::ground_solutions() {
|
372
|
+
std::size_t solution_count = 0;
|
373
|
+
std::vector<dval> transform_scratch(param_cache_.size(), 0);
|
374
|
+
|
375
|
+
auto prev = bound_.cbefore_begin();
|
376
|
+
auto next = bound_.begin();
|
377
|
+
auto end = bound_.cend();
|
378
|
+
while (next != end) {
|
379
|
+
if (constraint_handler->violate_constraints(*next) || has_previously_tested(*next)) {
|
380
|
+
next = bound_.erase_after(prev);
|
381
|
+
} else {
|
382
|
+
transform(transform_scratch, *next);
|
383
|
+
solution_count++;
|
384
|
+
++prev;
|
385
|
+
++next;
|
386
|
+
}
|
387
|
+
}
|
388
|
+
|
389
|
+
while(!unbound_.empty()) {
|
390
|
+
dtest_case first = unbound_.front();
|
391
|
+
if(constraint_handler->ground(first)) {
|
392
|
+
if(!has_previously_tested(first)) {
|
393
|
+
transform(transform_scratch, first);
|
394
|
+
solution_count++;
|
395
|
+
bound_.push_front(first);
|
396
|
+
}
|
397
|
+
}
|
398
|
+
unbound_.pop_front();
|
399
|
+
}
|
400
|
+
solution_size = solution_count;
|
401
|
+
}
|
402
|
+
|
403
|
+
void Ipog::fill(int *solution) {
|
404
|
+
std::size_t i = 0;
|
405
|
+
for(auto it = bound_.cbegin(); it != bound_.cend(); ++it) {
|
406
|
+
for(auto iit = (*it).cbegin(); iit != (*it).cend(); ++iit, i++) {
|
407
|
+
solution[i] = *iit;
|
408
|
+
}
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
void Ipog::add_previously_tested(const int values[], const std::size_t length) {
|
413
|
+
std::vector<dval> tmp(length);
|
414
|
+
std::copy(values, values+length, tmp.begin());
|
415
|
+
original_previously_tested_.push_back(tmp);
|
416
|
+
}
|
417
|
+
|
418
|
+
inline bool Ipog::has_previously_tested(std::vector<param>& test_case) {
|
419
|
+
for(auto it = previously_tested_.cbegin(); it != previously_tested_.cend(); ++it) {
|
420
|
+
bool flag = true;
|
421
|
+
for(auto iit = test_case.cbegin(); iit != test_case.cend(); ++iit) {
|
422
|
+
if((*it)[(*iit).first] != (*iit).second) {
|
423
|
+
flag = false;
|
424
|
+
break;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
if(flag) {
|
428
|
+
return true;
|
429
|
+
}
|
430
|
+
}
|
431
|
+
return false;
|
432
|
+
}
|
433
|
+
|
434
|
+
inline bool Ipog::has_previously_tested(dtest_case& test_case) {
|
435
|
+
for(auto it = previously_tested_.cbegin(); it != previously_tested_.cend(); ++it) {
|
436
|
+
if(std::equal(test_case.cbegin(), test_case.cend(), (*it).cbegin())) {
|
437
|
+
return true;
|
438
|
+
}
|
439
|
+
}
|
440
|
+
return false;
|
441
|
+
}
|
442
|
+
|
443
|
+
inline bool Ipog::has_previously_tested(const int k, dtest_case& test_case) {
|
444
|
+
for(auto it = previously_tested_.cbegin(); it != previously_tested_.cend(); ++it) {
|
445
|
+
if(std::equal(test_case.cbegin(), test_case.cbegin()+k, (*it).cbegin())) {
|
446
|
+
return true;
|
447
|
+
}
|
448
|
+
}
|
449
|
+
return false;
|
450
|
+
}
|
451
|
+
}
|
data/ext/dither/ipog.h
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright (C) 2015 Jason Gowan
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This software may be modified and distributed under the terms
|
7
|
+
* of the BSD license. See the LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#ifndef IPOG_H_
|
11
|
+
#define IPOG_H_
|
12
|
+
|
13
|
+
#include <vector>
|
14
|
+
#include <iostream>
|
15
|
+
#include <forward_list>
|
16
|
+
#include <algorithm>
|
17
|
+
#include <string>
|
18
|
+
#include <unordered_map>
|
19
|
+
#include "combinations.h"
|
20
|
+
#include "dither_types.h"
|
21
|
+
#include "base_constraint_handler.h"
|
22
|
+
#include "simple_constraint_handler.h"
|
23
|
+
|
24
|
+
namespace dither {
|
25
|
+
|
26
|
+
class Ipog {
|
27
|
+
std::size_t t_;
|
28
|
+
std::vector<std::vector<dval>> input_params_;
|
29
|
+
std::vector<std::vector<param>> param_cache_;
|
30
|
+
std::forward_list<dtest_case> bound_;
|
31
|
+
std::forward_list<dtest_case> unbound_;
|
32
|
+
std::unordered_map<std::string, std::vector<int>> int_params_;
|
33
|
+
std::unordered_map<std::string, std::vector<std::string>> str_params_;
|
34
|
+
std::unordered_map<std::string, std::vector<bool>> bool_params_;
|
35
|
+
std::vector<std::string> ordered_param_names_;
|
36
|
+
std::vector<int> ordered_param_index_;
|
37
|
+
std::vector<int> reverse_ordered_param_index_;
|
38
|
+
std::unordered_map<std::string, int> param_index_;
|
39
|
+
std::unordered_map<int, std::string> reverse_param_index_;
|
40
|
+
dtest_case merge_scratch_;
|
41
|
+
BaseConstraintHandler* constraint_handler;
|
42
|
+
std::vector<std::vector<dval>> constraints;
|
43
|
+
std::vector<dval> ranges;
|
44
|
+
std::size_t solution_size;
|
45
|
+
std::vector<std::vector<dval>> original_previously_tested_;
|
46
|
+
std::vector<std::vector<dval>> previously_tested_;
|
47
|
+
|
48
|
+
inline void transform(std::vector<dval>& scratch, std::vector<dval>& test_case) {
|
49
|
+
for(std::size_t i = 0; i < test_case.size(); i++) {
|
50
|
+
scratch[ordered_param_index_[i]] = test_case[i];
|
51
|
+
}
|
52
|
+
std::copy(scratch.cbegin(), scratch.cend(), test_case.begin());
|
53
|
+
}
|
54
|
+
|
55
|
+
inline bool has_previously_tested(std::vector<param>& test_case);
|
56
|
+
inline bool has_previously_tested(dtest_case& test_case);
|
57
|
+
inline bool has_previously_tested(const int, dtest_case& test_case);
|
58
|
+
|
59
|
+
public:
|
60
|
+
Ipog();
|
61
|
+
~Ipog();
|
62
|
+
Ipog(const unsigned int);
|
63
|
+
void set_t(const unsigned int t) { t_ = t; }
|
64
|
+
void add_parameter(const std::string, const int[], const unsigned int);
|
65
|
+
void add_parameter(const std::string, const std::string[], const unsigned int);
|
66
|
+
void add_parameter(const std::string);
|
67
|
+
void init_bound();
|
68
|
+
void init_param_cache();
|
69
|
+
void run();
|
70
|
+
int size();
|
71
|
+
std::string *header();
|
72
|
+
void ground_solutions();
|
73
|
+
inline bool is_valid() { return t_ <= param_cache_.size(); }
|
74
|
+
std::forward_list<std::vector<param>> cover(int);
|
75
|
+
const int maximize_coverage(const int, dtest_case &,
|
76
|
+
std::forward_list<std::vector<param>> &);
|
77
|
+
void add_constraint(const int[], const unsigned int);
|
78
|
+
void add_previously_tested(const int[], const std::size_t);
|
79
|
+
inline bool is_covered(const dtest_case &test_case,
|
80
|
+
const std::vector<param> ¶ms);
|
81
|
+
inline bool is_covered(const std::vector<param> ¶ms);
|
82
|
+
inline const int merge(const int, dtest_case &, const std::vector<param> &);
|
83
|
+
void display_raw_solution();
|
84
|
+
void fill(int[]);
|
85
|
+
inline void display_header() {
|
86
|
+
for (std::size_t i = 0; i < param_cache_.size();) {
|
87
|
+
std::cout << reverse_param_index_[i];
|
88
|
+
if (++i < param_cache_.size()) {
|
89
|
+
std::cout << ',';
|
90
|
+
}
|
91
|
+
}
|
92
|
+
std::cout << std::endl;
|
93
|
+
}
|
94
|
+
|
95
|
+
inline void display_test_case(const dtest_case &test_case) {
|
96
|
+
for (std::size_t i = 0; i < test_case.size();) {
|
97
|
+
const dval value = test_case[i];
|
98
|
+
if (value == -1) {
|
99
|
+
std::cout << '-';
|
100
|
+
if (++i < test_case.size()) {
|
101
|
+
std::cout << ',';
|
102
|
+
}
|
103
|
+
continue;
|
104
|
+
}
|
105
|
+
const param my_param = param_cache_[reverse_ordered_param_index_[i]][value];
|
106
|
+
switch (my_param.type) {
|
107
|
+
case DITHER_INT_T:
|
108
|
+
std::cout << int_params_[my_param.name][my_param.second];
|
109
|
+
break;
|
110
|
+
case DITHER_BOOL_T:
|
111
|
+
std::cout << std::boolalpha
|
112
|
+
<< bool_params_[my_param.name][my_param.second];
|
113
|
+
break;
|
114
|
+
case DITHER_STRING_T:
|
115
|
+
std::cout << str_params_[my_param.name][my_param.second];
|
116
|
+
break;
|
117
|
+
}
|
118
|
+
if (++i < test_case.size()) {
|
119
|
+
std::cout << ',';
|
120
|
+
}
|
121
|
+
}
|
122
|
+
std::cout << std::endl;
|
123
|
+
}
|
124
|
+
};
|
125
|
+
|
126
|
+
}
|
127
|
+
|
128
|
+
#endif
|
@@ -0,0 +1,105 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright (C) 2015 Jason Gowan
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This software may be modified and distributed under the terms
|
7
|
+
* of the BSD license. See the LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "simple_constraint_handler.h"
|
11
|
+
#include <iostream>
|
12
|
+
|
13
|
+
namespace dither {
|
14
|
+
|
15
|
+
SimpleConstraintHandler::SimpleConstraintHandler(std::vector<dval>& ranges, std::vector<std::vector<dval>>& pconstraints) : params(ranges), scratch(ranges.size(), -1) {
|
16
|
+
for(auto it = pconstraints.cbegin(); it != pconstraints.cend(); ++it) {
|
17
|
+
std::vector<std::pair<std::size_t, dval>> constraint;
|
18
|
+
std::size_t i = 0;
|
19
|
+
for(auto iit = (*it).cbegin(); iit != (*it).cend(); ++iit, i++) {
|
20
|
+
if((*iit) != -1) {
|
21
|
+
constraint.push_back(std::make_pair(i, *iit));
|
22
|
+
}
|
23
|
+
}
|
24
|
+
constraints.push_back(constraint);
|
25
|
+
}
|
26
|
+
std::sort(constraints.begin(), constraints.end(), [](std::vector<std::pair<std::size_t, dval>>& a, std::vector<std::pair<std::size_t, dval>>& b) { return a.size() < b.size(); });
|
27
|
+
}
|
28
|
+
|
29
|
+
bool SimpleConstraintHandler::violate_constraints(const dtest_case &test_case) {
|
30
|
+
if(violate_constraints_(test_case)) {
|
31
|
+
return true;
|
32
|
+
}
|
33
|
+
std::copy(test_case.cbegin(), test_case.cend(), scratch.begin());
|
34
|
+
return !ground(scratch);
|
35
|
+
}
|
36
|
+
|
37
|
+
inline bool SimpleConstraintHandler::violate_constraints_(const dtest_case &test_case) {
|
38
|
+
for(auto constraint = constraints.cbegin(); constraint != constraints.cend(); ++constraint) {
|
39
|
+
if(violate_constraint(test_case, *constraint)) {
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
return false;
|
44
|
+
}
|
45
|
+
|
46
|
+
inline bool SimpleConstraintHandler::violate_constraint(const dtest_case& test_case, const std::vector<std::pair<std::size_t, dval>>& constraint) {
|
47
|
+
for(auto it = constraint.cbegin(); it != constraint.cend(); ++it) {
|
48
|
+
auto value = test_case[(*it).first];
|
49
|
+
if(value == -1 || value != (*it).second) {
|
50
|
+
return false;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
return true;
|
54
|
+
}
|
55
|
+
|
56
|
+
bool SimpleConstraintHandler::violate_constraints(const std::vector<param> &test_case) {
|
57
|
+
std::fill(scratch.begin(), scratch.end(), -1);
|
58
|
+
for(auto p : test_case) {
|
59
|
+
scratch[p.first] = p.second;
|
60
|
+
}
|
61
|
+
if(violate_constraints_(scratch)) {
|
62
|
+
return true;
|
63
|
+
}
|
64
|
+
return !ground(scratch);
|
65
|
+
}
|
66
|
+
|
67
|
+
bool SimpleConstraintHandler::ground(dtest_case &test_case) {
|
68
|
+
std::vector<std::size_t> indexes;
|
69
|
+
|
70
|
+
// find unbound indexes
|
71
|
+
std::size_t i = 0;
|
72
|
+
for (auto it = test_case.begin(); it != test_case.end(); ++it, i++) {
|
73
|
+
if ((*it) == -1) {
|
74
|
+
indexes.push_back(i);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
std::vector<dval> bound_values(indexes.size(), -1);
|
78
|
+
i = 0;
|
79
|
+
|
80
|
+
LOOP:while(i < indexes.size()) {
|
81
|
+
|
82
|
+
const dval max = params[indexes[i]];
|
83
|
+
for(dval value = bound_values[i] + 1; value <= max; value++) {
|
84
|
+
test_case[indexes[i]] = value;
|
85
|
+
if(violate_constraints_(test_case)) {
|
86
|
+
continue;
|
87
|
+
}
|
88
|
+
bound_values[i] = value;
|
89
|
+
i++;
|
90
|
+
goto LOOP;
|
91
|
+
}
|
92
|
+
|
93
|
+
if(i == 0) {
|
94
|
+
return false;
|
95
|
+
}
|
96
|
+
|
97
|
+
// unwind
|
98
|
+
bound_values[i] = -1;
|
99
|
+
test_case[indexes[i]] = -1;
|
100
|
+
i--;
|
101
|
+
}
|
102
|
+
|
103
|
+
return true;
|
104
|
+
}
|
105
|
+
}
|