dither 0.1.5 → 0.2.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -1
- data/README.md +3 -0
- data/Rakefile +4 -0
- data/dither.gemspec +4 -0
- 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 +119 -0
- data/ext/dither/simple_constraint_handler.h +38 -0
- data/lib/dither/api.rb +20 -0
- data/lib/dither/version.rb +1 -1
- data/lib/dither.rb +64 -13
- data/spec/dither/dither_spec.rb +27 -96
- metadata +47 -12
- 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,119 @@
|
|
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
|
+
|
12
|
+
namespace dither {
|
13
|
+
|
14
|
+
SimpleConstraintHandler::SimpleConstraintHandler(std::vector<dval>& ranges, std::vector<std::vector<dval>>& pconstraints) : params(ranges) {
|
15
|
+
for(auto it = pconstraints.cbegin(); it != pconstraints.cend(); ++it) {
|
16
|
+
std::vector<std::pair<std::size_t, dval>> constraint;
|
17
|
+
int i = 0;
|
18
|
+
for(auto iit = (*it).cbegin(); iit != (*it).cend(); ++iit, i++) {
|
19
|
+
if((*iit) != -1) {
|
20
|
+
constraint.push_back(std::make_pair(i, *iit));
|
21
|
+
}
|
22
|
+
}
|
23
|
+
constraints.push_back(constraint);
|
24
|
+
}
|
25
|
+
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(); });
|
26
|
+
}
|
27
|
+
|
28
|
+
bool SimpleConstraintHandler::violate_constraints(const dtest_case &test_case) {
|
29
|
+
for(auto constraint = constraints.cbegin(); constraint != constraints.cend(); ++constraint) {
|
30
|
+
if(violate_constraint(test_case, *constraint)) {
|
31
|
+
return true;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return false;
|
35
|
+
}
|
36
|
+
|
37
|
+
inline bool SimpleConstraintHandler::violate_constraint(const dtest_case& test_case, const std::vector<std::pair<std::size_t, dval>>& constraint) {
|
38
|
+
for(auto it = constraint.cbegin(); it != constraint.cend(); ++it) {
|
39
|
+
auto value = test_case[(*it).first];
|
40
|
+
if(value == -1 || value != (*it).second) {
|
41
|
+
return false;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
|
47
|
+
bool SimpleConstraintHandler::violate_constraints(const std::vector<param> &test_case) {
|
48
|
+
for(auto constraint = constraints.cbegin(); constraint != constraints.cend(); ++constraint) {
|
49
|
+
if(violate_constraint(test_case, *constraint)) {
|
50
|
+
return true;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
return false;
|
54
|
+
}
|
55
|
+
|
56
|
+
inline bool SimpleConstraintHandler::violate_constraint(const std::vector<param>& test_case, const std::vector<std::pair<std::size_t, dval>>& constraint) {
|
57
|
+
if(test_case.size() < constraint.size()) {
|
58
|
+
return false;
|
59
|
+
}
|
60
|
+
|
61
|
+
std::size_t count = 0;
|
62
|
+
for(auto it = constraint.cbegin(); it != constraint.cend(); ++it) {
|
63
|
+
for(auto iit = test_case.cbegin(); iit != test_case.cend(); ++iit) {
|
64
|
+
if((*iit).first == (*it).first && (*iit).second == (*it).second) {
|
65
|
+
count++;
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
if(count == constraint.size()) {
|
71
|
+
return true;
|
72
|
+
}
|
73
|
+
return false;
|
74
|
+
}
|
75
|
+
|
76
|
+
bool SimpleConstraintHandler::ground(dtest_case &test_case) {
|
77
|
+
std::vector<std::size_t> indexes;
|
78
|
+
|
79
|
+
// find unbound indexes
|
80
|
+
std::size_t i = 0;
|
81
|
+
for (auto it = test_case.begin(); it != test_case.end(); ++it, i++) {
|
82
|
+
if ((*it) == -1) {
|
83
|
+
indexes.push_back(i);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
if(indexes.size() == 0) {
|
87
|
+
return true;
|
88
|
+
}
|
89
|
+
std::vector<dval> bound_values(indexes.size(), 0);
|
90
|
+
i = 0;
|
91
|
+
|
92
|
+
LOOP:{
|
93
|
+
do {
|
94
|
+
test_case[indexes[i]] = bound_values[i];
|
95
|
+
if(violate_constraints(test_case)) {
|
96
|
+
// try to bump a bound value... return false if no valid value
|
97
|
+
const std::size_t upper_bound = i + 1;
|
98
|
+
for(std::size_t j = 0; j < upper_bound; j++) {
|
99
|
+
auto bump_value = bound_values[i] + 1;
|
100
|
+
if(bump_value < params[indexes[i]]) {
|
101
|
+
bound_values[i] = bump_value;
|
102
|
+
goto LOOP;
|
103
|
+
}
|
104
|
+
|
105
|
+
// unwind
|
106
|
+
bound_values[i] = 0;
|
107
|
+
test_case[indexes[i]] = -1;
|
108
|
+
i--;
|
109
|
+
}
|
110
|
+
|
111
|
+
return false;
|
112
|
+
}
|
113
|
+
i++;
|
114
|
+
}while(i < indexes.size());
|
115
|
+
}
|
116
|
+
|
117
|
+
return true;
|
118
|
+
}
|
119
|
+
}
|