dep_selector 0.0.8 → 0.1.1
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 +7 -0
- data/ext/dep_gecode/dep_selector_swig.i +2 -1
- data/ext/dep_gecode/dep_selector_swig_wrap.cxx +530 -180
- data/ext/dep_gecode/dep_selector_to_gecode.cpp +404 -360
- data/ext/dep_gecode/dep_selector_to_gecode.h +13 -5
- data/ext/dep_gecode/dep_selector_to_gecode_interface.cpp +3 -2
- data/ext/dep_gecode/dep_selector_to_gecode_interface.h +2 -1
- data/ext/dep_gecode/extconf.rb +24 -6
- data/lib/dep_selector/dep_selector_version.rb +1 -1
- data/lib/dep_selector/dependency_graph.rb +4 -1
- data/lib/dep_selector/error_reporter/simple_tree_traverser.rb +4 -0
- data/lib/dep_selector/exceptions.rb +5 -0
- data/lib/dep_selector/gecode_wrapper.rb +7 -4
- data/lib/dep_selector/selector.rb +46 -40
- metadata +71 -43
@@ -25,6 +25,7 @@
|
|
25
25
|
|
26
26
|
#include "dep_selector_to_gecode.h"
|
27
27
|
|
28
|
+
#include <cstdio>
|
28
29
|
#include <limits>
|
29
30
|
#include <iostream>
|
30
31
|
#include <vector>
|
@@ -42,33 +43,33 @@ const int VersionProblem::MIN_TRUST_LEVEL = 0;
|
|
42
43
|
const int VersionProblem::MAX_TRUST_LEVEL = 10;
|
43
44
|
const int VersionProblem::MAX_PREFERRED_WEIGHT = 10;
|
44
45
|
|
45
|
-
VersionProblemPool::VersionProblemPool() : elems()
|
46
|
+
VersionProblemPool::VersionProblemPool() : elems()
|
46
47
|
{ }
|
47
48
|
|
48
|
-
VersionProblemPool::~VersionProblemPool()
|
49
|
+
VersionProblemPool::~VersionProblemPool()
|
49
50
|
{
|
50
51
|
DeleteAll();
|
51
52
|
}
|
52
|
-
void VersionProblemPool::Add(VersionProblem * vp)
|
53
|
+
void VersionProblemPool::Add(VersionProblem * vp)
|
53
54
|
{
|
54
55
|
vp->pool = this;
|
55
56
|
#ifdef MEMORY_DEBUG
|
56
57
|
DEBUG_STREAM << "Pool add\t" << vp << std::endl << std::flush;
|
57
58
|
#endif // MEMORY_DEBUG
|
58
|
-
elems.insert(vp);
|
59
|
+
elems.insert(vp);
|
59
60
|
}
|
60
|
-
void VersionProblemPool::Delete(VersionProblem *vp)
|
61
|
-
{
|
62
|
-
if (vp->pool != 0)
|
63
|
-
|
61
|
+
void VersionProblemPool::Delete(VersionProblem *vp)
|
62
|
+
{
|
63
|
+
if (vp->pool != 0)
|
64
|
+
{
|
64
65
|
#ifdef MEMORY_DEBUG
|
65
|
-
|
66
|
+
DEBUG_STREAM << "Pool del\t" << vp << std::endl << std::flush;
|
66
67
|
#endif // MEMORY_DEBUG
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
elems.erase(vp);
|
69
|
+
vp->pool = 0;
|
70
|
+
}
|
70
71
|
}
|
71
|
-
void VersionProblemPool::ShowAll()
|
72
|
+
void VersionProblemPool::ShowAll()
|
72
73
|
{
|
73
74
|
DEBUG_STREAM << "ShowAll =====================================================" << std::endl << std::flush;
|
74
75
|
std::set<VersionProblem *>::iterator i;
|
@@ -84,7 +85,7 @@ void VersionProblemPool::DeleteAll()
|
|
84
85
|
{
|
85
86
|
#ifdef MEMORY_DEBUG
|
86
87
|
ShowAll();
|
87
|
-
#endif
|
88
|
+
#endif
|
88
89
|
std::set<VersionProblem *>::iterator i;
|
89
90
|
for(i = elems.begin(); i != elems.end(); i++) {
|
90
91
|
VersionProblem *vp = *i;
|
@@ -97,279 +98,320 @@ void VersionProblemPool::DeleteAll()
|
|
97
98
|
#endif
|
98
99
|
}
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
101
|
+
int VersionProblem::instance_counter = 0;
|
102
|
+
|
103
|
+
VersionProblem::VersionProblem(int packageCount, bool dumpStats, bool debug, const char * logId)
|
104
|
+
: size(packageCount), version_constraint_count(0), dump_stats(dumpStats),
|
105
|
+
debugLogging(debug),
|
106
|
+
finalized(false), cur_package(0), package_versions(*this, packageCount),
|
107
|
+
disabled_package_variables(*this, packageCount, 0, 1), total_disabled(*this, 0, packageCount*MAX_TRUST_LEVEL),
|
108
|
+
total_required_disabled(*this, 0, packageCount), total_induced_disabled(*this, 0, packageCount),
|
109
|
+
total_suspicious_disabled(*this, 0, packageCount),
|
110
|
+
is_required(new int[packageCount]),
|
111
|
+
is_suspicious(new int[packageCount]),
|
112
|
+
at_latest(*this, packageCount, 0, 1),
|
113
|
+
// These domains could be narrowed a bit; check later
|
114
|
+
total_preferred_at_latest(*this, -packageCount*MAX_PREFERRED_WEIGHT, packageCount*MAX_PREFERRED_WEIGHT),
|
115
|
+
total_not_preferred_at_latest(*this, -packageCount, packageCount),
|
116
|
+
preferred_at_latest_weights(new int[packageCount]),
|
117
|
+
pool(0),
|
118
|
+
instance_id(instance_counter++)
|
117
119
|
{
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
120
|
+
char * end = strncpy(debugPrefix, logId, DEBUG_PREFIX_LENGTH);
|
121
|
+
strncat(end, ": ", DEBUG_PREFIX_LENGTH-(debugPrefix-end));
|
122
|
+
for (int i = 0; i < packageCount; i++)
|
123
|
+
{
|
124
|
+
preferred_at_latest_weights[i] = 0;
|
125
|
+
is_required[i] = 0;
|
126
|
+
is_suspicious[i] = 0;
|
127
|
+
}
|
128
|
+
if (debugLogging) {
|
129
|
+
DEBUG_STREAM << std::endl;
|
130
|
+
DEBUG_STREAM << debugPrefix << "Creating VersionProblem inst# " << instance_id << " with " << packageCount << " packages, "
|
131
|
+
<< dumpStats << " stats, " << debug << " debug" << std::endl;
|
132
|
+
DEBUG_STREAM.flush();
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
VersionProblem::VersionProblem(bool share, VersionProblem & s)
|
137
|
+
: Space(share, s),
|
138
|
+
size(s.size), version_constraint_count(s.version_constraint_count),
|
139
|
+
dump_stats(s.dump_stats),
|
140
|
+
debugLogging(s.debugLogging),
|
141
|
+
finalized(s.finalized), cur_package(s.cur_package),
|
142
|
+
disabled_package_variables(s.disabled_package_variables), total_disabled(s.total_disabled),
|
143
|
+
total_required_disabled(s.total_required_disabled), total_induced_disabled(s.total_induced_disabled),
|
144
|
+
total_suspicious_disabled(s.total_suspicious_disabled),
|
145
|
+
is_required(NULL), is_suspicious(NULL),
|
146
|
+
at_latest(s.at_latest),
|
147
|
+
total_preferred_at_latest(s.total_preferred_at_latest),
|
148
|
+
total_not_preferred_at_latest(s.total_preferred_at_latest),
|
149
|
+
preferred_at_latest_weights(NULL),
|
150
|
+
pool(s.pool),
|
151
|
+
instance_id(s.instance_id)
|
143
152
|
{
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
153
|
+
strncpy(debugPrefix, s.debugPrefix, DEBUG_PREFIX_LENGTH),
|
154
|
+
package_versions.update(*this, share, s.package_versions);
|
155
|
+
disabled_package_variables.update(*this, share, s.disabled_package_variables);
|
156
|
+
total_disabled.update(*this, share, s.total_disabled);
|
157
|
+
total_required_disabled.update(*this, share, s.total_required_disabled);
|
158
|
+
total_induced_disabled.update(*this, share, s.total_induced_disabled);
|
159
|
+
total_suspicious_disabled.update(*this, share, s.total_suspicious_disabled);
|
160
|
+
at_latest.update(*this, share, s.at_latest);
|
161
|
+
total_preferred_at_latest.update(*this, share, s.total_preferred_at_latest);
|
162
|
+
total_not_preferred_at_latest.update(*this, share, s.total_not_preferred_at_latest);
|
163
|
+
|
164
|
+
pool->Add(this);
|
155
165
|
#ifdef MEMORY_DEBUG
|
156
|
-
|
157
|
-
#endif
|
166
|
+
DEBUG_STREAM << "C VersionProblem(bool, VP)\t" << this << std::endl << std::flush;
|
167
|
+
#endif
|
158
168
|
}
|
159
169
|
|
160
170
|
// Support for gecode
|
161
171
|
Space* VersionProblem::copy(bool share)
|
162
172
|
{
|
163
|
-
|
173
|
+
return new VersionProblem(share,*this);
|
164
174
|
}
|
165
175
|
|
166
|
-
VersionProblem::~VersionProblem()
|
176
|
+
VersionProblem::~VersionProblem()
|
167
177
|
{
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
178
|
+
delete[] preferred_at_latest_weights;
|
179
|
+
delete[] is_required;
|
180
|
+
delete[] is_suspicious;
|
181
|
+
if (pool!= 0) {
|
182
|
+
pool->Delete(this);
|
183
|
+
}
|
174
184
|
#ifdef MEMORY_DEBUG
|
175
|
-
|
185
|
+
DEBUG_STREAM << "D VersionProblem\t\t" << this << std::endl << std::flush;
|
176
186
|
#endif
|
177
187
|
}
|
178
188
|
|
179
|
-
int VersionProblem::Size()
|
189
|
+
int VersionProblem::Size()
|
180
190
|
{
|
181
|
-
|
191
|
+
return size;
|
182
192
|
}
|
183
193
|
|
184
|
-
int VersionProblem::PackageCount()
|
194
|
+
int VersionProblem::PackageCount()
|
185
195
|
{
|
186
|
-
|
196
|
+
return cur_package;
|
187
197
|
}
|
188
198
|
|
189
199
|
int
|
190
|
-
VersionProblem::AddPackage(int minVersion, int maxVersion, int currentVersion)
|
200
|
+
VersionProblem::AddPackage(int minVersion, int maxVersion, int currentVersion)
|
191
201
|
{
|
192
|
-
|
193
|
-
|
194
|
-
|
202
|
+
if (cur_package == size) {
|
203
|
+
return -1;
|
204
|
+
}
|
195
205
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
206
|
+
if (debugLogging) {
|
207
|
+
sprintf(outputBuffer, "%s DepSelector inst# %d - Adding package id %d/%d: min = %d, max = %d, current version %d",
|
208
|
+
debugPrefix, instance_id, cur_package, size, minVersion, maxVersion, currentVersion);
|
209
|
+
DEBUG_STREAM << outputBuffer;
|
210
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
211
|
+
// << " - Adding package id " << cur_package << '/' << size << ": min = " << minVersion << ", max = " << maxVersion << ", current version " << currentVersion << std::endl;
|
212
|
+
DEBUG_STREAM.flush();
|
213
|
+
}
|
214
|
+
int index = cur_package;
|
215
|
+
cur_package++;
|
216
|
+
// IntVar version(*this, minVersion, maxVersion);
|
217
|
+
package_versions[index] = IntVar(*this, minVersion, maxVersion);
|
204
218
|
|
205
|
-
|
206
|
-
|
219
|
+
// register the binding of package to version that corresponds to the package's latest
|
220
|
+
rel(*this, package_versions[index], IRT_EQ, maxVersion, at_latest[index]);
|
207
221
|
|
208
|
-
|
222
|
+
return index;
|
209
223
|
}
|
210
224
|
|
211
|
-
bool
|
212
|
-
VersionProblem::AddVersionConstraint(int packageId, int version,
|
213
|
-
|
225
|
+
bool
|
226
|
+
VersionProblem::AddVersionConstraint(int packageId, int version,
|
227
|
+
int dependentPackageId, int minDependentVersion, int maxDependentVersion)
|
214
228
|
{
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
229
|
+
BoolVar version_match(*this, 0, 1);
|
230
|
+
BoolVar depend_match(*this, 0, 1);
|
231
|
+
BoolVar predicated_depend_match(*this, 0, 1);
|
232
|
+
|
233
|
+
version_constraint_count++;
|
234
|
+
if (debugLogging) {
|
235
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Adding VC for %d @ %d depPkg %d [%d, %d]",
|
236
|
+
debugPrefix, instance_id, packageId, version, dependentPackageId, minDependentVersion, maxDependentVersion);
|
237
|
+
DEBUG_STREAM << outputBuffer;
|
238
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
239
|
+
// << " - Adding VC for " << packageId << " @ " << version << " depPkg " << dependentPackageId
|
240
|
+
// << " [ " << minDependentVersion << ", " << maxDependentVersion << " ]" << std::endl;
|
241
|
+
DEBUG_STREAM.flush();
|
242
|
+
}
|
225
243
|
|
226
244
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
245
|
+
//version_flags << version_match;
|
246
|
+
// Constrain pred to reify package @ version
|
247
|
+
rel(*this, package_versions[packageId], IRT_EQ, version, version_match);
|
248
|
+
// Add the predicated version constraints imposed on dependent package
|
231
249
|
|
232
|
-
|
233
|
-
|
250
|
+
// package_versions[dependendPackageId] in domain [minDependentVersion,maxDependentVersion] <=> depend_match
|
251
|
+
dom(*this, package_versions[dependentPackageId], minDependentVersion, maxDependentVersion, depend_match);
|
234
252
|
|
235
|
-
|
236
|
-
|
253
|
+
// disabled_package_variables[dependentPackageId] OR depend_match <=> predicated_depend_match
|
254
|
+
// rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, version_match);
|
237
255
|
|
238
|
-
|
239
|
-
|
256
|
+
rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, predicated_depend_match);
|
257
|
+
rel(*this, version_match, BOT_IMP, predicated_depend_match, 1);
|
240
258
|
}
|
241
259
|
|
242
260
|
void
|
243
|
-
VersionProblem::MarkPackageSuspicious(int packageId)
|
261
|
+
VersionProblem::MarkPackageSuspicious(int packageId)
|
244
262
|
{
|
245
|
-
|
263
|
+
is_suspicious[packageId] = 1;
|
264
|
+
|
265
|
+
if (debugLogging) {
|
266
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Suspicious %d",
|
267
|
+
debugPrefix, instance_id, packageId);
|
268
|
+
DEBUG_STREAM << outputBuffer;
|
269
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
270
|
+
// << " - Marking Package Suspicious " << packageId << std::endl;
|
271
|
+
DEBUG_STREAM.flush();
|
272
|
+
}
|
246
273
|
}
|
247
274
|
|
248
|
-
void
|
275
|
+
void
|
249
276
|
VersionProblem::MarkPackageRequired(int packageId)
|
250
277
|
{
|
251
|
-
|
278
|
+
is_required[packageId] = 1;
|
279
|
+
|
280
|
+
if (debugLogging) {
|
281
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Required %d", debugPrefix, instance_id, packageId);
|
282
|
+
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
283
|
+
<< " - Marking Package Required " << packageId << std::endl;
|
284
|
+
DEBUG_STREAM.flush();
|
285
|
+
}
|
252
286
|
}
|
253
287
|
|
254
288
|
void
|
255
289
|
VersionProblem::MarkPackagePreferredToBeAtLatest(int packageId, int weight)
|
256
|
-
{
|
257
|
-
|
290
|
+
{
|
291
|
+
preferred_at_latest_weights[packageId] = std::max(MAX_PREFERRED_WEIGHT, std::min(0, weight));
|
292
|
+
|
293
|
+
if (debugLogging) {
|
294
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Preferred Latest %d weight %d",
|
295
|
+
debugPrefix, instance_id, packageId, weight);
|
296
|
+
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
297
|
+
<< " - Marking Package Preferred Latest " << packageId << " weight " << weight << std::endl;
|
298
|
+
DEBUG_STREAM.flush();
|
299
|
+
}
|
258
300
|
}
|
259
301
|
|
260
|
-
void VersionProblem::Finalize()
|
302
|
+
void VersionProblem::Finalize()
|
261
303
|
{
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
304
|
+
if (debugLogging) {
|
305
|
+
DEBUG_STREAM << debugPrefix << "Finalization Started for inst# " << instance_id << std::endl;
|
306
|
+
DEBUG_STREAM.flush();
|
307
|
+
}
|
308
|
+
finalized = true;
|
309
|
+
|
310
|
+
// Setup constraint for cost
|
311
|
+
// We wish to minimize the total number of disabled packages, by priority ranks
|
312
|
+
IntArgs disabled_required_weights(size, is_required);
|
313
|
+
linear(*this, disabled_required_weights, disabled_package_variables, IRT_EQ, total_required_disabled);
|
314
|
+
if (debugLogging) {
|
315
|
+
DEBUG_STREAM << debugPrefix << " disabled_required_weights: " << disabled_required_weights << std::endl;
|
316
|
+
DEBUG_STREAM << debugPrefix << " total_required_disabled: " << total_required_disabled << std::endl;
|
317
|
+
}
|
318
|
+
|
319
|
+
IntArgs disabled_induced_weights(size);
|
320
|
+
for (int i = 0; i < size; i++) {
|
321
|
+
disabled_induced_weights[i] = !(is_required[i] || is_suspicious[i]);
|
322
|
+
}
|
323
|
+
linear(*this, disabled_induced_weights, disabled_package_variables, IRT_EQ, total_induced_disabled);
|
324
|
+
|
325
|
+
if (debugLogging) {
|
326
|
+
DEBUG_STREAM << debugPrefix << " disabled_induced_weights: " << disabled_induced_weights << std::endl;
|
327
|
+
DEBUG_STREAM << debugPrefix <<" total_induced_disabled: " << total_induced_disabled << std::endl;
|
328
|
+
}
|
329
|
+
|
330
|
+
IntArgs disabled_suspicious_weights(size, is_suspicious);
|
331
|
+
linear(*this, disabled_suspicious_weights, disabled_package_variables, IRT_EQ, total_suspicious_disabled);
|
332
|
+
|
333
|
+
if (debugLogging) {
|
334
|
+
DEBUG_STREAM << debugPrefix << " disabled_suspicious_weights: " << disabled_suspicious_weights << std::endl;
|
335
|
+
DEBUG_STREAM << debugPrefix << " total_suspicious_disabled: " << total_suspicious_disabled << std::endl;
|
336
|
+
}
|
337
|
+
|
338
|
+
linear(*this, disabled_package_variables, IRT_EQ, total_disabled);
|
339
|
+
if (debugLogging) {
|
340
|
+
DEBUG_STREAM << debugPrefix <<" total_disabled: " << total_disabled << std::endl;
|
341
|
+
}
|
342
|
+
|
343
|
+
// Setup computation for total_preferred_at_latest
|
344
|
+
// We wish to maximize the total number of packages at their latest versions in the preferred tier of packages
|
345
|
+
// We negate the weights in the cost function to make it fit into the context of a minimization problem.
|
346
|
+
for (int i = 0; i < size; i++) {
|
347
|
+
preferred_at_latest_weights[i] = -preferred_at_latest_weights[i];
|
348
|
+
}
|
349
|
+
IntArgs preferred_at_latest_weights_args(size, preferred_at_latest_weights);
|
350
|
+
linear(*this, preferred_at_latest_weights_args, at_latest, IRT_EQ, total_preferred_at_latest);
|
351
|
+
if (debugLogging) {
|
352
|
+
DEBUG_STREAM << debugPrefix << " preferred_at_latest_weights_args: " << preferred_at_latest_weights_args << std::endl;
|
353
|
+
DEBUG_STREAM << debugPrefix << " total_preferred_at_latest: " << total_preferred_at_latest << std::endl;
|
354
|
+
}
|
355
|
+
|
356
|
+
// Setup computation for remaining variables
|
357
|
+
// We wish to maximize the total number of packages at their latest version in the non-preferred tier of packages
|
358
|
+
// We negate the weights in the cost function to make it fit into the context of a minimization problem.
|
359
|
+
IntArgs not_preferred_at_latest_weights_args = IntArgs::create(size, 0, 0);
|
360
|
+
for (int i = 0; i < size; i++) {
|
361
|
+
if (preferred_at_latest_weights[i] == 0) {
|
362
|
+
not_preferred_at_latest_weights_args[i] = -1;
|
363
|
+
}
|
364
|
+
}
|
365
|
+
linear(*this, not_preferred_at_latest_weights_args, at_latest, IRT_EQ, total_not_preferred_at_latest);
|
366
|
+
if (debugLogging) {
|
367
|
+
DEBUG_STREAM << debugPrefix << " not_preferred_at_latest_weights_args: " << not_preferred_at_latest_weights_args << std::endl;
|
368
|
+
DEBUG_STREAM << debugPrefix << " total_not_preferred_at_latest: " << total_not_preferred_at_latest << std::endl;
|
369
|
+
}
|
370
|
+
|
371
|
+
|
372
|
+
// Cleanup
|
373
|
+
// Assign a dummy variable to elements greater than actually used.
|
374
|
+
for (int i = cur_package; i < size; i++) {
|
375
|
+
package_versions[i] = IntVar(*this, -1, -1);
|
376
|
+
disabled_package_variables[i] = BoolVar(*this, 1, 1);
|
377
|
+
}
|
336
378
|
|
337
379
|
#ifdef USE_DUMB_BRANCHING
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
380
|
+
if (debugLogging) {
|
381
|
+
DEBUG_STREAM << debugPrefix << " Adding branching (POOR)" << std::endl;
|
382
|
+
DEBUG_STREAM.flush();
|
383
|
+
}
|
384
|
+
// This branching starts as far as possible from the solution, in order to exercise the optimization functions.
|
385
|
+
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
386
|
+
branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
387
|
+
branch(*this, total_required_disabled, INT_VAL_MAX);
|
388
|
+
branch(*this, total_induced_disabled, INT_VAL_MAX);
|
389
|
+
branch(*this, total_suspicious_disabled, INT_VAL_MAX);
|
390
|
+
branch(*this, total_disabled, INT_VAL_MAX);
|
391
|
+
branch(*this, at_latest, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
392
|
+
branch(*this, total_preferred_at_latest, INT_VAL_MIN);
|
393
|
+
branch(*this, total_not_preferred_at_latest, INT_VAL_MIN);
|
352
394
|
#else // USE_DUMB_BRANCHING
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
395
|
+
if (debugLogging) {
|
396
|
+
DEBUG_STREAM << debugPrefix << " Adding branching (BEST)" << std::endl;
|
397
|
+
DEBUG_STREAM.flush();
|
398
|
+
}
|
399
|
+
// This branching is meant to start with most probable solution
|
400
|
+
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
401
|
+
branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
402
|
+
branch(*this, total_required_disabled, INT_VAL_MIN);
|
403
|
+
branch(*this, total_induced_disabled, INT_VAL_MIN);
|
404
|
+
branch(*this, total_suspicious_disabled, INT_VAL_MIN);
|
405
|
+
branch(*this, total_disabled, INT_VAL_MIN);
|
406
|
+
branch(*this, at_latest, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
407
|
+
branch(*this, total_preferred_at_latest, INT_VAL_MAX);
|
408
|
+
branch(*this, total_not_preferred_at_latest, INT_VAL_MAX);
|
367
409
|
#endif // USE_DUMB_BRANCHING
|
368
410
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
411
|
+
if (debugLogging) {
|
412
|
+
DEBUG_STREAM << debugPrefix << "Finalization Done" << std::endl;
|
413
|
+
DEBUG_STREAM.flush();
|
414
|
+
}
|
373
415
|
}
|
374
416
|
|
375
417
|
////////////////////////////////////////////////////////////////////////
|
@@ -380,7 +422,7 @@ void VersionProblem::Finalize()
|
|
380
422
|
// and operate in the context of a fresh space, not yet fully assigned. Their purpose is to add
|
381
423
|
// constraints such that the assignments in the fresh space will either yield a better solution, or
|
382
424
|
// none at all if the best_known_solution is the best possible.
|
383
|
-
//
|
425
|
+
//
|
384
426
|
|
385
427
|
#ifdef TOTAL_DISABLED_COST
|
386
428
|
//
|
@@ -389,15 +431,16 @@ void VersionProblem::Finalize()
|
|
389
431
|
//
|
390
432
|
void VersionProblem::constrain(const Space & _best_known_solution)
|
391
433
|
{
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
434
|
+
const VersionProblem& best_known_solution = static_cast<const VersionProblem &>(_best_known_solution);
|
435
|
+
|
436
|
+
// add first-level objective function minimization (failing packages, weighted)
|
437
|
+
// new constraint: total_disabled < best_known_total_disabled_value)
|
438
|
+
int best_known_total_disabled_value = best_known_solution.total_disabled.val();
|
439
|
+
rel(*this, total_disabled, IRT_LE, best_known_total_disabled_value);
|
440
|
+
if (debugLogging) {
|
441
|
+
DEBUG_STREAM << debugPrefix;
|
442
|
+
PrintVarAligned("Con strain: total_disabled: ", total_disabled);
|
443
|
+
}
|
401
444
|
}
|
402
445
|
#endif // TOTAL_DISABLED_COST
|
403
446
|
|
@@ -425,143 +468,143 @@ void VersionProblem::constrain(const Space & _best_known_solution)
|
|
425
468
|
// walks the space until it finds another, more constrained solution.
|
426
469
|
|
427
470
|
#ifdef VECTOR_CONSTRAIN
|
428
|
-
//
|
471
|
+
//
|
429
472
|
// The vector constrain function assembles multiple cost functions into a vector cost, and then
|
430
473
|
// constrains the vector cost to be less than the vector cost of the current best_known_solution.
|
431
474
|
// The less than operation here is a pairwise comparison in order of decreasing precedence; only if
|
432
|
-
// higher precedence elements are tied will the lower precedence elements be consulted. The elements
|
433
|
-
// are in increasing order of precedence.
|
475
|
+
// higher precedence elements are tied will the lower precedence elements be consulted. The elements
|
476
|
+
// are in increasing order of precedence.
|
434
477
|
//
|
435
478
|
// In this case the lowest precedence cost is total_not_preferred_at_latest, followed by total_preferred_at_latest
|
436
479
|
// and finally total_disabled.
|
437
480
|
//
|
438
481
|
void VersionProblem::constrain(const Space & _best_known_solution)
|
439
482
|
{
|
440
|
-
|
483
|
+
const VersionProblem& best_known_solution = static_cast<const VersionProblem &>(_best_known_solution);
|
441
484
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
485
|
+
IntVarArgs current(5);
|
486
|
+
IntVarArgs best(5);
|
487
|
+
BuildCostVector(current);
|
488
|
+
best_known_solution.BuildCostVector(best);
|
489
|
+
ConstrainVectorLessThanBest(current, best);
|
447
490
|
}
|
448
491
|
#endif // VECTOR_CONSTRAIN
|
449
492
|
|
450
493
|
void VersionProblem::BuildCostVector(IntVarArgs & costVector) const {
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
494
|
+
costVector[0] = total_not_preferred_at_latest;
|
495
|
+
costVector[1] = total_preferred_at_latest;
|
496
|
+
costVector[2] = total_suspicious_disabled;
|
497
|
+
costVector[3] = total_induced_disabled;
|
498
|
+
costVector[4] = total_required_disabled;
|
456
499
|
}
|
457
500
|
|
458
501
|
|
459
502
|
|
460
503
|
IntVar & VersionProblem::GetPackageVersionVar(int packageId)
|
461
504
|
{
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
}
|
472
|
-
|
473
|
-
int VersionProblem::GetPackageVersion(int packageId)
|
505
|
+
if (packageId < cur_package) {
|
506
|
+
return package_versions[packageId];
|
507
|
+
} else {
|
508
|
+
if (debugLogging) {
|
509
|
+
DEBUG_STREAM << debugPrefix << "Bad package Id " << packageId << " >= " << cur_package << std::endl;
|
510
|
+
DEBUG_STREAM.flush();
|
511
|
+
}
|
512
|
+
// return 0;
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
int VersionProblem::GetPackageVersion(int packageId)
|
474
517
|
{
|
475
|
-
|
476
|
-
|
477
|
-
|
518
|
+
IntVar & var = GetPackageVersionVar(packageId);
|
519
|
+
if (1 == var.size()) return var.val();
|
520
|
+
return UNRESOLVED_VARIABLE;
|
478
521
|
}
|
479
|
-
bool VersionProblem::GetPackageDisabledState(int packageId)
|
522
|
+
bool VersionProblem::GetPackageDisabledState(int packageId)
|
480
523
|
{
|
481
|
-
|
524
|
+
return disabled_package_variables[packageId].val() == 1;
|
482
525
|
}
|
483
526
|
|
484
527
|
int VersionProblem::GetMax(int packageId)
|
485
528
|
{
|
486
|
-
|
529
|
+
return GetPackageVersionVar(packageId).max();
|
487
530
|
}
|
488
531
|
int VersionProblem::GetMin(int packageId)
|
489
532
|
{
|
490
|
-
|
533
|
+
return GetPackageVersionVar(packageId).min();
|
491
534
|
}
|
492
535
|
|
493
536
|
int VersionProblem::GetDisabledVariableCount()
|
494
537
|
{
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
538
|
+
if (total_disabled.min() == total_disabled.max()) {
|
539
|
+
return total_disabled.min();
|
540
|
+
} else {
|
541
|
+
return UNRESOLVED_VARIABLE;
|
542
|
+
}
|
500
543
|
}
|
501
|
-
|
544
|
+
|
502
545
|
|
503
546
|
// Utility
|
504
|
-
void VersionProblem::Print(std::ostream & out)
|
547
|
+
void VersionProblem::Print(std::ostream & out)
|
505
548
|
{
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
549
|
+
out << debugPrefix << "Version problem dump: " << cur_package << "/" << size << " packages used/allocated" << std::endl;
|
550
|
+
out << debugPrefix << "Disabled Variables: " << disabled_package_variables << std::endl;
|
551
|
+
out << debugPrefix << "Total Disabled variables (required): " << total_required_disabled << std::endl;
|
552
|
+
out << debugPrefix << "Total Disabled variables: (induced): " << total_induced_disabled << std::endl;
|
553
|
+
out << debugPrefix << "Total Disabled variables: (suspicious): " << total_suspicious_disabled << std::endl;
|
554
|
+
out << debugPrefix << "Total Disabled variables: " << total_disabled << std::endl;
|
555
|
+
out << debugPrefix << "at_latest: " << at_latest << std::endl;
|
556
|
+
out << debugPrefix << "total_preferred_at_latest: " << total_preferred_at_latest << std::endl;
|
557
|
+
out << debugPrefix << "total_not_preferred_at_latest: " << total_not_preferred_at_latest << std::endl;
|
558
|
+
for (int i = 0; i < cur_package; i++) {
|
559
|
+
out << debugPrefix << "\t";
|
560
|
+
PrintPackageVar(out, i);
|
561
|
+
out << std::endl;
|
562
|
+
}
|
563
|
+
out.flush();
|
521
564
|
}
|
522
565
|
|
523
566
|
// TODO: Validate package ids !
|
524
567
|
|
525
|
-
void VersionProblem::PrintPackageVar(std::ostream & out, int packageId)
|
568
|
+
void VersionProblem::PrintPackageVar(std::ostream & out, int packageId)
|
526
569
|
{
|
527
|
-
|
528
|
-
|
570
|
+
IntVar & var = GetPackageVersionVar(packageId);
|
571
|
+
out << "PackageId: " << packageId << " Sltn: " << var << " disabled: " << disabled_package_variables[packageId] << " at latest: " << at_latest[packageId];
|
529
572
|
}
|
530
573
|
|
531
|
-
bool VersionProblem::CheckPackageId(int id)
|
574
|
+
bool VersionProblem::CheckPackageId(int id)
|
532
575
|
{
|
533
|
-
|
576
|
+
return (id < size);
|
534
577
|
}
|
535
578
|
|
536
|
-
// We want to sort vectors
|
579
|
+
// We want to sort vectors
|
537
580
|
// This constrains current to be less than best by a process analogous to subtraction
|
538
|
-
// we compute current - best, pairwise with borrows from less significant elements. We require it to be less than zero by requiring the most
|
539
|
-
// significant element to generate a borrow.
|
540
|
-
//
|
581
|
+
// we compute current - best, pairwise with borrows from less significant elements. We require it to be less than zero by requiring the most
|
582
|
+
// significant element to generate a borrow.
|
583
|
+
//
|
541
584
|
void VersionProblem::ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best) {
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
585
|
+
BoolVarArray borrow(*this, current.size()+1, 0, 1);
|
586
|
+
|
587
|
+
// No borrows can happen at the least significant element.
|
588
|
+
rel(*this, borrow[0], IRT_EQ, 0);
|
589
|
+
|
590
|
+
for (int i = 0; i < current.size(); i++) {
|
591
|
+
// If best+borrow is greater than current (equivalently current-(best+borrow) is < 0) then a more significant element
|
592
|
+
// must have decreased, so we propagate a borrow to the next most significant element.
|
593
|
+
int best_val = best[i].val();
|
594
|
+
IntVar delta = expr(*this, current[i] - best_val - borrow[i]);
|
595
|
+
// (delta < 0) <=> borrow[i+1]
|
596
|
+
rel(*this, delta, IRT_LE, 0, borrow[i+1]);
|
597
|
+
if (debugLogging) {
|
598
|
+
DEBUG_STREAM << debugPrefix << " ConstrainVector: borrow[" << i+1 << "] " << borrow[i+1] << ",\tdelta " << delta << std::endl;
|
599
|
+
DEBUG_STREAM << debugPrefix << " ConstrainVector: current[" << i << "] " << current[i] << ",\tbest_val " << best_val << std::endl;
|
600
|
+
}
|
557
601
|
}
|
558
|
-
}
|
559
602
|
|
560
|
-
|
561
|
-
|
603
|
+
// must borrow off past the most significant element.
|
604
|
+
rel(*this, borrow[current.size()], IRT_EQ, 1);
|
562
605
|
}
|
563
606
|
|
564
|
-
VersionProblem * VersionProblem::InnerSolve(VersionProblem * problem, int &itercount)
|
607
|
+
VersionProblem * VersionProblem::InnerSolve(VersionProblem * problem, int &itercount)
|
565
608
|
{
|
566
609
|
Gecode::Support::Timer timer;
|
567
610
|
timer.start();
|
@@ -571,36 +614,37 @@ VersionProblem * VersionProblem::InnerSolve(VersionProblem * problem, int &iterc
|
|
571
614
|
#endif
|
572
615
|
VersionProblem *best_solution = NULL;
|
573
616
|
Restart<VersionProblem> solver(problem);
|
574
|
-
|
617
|
+
|
575
618
|
#ifdef MEMORY_DEBUG
|
576
619
|
DEBUG_STREAM << "Starting Solve" << std::endl << std::flush;
|
577
|
-
#endif
|
620
|
+
#endif
|
578
621
|
|
579
622
|
while (VersionProblem *solution = solver.next())
|
580
|
-
|
623
|
+
{
|
581
624
|
#ifdef MEMORY_DEBUG
|
582
|
-
|
625
|
+
DEBUG_STREAM << "Solver Next " << solution << std::endl << std::flush;
|
583
626
|
#endif
|
584
|
-
|
585
|
-
|
586
|
-
|
627
|
+
if (best_solution != NULL)
|
628
|
+
{
|
629
|
+
delete best_solution;
|
630
|
+
}
|
631
|
+
best_solution = solution;
|
632
|
+
++itercount;
|
633
|
+
if (problem->debugLogging) {
|
634
|
+
DEBUG_STREAM << problem->debugPrefix << "Trial Solution #" << itercount << "===============================" << std::endl;
|
635
|
+
const Search::Statistics & stats = solver.statistics();
|
636
|
+
DEBUG_STREAM << problem->debugPrefix << "Solver stats: Prop:" << stats.propagate << " Fail:" << stats.fail << " Node:" << stats.node;
|
637
|
+
DEBUG_STREAM << " Depth:" << stats.depth << " memory:" << stats.memory << std::endl;
|
638
|
+
solution->Print(DEBUG_STREAM);
|
639
|
+
}
|
587
640
|
}
|
588
|
-
|
589
|
-
++itercount;
|
590
|
-
if (problem->debug_logging) {
|
591
|
-
DEBUG_STREAM << "Trial Solution #" << itercount << "===============================" << std::endl;
|
592
|
-
const Search::Statistics & stats = solver.statistics();
|
593
|
-
DEBUG_STREAM << "Solver stats: Prop:" << stats.propagate << " Fail:" << stats.fail << " Node:" << stats.node;
|
594
|
-
DEBUG_STREAM << " Depth:" << stats.depth << " memory:" << stats.memory << std::endl;
|
595
|
-
solution->Print(DEBUG_STREAM);
|
596
|
-
}
|
597
|
-
}
|
598
|
-
|
641
|
+
|
599
642
|
double elapsed_time = timer.stop();
|
600
|
-
|
643
|
+
|
601
644
|
if (problem->dump_stats) {
|
645
|
+
if (problem->debugLogging) std::cerr << problem->debugPrefix;
|
602
646
|
std::cerr << "dep_selector solve: ";
|
603
|
-
std::cerr << (best_solution ? "SOLVED" : "FAILED") << " ";
|
647
|
+
std::cerr << (best_solution ? "SOLVED" : "FAILED") << " ";
|
604
648
|
std::cerr << problem->size << " packages, " << problem->version_constraint_count << " constraints, ";
|
605
649
|
std::cerr << "Time: " << elapsed_time << "ms ";
|
606
650
|
const Search::Statistics & final_stats = solver.statistics();
|
@@ -609,11 +653,11 @@ VersionProblem * VersionProblem::InnerSolve(VersionProblem * problem, int &iterc
|
|
609
653
|
std::cerr << final_stats.propagate << " props, " << final_stats.node << " nodes, " << final_stats.depth << " depth ";
|
610
654
|
std::cerr << std::endl << std::flush;
|
611
655
|
}
|
612
|
-
|
656
|
+
|
613
657
|
return best_solution;
|
614
658
|
}
|
615
659
|
|
616
|
-
VersionProblem * VersionProblem::Solve(VersionProblem * problem)
|
660
|
+
VersionProblem * VersionProblem::Solve(VersionProblem * problem)
|
617
661
|
{
|
618
662
|
|
619
663
|
problem->Finalize();
|
@@ -622,37 +666,37 @@ VersionProblem * VersionProblem::Solve(VersionProblem * problem)
|
|
622
666
|
VersionProblemPool *pool = new VersionProblemPool();
|
623
667
|
problem->pool = pool;
|
624
668
|
|
625
|
-
if (problem->
|
626
|
-
DEBUG_STREAM << " Before solve" << std::endl;
|
669
|
+
if (problem->debugLogging) {
|
670
|
+
DEBUG_STREAM << problem->DebugPrefix() << " Before solve" << std::endl;
|
627
671
|
problem->Print(DEBUG_STREAM);
|
628
672
|
}
|
629
673
|
int itercount = 0;
|
630
|
-
|
674
|
+
|
631
675
|
VersionProblem *best_solution = InnerSolve(problem, itercount);
|
632
|
-
|
633
|
-
if (problem->
|
634
|
-
DEBUG_STREAM << "Solver Best Solution " << best_solution << std::endl << std::flush;
|
676
|
+
|
677
|
+
if (problem->debugLogging) {
|
678
|
+
DEBUG_STREAM << problem->DebugPrefix() << "Solver Best Solution " << best_solution << std::endl << std::flush;
|
635
679
|
}
|
636
680
|
|
637
681
|
pool->Delete(best_solution);
|
638
|
-
problem->pool = 0;
|
682
|
+
problem->pool = 0;
|
639
683
|
|
640
684
|
pool->DeleteAll();
|
641
685
|
delete pool;
|
642
686
|
|
643
|
-
|
687
|
+
return best_solution;
|
644
688
|
}
|
645
689
|
|
646
690
|
//
|
647
691
|
// Debug output
|
648
|
-
//
|
649
|
-
template <class T> void PrintVarAligned(const char * message, T & var)
|
692
|
+
//
|
693
|
+
template <class T> void PrintVarAligned(const char * message, T & var)
|
650
694
|
{
|
651
695
|
DEBUG_STREAM.width(40);
|
652
696
|
DEBUG_STREAM << std::left << message << var << std::endl;
|
653
697
|
DEBUG_STREAM.width(0);
|
654
698
|
}
|
655
|
-
template <class S, class T> void PrintVarAligned(const char * message, S & var1, T & var2)
|
699
|
+
template <class S, class T> void PrintVarAligned(const char * message, S & var1, T & var2)
|
656
700
|
{
|
657
701
|
DEBUG_STREAM.width(40);
|
658
702
|
DEBUG_STREAM << std::left << message << var1 << " " << var2 << std::endl;
|
@@ -667,5 +711,5 @@ template <class S, class T> void PrintVarAligned(const char * message, S & var1,
|
|
667
711
|
// Version Problem
|
668
712
|
//
|
669
713
|
//
|
670
|
-
//
|
714
|
+
//
|
671
715
|
//
|