dep_selector 0.0.8 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
//
|