dep_selector 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/dep_gecode/dep_selector_to_gecode.cpp +245 -84
- data/ext/dep_gecode/dep_selector_to_gecode.h +41 -25
- data/ext/dep_gecode/dep_selector_to_gecode_interface.cpp +20 -10
- data/ext/dep_gecode/dep_selector_to_gecode_interface.h +17 -4
- data/lib/dep_selector.rb +1 -0
- data/lib/dep_selector/debug.rb +29 -0
- data/lib/dep_selector/dep_gecode.rb +9 -6
- data/lib/dep_selector/dep_selector_version.rb +1 -1
- data/lib/dep_selector/dependency_graph.rb +7 -1
- data/lib/dep_selector/gecode_wrapper.rb +31 -4
- data/lib/dep_selector/package.rb +13 -2
- data/lib/dep_selector/selector.rb +4 -5
- metadata +27 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c2b77c7e96ffbe77d1c03fc080b94d221b6daeb
|
4
|
+
data.tar.gz: 96c96d4e9b17c475c538651ab186f2bd6a200a12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 160d6cebdbe86f5a0e44434a8c87293b1e680940420bcced8caa12059461d21991b3be15b1f59bbcd95d238b511d6484452c181ce6ba88dce7b7c97f83eb4382
|
7
|
+
data.tar.gz: b6f36b5d3aba61b1c9a7ef755ced8d92fc61be0a911a3f4dc8487fb896740624910463c2f21681bd2bb73ae145e28c7293e69fd0de3aa8ce4240c5dde614d8b0
|
@@ -100,9 +100,10 @@ void VersionProblemPool::DeleteAll()
|
|
100
100
|
|
101
101
|
int VersionProblem::instance_counter = 0;
|
102
102
|
|
103
|
-
VersionProblem::VersionProblem(int packageCount, bool dumpStats, bool debug, const char * logId
|
103
|
+
VersionProblem::VersionProblem(int packageCount, bool dumpStats, bool debug, const char * logId,
|
104
|
+
unsigned long int _timeout)
|
104
105
|
: size(packageCount), version_constraint_count(0), dump_stats(dumpStats),
|
105
|
-
debugLogging(debug),
|
106
|
+
debugLogging(debug), timeout(_timeout), solutionState(SOLUTION_STATE_UNSTARTED),
|
106
107
|
finalized(false), cur_package(0), package_versions(*this, packageCount),
|
107
108
|
disabled_package_variables(*this, packageCount, 0, 1), total_disabled(*this, 0, packageCount*MAX_TRUST_LEVEL),
|
108
109
|
total_required_disabled(*this, 0, packageCount), total_induced_disabled(*this, 0, packageCount),
|
@@ -128,16 +129,16 @@ VersionProblem::VersionProblem(int packageCount, bool dumpStats, bool debug, con
|
|
128
129
|
if (debugLogging) {
|
129
130
|
DEBUG_STREAM << std::endl;
|
130
131
|
DEBUG_STREAM << debugPrefix << "Creating VersionProblem inst# " << instance_id << " with " << packageCount << " packages, "
|
131
|
-
<< dumpStats << " stats, " << debug << " debug" << std::endl;
|
132
|
+
<< dumpStats << " stats, " << debug << " debug " << timeout << " timeout" << std::endl;
|
132
133
|
DEBUG_STREAM.flush();
|
133
134
|
}
|
134
135
|
}
|
135
136
|
|
136
137
|
VersionProblem::VersionProblem(bool share, VersionProblem & s)
|
137
138
|
: Space(share, s),
|
138
|
-
size(s.size), version_constraint_count(s.version_constraint_count),
|
139
|
-
dump_stats(s.dump_stats),
|
140
|
-
debugLogging(s.debugLogging),
|
139
|
+
size(s.size), version_constraint_count(s.version_constraint_count),
|
140
|
+
dump_stats(s.dump_stats),
|
141
|
+
debugLogging(s.debugLogging), timeout(s.timeout), solutionState(s.solutionState),
|
141
142
|
finalized(s.finalized), cur_package(s.cur_package),
|
142
143
|
disabled_package_variables(s.disabled_package_variables), total_disabled(s.total_disabled),
|
143
144
|
total_required_disabled(s.total_required_disabled), total_induced_disabled(s.total_induced_disabled),
|
@@ -204,10 +205,10 @@ VersionProblem::AddPackage(int minVersion, int maxVersion, int currentVersion)
|
|
204
205
|
}
|
205
206
|
|
206
207
|
if (debugLogging) {
|
207
|
-
sprintf(outputBuffer, "%
|
208
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Adding package id %d/%d: min = %d, max = %d, current version %d\n",
|
208
209
|
debugPrefix, instance_id, cur_package, size, minVersion, maxVersion, currentVersion);
|
209
210
|
DEBUG_STREAM << outputBuffer;
|
210
|
-
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
211
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
211
212
|
// << " - Adding package id " << cur_package << '/' << size << ": min = " << minVersion << ", max = " << maxVersion << ", current version " << currentVersion << std::endl;
|
212
213
|
DEBUG_STREAM.flush();
|
213
214
|
}
|
@@ -232,10 +233,10 @@ VersionProblem::AddVersionConstraint(int packageId, int version,
|
|
232
233
|
|
233
234
|
version_constraint_count++;
|
234
235
|
if (debugLogging) {
|
235
|
-
sprintf(outputBuffer, "%sDepSelector inst# %d - Adding VC for %d @ %d depPkg %d [%d, %d]",
|
236
|
+
sprintf(outputBuffer, "%sDepSelector inst# %d - Adding VC for %d @ %d depPkg %d [%d, %d]\n",
|
236
237
|
debugPrefix, instance_id, packageId, version, dependentPackageId, minDependentVersion, maxDependentVersion);
|
237
238
|
DEBUG_STREAM << outputBuffer;
|
238
|
-
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
239
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
239
240
|
// << " - Adding VC for " << packageId << " @ " << version << " depPkg " << dependentPackageId
|
240
241
|
// << " [ " << minDependentVersion << ", " << maxDependentVersion << " ]" << std::endl;
|
241
242
|
DEBUG_STREAM.flush();
|
@@ -270,7 +271,7 @@ VersionProblem::MarkPackageSuspicious(int packageId)
|
|
270
271
|
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Suspicious %d",
|
271
272
|
debugPrefix, instance_id, packageId);
|
272
273
|
DEBUG_STREAM << outputBuffer;
|
273
|
-
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
274
|
+
// DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
274
275
|
// << " - Marking Package Suspicious " << packageId << std::endl;
|
275
276
|
DEBUG_STREAM.flush();
|
276
277
|
}
|
@@ -283,7 +284,7 @@ VersionProblem::MarkPackageRequired(int packageId)
|
|
283
284
|
|
284
285
|
if (debugLogging) {
|
285
286
|
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Required %d", debugPrefix, instance_id, packageId);
|
286
|
-
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
287
|
+
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
287
288
|
<< " - Marking Package Required " << packageId << std::endl;
|
288
289
|
DEBUG_STREAM.flush();
|
289
290
|
}
|
@@ -297,7 +298,7 @@ VersionProblem::MarkPackagePreferredToBeAtLatest(int packageId, int weight)
|
|
297
298
|
if (debugLogging) {
|
298
299
|
sprintf(outputBuffer, "%sDepSelector inst# %d - Marking Package Preferred Latest %d weight %d",
|
299
300
|
debugPrefix, instance_id, packageId, weight);
|
300
|
-
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
301
|
+
DEBUG_STREAM << debugPrefix << "DepSelector inst# " << instance_id
|
301
302
|
<< " - Marking Package Preferred Latest " << packageId << " weight " << weight << std::endl;
|
302
303
|
DEBUG_STREAM.flush();
|
303
304
|
}
|
@@ -310,6 +311,7 @@ void VersionProblem::Finalize()
|
|
310
311
|
DEBUG_STREAM.flush();
|
311
312
|
}
|
312
313
|
finalized = true;
|
314
|
+
solutionState = SOLUTION_STATE_FINALIZED;
|
313
315
|
|
314
316
|
// Setup constraint for cost
|
315
317
|
// We wish to minimize the total number of disabled packages, by priority ranks
|
@@ -381,11 +383,51 @@ void VersionProblem::Finalize()
|
|
381
383
|
}
|
382
384
|
|
383
385
|
#ifdef USE_DUMB_BRANCHING
|
386
|
+
AddBrancherPoor(DEBUG_STREAM);
|
387
|
+
#else // USE_DUMB_BRANCHING
|
388
|
+
AddBrancherV2(DEBUG_STREAM);
|
389
|
+
#endif // USE_DUMB_BRANCHING
|
390
|
+
|
391
|
+
if (debugLogging) {
|
392
|
+
DEBUG_STREAM << debugPrefix << "Finalization Done" << std::endl;
|
393
|
+
DEBUG_STREAM.flush();
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
// GECODE VERSION NUMBER is 100000 * x + 100 * y + z for version x.y.z
|
398
|
+
#ifndef GECODE_VERSION_3
|
399
|
+
#undef INT_VAL_MAX
|
400
|
+
#undef INT_VAL_MIN
|
401
|
+
#undef INT_VAR_DEGREE_MAX
|
402
|
+
#undef INT_VAR_DEGREE_MIN
|
403
|
+
#undef INT_VAR_SIZE_MAX
|
404
|
+
#undef INT_VAR_SIZE_MIN
|
405
|
+
|
406
|
+
#define INT_VAL_MAX INT_VAL_MAX()
|
407
|
+
#define INT_VAL_MIN INT_VAL_MIN()
|
408
|
+
#define INT_VAR_DEGREE_MAX INT_VAR_DEGREE_MAX()
|
409
|
+
#define INT_VAR_DEGREE_MIN INT_VAR_DEGREE_MINX()
|
410
|
+
#define INT_VAR_SIZE_MAX INT_VAR_SIZE_MAX()
|
411
|
+
#define INT_VAR_SIZE_MIN INT_VAR_SIZE_MIN()
|
412
|
+
|
413
|
+
#endif
|
414
|
+
|
415
|
+
// Define various branchers:
|
416
|
+
//
|
417
|
+
// The ordering here is important; we make variable choices in
|
418
|
+
// order that the branchings are listed, and a bad variable choice
|
419
|
+
// can be orders of magnitude slower to solve. In general we want to
|
420
|
+
// choose variables that generate lots of propagations; each variable
|
421
|
+
// choice can involve a backtrack, so the bias is towards maximizing the
|
422
|
+
// bindings induced by a choice.
|
423
|
+
|
424
|
+
// This branching starts as far as possible from the solution, in order to exercise the optimization functions.
|
425
|
+
void VersionProblem::AddBrancherPoor(std::ostream & o) {
|
384
426
|
if (debugLogging) {
|
385
427
|
DEBUG_STREAM << debugPrefix << " Adding branching (POOR)" << std::endl;
|
386
428
|
DEBUG_STREAM.flush();
|
387
429
|
}
|
388
|
-
|
430
|
+
|
389
431
|
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
390
432
|
branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
391
433
|
branch(*this, total_required_disabled, INT_VAL_MAX);
|
@@ -395,12 +437,19 @@ void VersionProblem::Finalize()
|
|
395
437
|
branch(*this, at_latest, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
396
438
|
branch(*this, total_preferred_at_latest, INT_VAL_MIN);
|
397
439
|
branch(*this, total_not_preferred_at_latest, INT_VAL_MIN);
|
398
|
-
|
440
|
+
}
|
441
|
+
|
442
|
+
// This is the 'classic' brancher that's been used since 2012. Has
|
443
|
+
// some pathological solves
|
444
|
+
void VersionProblem::AddBrancherOriginal(std::ostream & o) {
|
399
445
|
if (debugLogging) {
|
400
|
-
DEBUG_STREAM << debugPrefix << " Adding branching (
|
446
|
+
DEBUG_STREAM << debugPrefix << " Adding branching (ORIGINAL)" << std::endl;
|
401
447
|
DEBUG_STREAM.flush();
|
402
448
|
}
|
403
449
|
// This branching is meant to start with most probable solution
|
450
|
+
// The ordering here is important; we make variable choices in
|
451
|
+
// order that the branchings are listed, and a bad variable choice
|
452
|
+
// can be orders of magnitude slower to solve.
|
404
453
|
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
405
454
|
branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
406
455
|
branch(*this, total_required_disabled, INT_VAL_MIN);
|
@@ -410,12 +459,50 @@ void VersionProblem::Finalize()
|
|
410
459
|
branch(*this, at_latest, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
411
460
|
branch(*this, total_preferred_at_latest, INT_VAL_MAX);
|
412
461
|
branch(*this, total_not_preferred_at_latest, INT_VAL_MAX);
|
413
|
-
|
462
|
+
}
|
414
463
|
|
415
|
-
|
416
|
-
|
464
|
+
// This is the minimal tweak to the 'classic' brancher that avoids the solves.
|
465
|
+
void VersionProblem::AddBrancherV2(std::ostream & o) {
|
466
|
+
if (debugLogging) {
|
467
|
+
DEBUG_STREAM << debugPrefix << " Adding branching (V2)" << std::endl;
|
417
468
|
DEBUG_STREAM.flush();
|
418
469
|
}
|
470
|
+
// This branching is meant to start with most probable solution
|
471
|
+
// The ordering here is important; we make variable choices in
|
472
|
+
// order that the branchings are listed, and a bad variable choice
|
473
|
+
// can be orders of magnitude slower to solve.
|
474
|
+
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
475
|
+
// Using INT_VAR_SIZE_MIN (what old versions do; can cause 12E3 x slowdown)
|
476
|
+
branch(*this, package_versions, INT_VAR_DEGREE_MAX, INT_VAL_MAX);
|
477
|
+
branch(*this, total_required_disabled, INT_VAL_MIN);
|
478
|
+
branch(*this, total_induced_disabled, INT_VAL_MIN);
|
479
|
+
branch(*this, total_suspicious_disabled, INT_VAL_MIN);
|
480
|
+
branch(*this, total_disabled, INT_VAL_MIN);
|
481
|
+
branch(*this, at_latest, INT_VAR_SIZE_MIN, INT_VAL_MAX);
|
482
|
+
branch(*this, total_preferred_at_latest, INT_VAL_MAX);
|
483
|
+
branch(*this, total_not_preferred_at_latest, INT_VAL_MAX);
|
484
|
+
}
|
485
|
+
|
486
|
+
// This behaves better on some problems, and worse on others; still
|
487
|
+
// figuring out why. Behaves very well on gecode 4.x
|
488
|
+
void VersionProblem::AddBrancherAtLatest(std::ostream & o) {
|
489
|
+
if (debugLogging) {
|
490
|
+
DEBUG_STREAM << debugPrefix << " Adding branching (AtLatest)" << std::endl;
|
491
|
+
DEBUG_STREAM.flush();
|
492
|
+
}
|
493
|
+
// We total preferred at latest at maximum first, to trigger as much
|
494
|
+
// propagation as possible, followed by all other packages at
|
495
|
+
// latest in order of degree (# of constraints related to this variable)
|
496
|
+
//
|
497
|
+
branch(*this, package_versions, INT_VAR_DEGREE_MAX, INT_VAL_MAX);
|
498
|
+
branch(*this, at_latest, INT_VAR_DEGREE_MAX, INT_VAL_MAX);
|
499
|
+
branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
|
500
|
+
branch(*this, total_preferred_at_latest, INT_VAL_MAX);
|
501
|
+
branch(*this, total_disabled, INT_VAL_MIN);
|
502
|
+
branch(*this, total_required_disabled, INT_VAL_MIN);
|
503
|
+
branch(*this, total_induced_disabled, INT_VAL_MIN);
|
504
|
+
branch(*this, total_suspicious_disabled, INT_VAL_MIN);
|
505
|
+
branch(*this, total_not_preferred_at_latest, INT_VAL_MAX);
|
419
506
|
}
|
420
507
|
|
421
508
|
////////////////////////////////////////////////////////////////////////
|
@@ -490,6 +577,7 @@ void VersionProblem::constrain(const Space & _best_known_solution)
|
|
490
577
|
IntVarArgs best(5);
|
491
578
|
BuildCostVector(current);
|
492
579
|
best_known_solution.BuildCostVector(best);
|
580
|
+
// rel(*this, best, IRT_LE, current);
|
493
581
|
ConstrainVectorLessThanBest(current, best);
|
494
582
|
}
|
495
583
|
#endif // VECTOR_CONSTRAIN
|
@@ -502,7 +590,34 @@ void VersionProblem::BuildCostVector(IntVarArgs & costVector) const {
|
|
502
590
|
costVector[4] = total_required_disabled;
|
503
591
|
}
|
504
592
|
|
593
|
+
// We want to sort vectors
|
594
|
+
// This constrains current to be less than best by a process analogous to subtraction
|
595
|
+
// we compute current - best, pairwise with borrows from less significant elements. We require it to be less than zero by requiring the most
|
596
|
+
// significant element to generate a borrow.
|
597
|
+
//
|
598
|
+
// DEPRECATED; remove once replacement is validated
|
599
|
+
void VersionProblem::ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best) {
|
600
|
+
BoolVarArray borrow(*this, current.size()+1, 0, 1);
|
505
601
|
|
602
|
+
// No borrows can happen at the least significant element.
|
603
|
+
rel(*this, borrow[0], IRT_EQ, 0);
|
604
|
+
|
605
|
+
for (int i = 0; i < current.size(); i++) {
|
606
|
+
// If best+borrow is greater than current (equivalently current-(best+borrow) is < 0) then a more significant element
|
607
|
+
// must have decreased, so we propagate a borrow to the next most significant element.
|
608
|
+
int best_val = best[i].val();
|
609
|
+
IntVar delta = expr(*this, current[i] - best_val - borrow[i]);
|
610
|
+
// (delta < 0) <=> borrow[i+1]
|
611
|
+
rel(*this, delta, IRT_LE, 0, borrow[i+1]);
|
612
|
+
if (debugLogging) {
|
613
|
+
DEBUG_STREAM << debugPrefix << " ConstrainVector: borrow[" << i+1 << "] " << borrow[i+1] << ",\tdelta " << delta << std::endl;
|
614
|
+
DEBUG_STREAM << debugPrefix << " ConstrainVector: current[" << i << "] " << current[i] << ",\tbest_val " << best_val << std::endl;
|
615
|
+
}
|
616
|
+
}
|
617
|
+
|
618
|
+
// must borrow off past the most significant element.
|
619
|
+
rel(*this, borrow[current.size()], IRT_EQ, 1);
|
620
|
+
}
|
506
621
|
|
507
622
|
IntVar * VersionProblem::GetPackageVersionVar(int packageId)
|
508
623
|
{
|
@@ -546,6 +661,16 @@ int VersionProblem::GetDisabledVariableCount()
|
|
546
661
|
}
|
547
662
|
}
|
548
663
|
|
664
|
+
void VersionProblem::SetTimeout(unsigned long int _timeout)
|
665
|
+
{
|
666
|
+
timeout = _timeout;
|
667
|
+
}
|
668
|
+
|
669
|
+
int VersionProblem::GetSolutionState()
|
670
|
+
{
|
671
|
+
return solutionState;
|
672
|
+
}
|
673
|
+
|
549
674
|
|
550
675
|
// Utility
|
551
676
|
void VersionProblem::Print(std::ostream & out)
|
@@ -580,88 +705,124 @@ bool VersionProblem::CheckPackageId(int id)
|
|
580
705
|
return (id < size);
|
581
706
|
}
|
582
707
|
|
583
|
-
|
584
|
-
// This constrains current to be less than best by a process analogous to subtraction
|
585
|
-
// we compute current - best, pairwise with borrows from less significant elements. We require it to be less than zero by requiring the most
|
586
|
-
// significant element to generate a borrow.
|
587
|
-
//
|
588
|
-
void VersionProblem::ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best) {
|
589
|
-
BoolVarArray borrow(*this, current.size()+1, 0, 1);
|
590
|
-
|
591
|
-
// No borrows can happen at the least significant element.
|
592
|
-
rel(*this, borrow[0], IRT_EQ, 0);
|
593
|
-
|
594
|
-
for (int i = 0; i < current.size(); i++) {
|
595
|
-
// If best+borrow is greater than current (equivalently current-(best+borrow) is < 0) then a more significant element
|
596
|
-
// must have decreased, so we propagate a borrow to the next most significant element.
|
597
|
-
int best_val = best[i].val();
|
598
|
-
IntVar delta = expr(*this, current[i] - best_val - borrow[i]);
|
599
|
-
// (delta < 0) <=> borrow[i+1]
|
600
|
-
rel(*this, delta, IRT_LE, 0, borrow[i+1]);
|
601
|
-
if (debugLogging) {
|
602
|
-
DEBUG_STREAM << debugPrefix << " ConstrainVector: borrow[" << i+1 << "] " << borrow[i+1] << ",\tdelta " << delta << std::endl;
|
603
|
-
DEBUG_STREAM << debugPrefix << " ConstrainVector: current[" << i << "] " << current[i] << ",\tbest_val " << best_val << std::endl;
|
604
|
-
}
|
605
|
-
}
|
606
|
-
|
607
|
-
// must borrow off past the most significant element.
|
608
|
-
rel(*this, borrow[current.size()], IRT_EQ, 1);
|
609
|
-
}
|
610
|
-
|
611
|
-
VersionProblem * VersionProblem::InnerSolve(VersionProblem * problem, int &itercount)
|
708
|
+
int VersionProblem::InnerSolve(VersionProblem * problem, int &itercount, VersionProblem** best_solution)
|
612
709
|
{
|
613
|
-
Gecode::Support::Timer timer;
|
614
|
-
timer.start();
|
615
|
-
|
616
710
|
#ifdef MEMORY_DEBUG
|
617
711
|
DEBUG_STREAM << "Creating solver" << std::endl << std::flush;
|
618
712
|
#endif
|
619
|
-
|
620
|
-
|
713
|
+
Gecode::Support::Timer timer;
|
714
|
+
timer.start();
|
715
|
+
*best_solution = NULL;
|
716
|
+
int result_code = SOLUTION_STATE_FAILED;
|
717
|
+
|
718
|
+
// This needs to accumulate over multiple steps.
|
719
|
+
Search::TimeStop timeStop(problem->timeout);
|
720
|
+
Search::Options options;
|
721
|
+
options.stop = &timeStop;
|
722
|
+
|
723
|
+
#ifdef GECODE_VERSION_3
|
724
|
+
// Restart strategy starts branching from scratch. BNB adds the
|
725
|
+
// constraint but keeps on going from where it was currently.
|
726
|
+
Restart<VersionProblem> solver(problem, options);
|
727
|
+
#else
|
728
|
+
options.cutoff = Search::Cutoff::geometric();
|
729
|
+
RBS<DFS, VersionProblem> solver(problem, options);
|
730
|
+
#endif
|
731
|
+
|
621
732
|
|
622
733
|
#ifdef MEMORY_DEBUG
|
623
734
|
DEBUG_STREAM << "Starting Solve" << std::endl << std::flush;
|
624
735
|
#endif
|
625
736
|
|
626
|
-
|
627
|
-
|
737
|
+
// Iterate over solutions; each call to solver.next creates a new
|
738
|
+
// copy of the problem, and constrains it to be better than the
|
739
|
+
// last solution. Null is returned if no solution is found.
|
740
|
+
while (VersionProblem *solution = solver.next()) {
|
741
|
+
|
628
742
|
#ifdef MEMORY_DEBUG
|
629
|
-
|
743
|
+
DEBUG_STREAM << "Solver Next " << solution << std::endl << std::flush;
|
630
744
|
#endif
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
745
|
+
delete *best_solution;
|
746
|
+
*best_solution = solution;
|
747
|
+
|
748
|
+
++itercount;
|
749
|
+
const Search::Statistics & stats = solver.statistics();
|
750
|
+
DebugLogStep(solution, itercount, stats);
|
751
|
+
}
|
752
|
+
|
753
|
+
// Solve with GIST:
|
754
|
+
VersionProblem * last = *best_solution ? *best_solution : problem;
|
755
|
+
last->GistSolveStep();
|
756
|
+
|
757
|
+
// If we fail to find a solution in time we treat it as no
|
758
|
+
// solution. We could return a special token to differentiate a
|
759
|
+
// timeout, but that could cause problems for the FFI interface.
|
760
|
+
if (solver.stopped()) {
|
761
|
+
result_code = SOLUTION_STATE_TIMED_OUT;
|
762
|
+
if (problem->debugLogging) {
|
763
|
+
DEBUG_STREAM << problem->debugPrefix << "Solver FAILED: timed out with timeout set to "
|
764
|
+
<< problem->timeout << " ms" << std::endl;
|
765
|
+
const Search::Statistics & stats = solver.statistics();
|
766
|
+
LogStats(DEBUG_STREAM, problem->debugPrefix, stats);
|
644
767
|
}
|
645
768
|
|
769
|
+
} else if (*best_solution) {
|
770
|
+
result_code = SOLUTION_STATE_OPTIMAL;
|
771
|
+
} else {
|
772
|
+
result_code = SOLUTION_STATE_FAILED;
|
773
|
+
}
|
774
|
+
|
646
775
|
double elapsed_time = timer.stop();
|
647
776
|
|
648
777
|
if (problem->dump_stats) {
|
649
|
-
if (problem->debugLogging) std::cerr << problem->debugPrefix;
|
650
|
-
std::cerr << "dep_selector solve: ";
|
651
|
-
std::cerr << (best_solution ? "SOLVED" : "FAILED") << " ";
|
652
|
-
std::cerr << problem->size << " packages, " << problem->version_constraint_count << " constraints, ";
|
653
|
-
std::cerr << "Time: " << elapsed_time << "ms ";
|
654
778
|
const Search::Statistics & final_stats = solver.statistics();
|
655
|
-
|
656
|
-
std::cerr << final_stats.memory << " bytes, ";
|
657
|
-
std::cerr << final_stats.propagate << " props, " << final_stats.node << " nodes, " << final_stats.depth << " depth ";
|
658
|
-
std::cerr << std::endl << std::flush;
|
779
|
+
DebugLogFinal(problem, itercount, elapsed_time, final_stats, result_code);
|
659
780
|
}
|
660
781
|
|
661
|
-
return
|
782
|
+
return result_code;
|
662
783
|
}
|
663
784
|
|
664
|
-
|
785
|
+
void VersionProblem::GistSolveStep() {
|
786
|
+
#ifdef GIST_ENABLED
|
787
|
+
VersionProblem * trial = dynamic_cast<VersionProblem*>(this->copy(false));
|
788
|
+
trial->constrain(*this);
|
789
|
+
Gist::Options options;
|
790
|
+
Gist::dfs(trial, options);
|
791
|
+
delete trial;
|
792
|
+
#endif
|
793
|
+
}
|
794
|
+
|
795
|
+
void VersionProblem::LogStats(std::ostream & o, const char * debugPrefix, const Search::Statistics & stats) {
|
796
|
+
o << debugPrefix << "Solver stats: Prop:" << stats.propagate << " Fail:" << stats.fail << " Node:" << stats.node;
|
797
|
+
o << " Depth:" << stats.depth;
|
798
|
+
#ifdef GECODE_VERSION_3
|
799
|
+
o << " memory:" << stats.memory;
|
800
|
+
#endif // GECODE_VERSION_3
|
801
|
+
o << std::endl;
|
802
|
+
}
|
803
|
+
|
804
|
+
void VersionProblem::DebugLogStep(VersionProblem *problem, int itercount, const Search::Statistics & stats) {
|
805
|
+
if (problem->debugLogging) {
|
806
|
+
DEBUG_STREAM << problem->debugPrefix << "Trial Solution #" << itercount << "===============================" << std::endl;
|
807
|
+
LogStats(DEBUG_STREAM, problem->debugPrefix, stats);
|
808
|
+
problem->Print(DEBUG_STREAM);
|
809
|
+
}
|
810
|
+
}
|
811
|
+
|
812
|
+
void VersionProblem::DebugLogFinal(VersionProblem *problem, int itercount, double elapsed_time, const Search::Statistics & stats, int solutionState) {
|
813
|
+
if (problem->debugLogging) std::cerr << problem->debugPrefix;
|
814
|
+
std::cerr << "dep_selector solve: ";
|
815
|
+
std::cerr << ((solutionState == SOLUTION_STATE_OPTIMAL) ? "SOLVED" : "FAILED") << " ";
|
816
|
+
std::cerr << problem->size << " packages, " << problem->version_constraint_count << " constraints, ";
|
817
|
+
std::cerr << "Time: " << elapsed_time << "ms ";
|
818
|
+
|
819
|
+
std::cerr << "Stats: " << itercount << " steps, ";
|
820
|
+
LogStats(std::cerr, (problem->debugLogging ? problem->debugPrefix : ""), stats);
|
821
|
+
std::cerr << std::flush;
|
822
|
+
}
|
823
|
+
|
824
|
+
|
825
|
+
int VersionProblem::Solve(VersionProblem * problem, VersionProblem ** solution)
|
665
826
|
{
|
666
827
|
|
667
828
|
problem->Finalize();
|
@@ -676,19 +837,19 @@ VersionProblem * VersionProblem::Solve(VersionProblem * problem)
|
|
676
837
|
}
|
677
838
|
int itercount = 0;
|
678
839
|
|
679
|
-
|
840
|
+
int result_code = InnerSolve(problem, itercount, solution);
|
680
841
|
|
681
842
|
if (problem->debugLogging) {
|
682
|
-
DEBUG_STREAM << problem->DebugPrefix() << "Solver Best Solution " <<
|
843
|
+
DEBUG_STREAM << problem->DebugPrefix() << "Solver Best Solution " << *solution << std::endl << std::flush;
|
683
844
|
}
|
684
845
|
|
685
|
-
pool->Delete(
|
846
|
+
pool->Delete(*solution);
|
686
847
|
problem->pool = 0;
|
687
848
|
|
688
849
|
pool->DeleteAll();
|
689
850
|
delete pool;
|
690
851
|
|
691
|
-
return
|
852
|
+
return result_code;
|
692
853
|
}
|
693
854
|
|
694
855
|
//
|
@@ -21,13 +21,18 @@
|
|
21
21
|
#define dep_selector_to_gecode_h
|
22
22
|
|
23
23
|
#include "dep_selector_to_gecode_interface.h"
|
24
|
-
#include <iostream>
|
24
|
+
#include <iostream>
|
25
25
|
#include <vector>
|
26
26
|
#include <set>
|
27
27
|
|
28
28
|
#include <gecode/driver.hh>
|
29
29
|
#include <gecode/int.hh>
|
30
30
|
#include <gecode/minimodel.hh>
|
31
|
+
#include <gecode/support.hh>
|
32
|
+
|
33
|
+
#if GECODE_VERSION_NUMBER < 400000
|
34
|
+
#define GECODE_VERSION_3
|
35
|
+
#endif
|
31
36
|
|
32
37
|
using namespace Gecode;
|
33
38
|
|
@@ -39,10 +44,10 @@ using namespace Gecode;
|
|
39
44
|
|
40
45
|
// Extend:
|
41
46
|
// Add optimization functions
|
42
|
-
// Allow non-contiguous ranges in package dependencies.
|
47
|
+
// Allow non-contiguous ranges in package dependencies.
|
43
48
|
|
44
|
-
// TODO: Add locking
|
45
|
-
struct VersionProblemPool
|
49
|
+
// TODO: Add locking
|
50
|
+
struct VersionProblemPool
|
46
51
|
{
|
47
52
|
std::set<VersionProblem *> elems;
|
48
53
|
VersionProblemPool();
|
@@ -59,15 +64,16 @@ class VersionProblem : public Space
|
|
59
64
|
{
|
60
65
|
public:
|
61
66
|
static const int UNRESOLVED_VARIABLE;
|
62
|
-
static const int MIN_TRUST_LEVEL;
|
67
|
+
static const int MIN_TRUST_LEVEL;
|
63
68
|
static const int MAX_TRUST_LEVEL;
|
64
69
|
static const int MAX_PREFERRED_WEIGHT;
|
65
70
|
|
66
71
|
static int instance_counter;
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
73
|
+
VersionProblem(int packageCount, bool dumpStats = true,
|
74
|
+
bool debug = false,
|
75
|
+
const char * logId = 0,
|
76
|
+
unsigned long int _timeout = 10000);
|
71
77
|
// Clone constructor; check gecode rules for this...
|
72
78
|
VersionProblem(bool share, VersionProblem & s);
|
73
79
|
virtual ~VersionProblem();
|
@@ -80,20 +86,20 @@ public:
|
|
80
86
|
virtual int AddPackage(int minVersion, int maxVersion, int currentVersion);
|
81
87
|
|
82
88
|
virtual void AddVersionConstraint(int packageId, int version,
|
83
|
-
|
89
|
+
int dependentPackageId, int minDependentVersion, int maxDependentVersion);
|
84
90
|
|
85
|
-
// We may wish to indicate that some packages have suspicious constraints, and when chosing packages to disable we
|
86
|
-
// would disable them first.
|
91
|
+
// We may wish to indicate that some packages have suspicious constraints, and when chosing packages to disable we
|
92
|
+
// would disable them first.
|
87
93
|
void MarkPackageSuspicious(int packageId);
|
88
94
|
|
89
|
-
void MarkPackageRequired(int packageId);
|
95
|
+
void MarkPackageRequired(int packageId);
|
90
96
|
|
91
97
|
// Packages marked by this method are preferentially chosen at
|
92
98
|
// latest according to weights
|
93
99
|
void MarkPackagePreferredToBeAtLatest(int packageId, int weight);
|
94
100
|
|
95
101
|
void Finalize();
|
96
|
-
|
102
|
+
|
97
103
|
virtual void constrain(const Space & _best_known_solution);
|
98
104
|
|
99
105
|
int GetPackageVersion(int packageId);
|
@@ -101,17 +107,27 @@ public:
|
|
101
107
|
int GetMax(int packageId);
|
102
108
|
int GetMin(int packageId);
|
103
109
|
int GetDisabledVariableCount();
|
104
|
-
|
110
|
+
|
111
|
+
void SetTimeout(unsigned long int _timeout);
|
112
|
+
int GetSolutionState();
|
113
|
+
|
105
114
|
// Support for gecode
|
106
115
|
virtual Space* copy(bool share);
|
107
116
|
|
108
117
|
// Debug and utility functions
|
109
118
|
void Print(std::ostream &out);
|
110
119
|
void PrintPackageVar(std::ostream & out, int packageId) ;
|
120
|
+
void GistSolveStep();
|
121
|
+
|
111
122
|
const char * DebugPrefix() const { return debugPrefix; }
|
112
123
|
|
113
|
-
static
|
114
|
-
|
124
|
+
static int InnerSolve(VersionProblem * problem, int & itercount, VersionProblem** solution);
|
125
|
+
|
126
|
+
static void DebugLogStep(VersionProblem *problem, int itercount, const Search::Statistics & stats);
|
127
|
+
static void LogStats(std::ostream & o, const char * debugPrefix, const Search::Statistics & stats);
|
128
|
+
static void DebugLogFinal(VersionProblem *problem, int itercount, double elapsed_time, const Search::Statistics & stats, int solutionState);
|
129
|
+
|
130
|
+
static int Solve(VersionProblem *problem, VersionProblem**solution);
|
115
131
|
|
116
132
|
protected:
|
117
133
|
int instance_id;
|
@@ -122,6 +138,9 @@ public:
|
|
122
138
|
bool debugLogging;
|
123
139
|
char debugPrefix[DEBUG_PREFIX_LENGTH];
|
124
140
|
char outputBuffer[1024];
|
141
|
+
unsigned long int timeout;
|
142
|
+
int solutionState;
|
143
|
+
|
125
144
|
bool finalized;
|
126
145
|
|
127
146
|
BoolVarArgs version_flags;
|
@@ -147,19 +166,16 @@ public:
|
|
147
166
|
void AddPackagesPreferredToBeAtLatestObjectiveFunction(const VersionProblem & best_known_solution);
|
148
167
|
void ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best);
|
149
168
|
void BuildCostVector(IntVarArgs & costVector) const;
|
150
|
-
|
169
|
+
|
170
|
+
void AddBrancherPoor(std::ostream & o);
|
171
|
+
void AddBrancherOriginal(std::ostream & o);
|
172
|
+
void AddBrancherV2(std::ostream & o);
|
173
|
+
void AddBrancherAtLatest(std::ostream & o);
|
174
|
+
|
151
175
|
friend class VersionProblemPool;
|
152
176
|
};
|
153
177
|
|
154
178
|
template<class T> void PrintVarAligned(const char * message, T & var);
|
155
179
|
template<class S, class T> void PrintVarAligned(const char * message, S & var1, T & var2);
|
156
180
|
|
157
|
-
class Solver {
|
158
|
-
public:
|
159
|
-
Solver(VersionProblem *s);
|
160
|
-
VersionProblem GetNextSolution();
|
161
|
-
private:
|
162
|
-
Restart<VersionProblem> solver;
|
163
|
-
};
|
164
|
-
|
165
181
|
#endif // dep_selector_to_gecode_h
|
@@ -30,9 +30,10 @@
|
|
30
30
|
|
31
31
|
// FFI friendly
|
32
32
|
VersionProblem * VersionProblemCreate(int packageCount, bool dump_stats,
|
33
|
-
bool debug, const char * logId
|
33
|
+
bool debug, const char * logId,
|
34
|
+
unsigned long int _timeout)
|
34
35
|
{
|
35
|
-
return new VersionProblem(packageCount, dump_stats, debug, logId);
|
36
|
+
return new VersionProblem(packageCount, dump_stats, debug, logId, _timeout);
|
36
37
|
}
|
37
38
|
|
38
39
|
void VersionProblemDestroy(VersionProblem * p)
|
@@ -40,12 +41,12 @@ void VersionProblemDestroy(VersionProblem * p)
|
|
40
41
|
delete p;
|
41
42
|
}
|
42
43
|
|
43
|
-
int VersionProblemSize(VersionProblem *p)
|
44
|
+
int VersionProblemSize(VersionProblem *p)
|
44
45
|
{
|
45
46
|
return p->Size();
|
46
47
|
}
|
47
48
|
|
48
|
-
int VersionProblemPackageCount(VersionProblem *p)
|
49
|
+
int VersionProblemPackageCount(VersionProblem *p)
|
49
50
|
{
|
50
51
|
return p->PackageCount();
|
51
52
|
}
|
@@ -58,7 +59,7 @@ void VersionProblemDump(VersionProblem *p)
|
|
58
59
|
std::cout.flush();
|
59
60
|
}
|
60
61
|
|
61
|
-
void VersionProblemPrintPackageVar(VersionProblem *p, int packageId)
|
62
|
+
void VersionProblemPrintPackageVar(VersionProblem *p, int packageId)
|
62
63
|
{
|
63
64
|
p->PrintPackageVar(std::cout, packageId);
|
64
65
|
std::cout.flush();
|
@@ -68,16 +69,16 @@ void VersionProblemPrintPackageVar(VersionProblem *p, int packageId)
|
|
68
69
|
int AddPackage(VersionProblem *problem, int min, int max, int currentVersion) {
|
69
70
|
return problem->AddPackage(min,max,currentVersion);
|
70
71
|
}
|
71
|
-
// Add constraint for package pkg @ version,
|
72
|
+
// Add constraint for package pkg @ version,
|
72
73
|
// that dependentPackage is at version [minDependentVersion,maxDependentVersion]
|
73
74
|
// Returns false if system becomes insoluble.
|
74
75
|
void AddVersionConstraint(VersionProblem *problem, int packageId, int version,
|
75
|
-
|
76
|
+
int dependentPackageId, int minDependentVersion, int maxDependentVersion)
|
76
77
|
{
|
77
78
|
return problem->AddVersionConstraint(packageId, version, dependentPackageId, minDependentVersion, maxDependentVersion);
|
78
79
|
}
|
79
80
|
|
80
|
-
void MarkPackageSuspicious(VersionProblem *problem, int packageId)
|
81
|
+
void MarkPackageSuspicious(VersionProblem *problem, int packageId)
|
81
82
|
{
|
82
83
|
return problem->MarkPackageSuspicious(packageId);
|
83
84
|
}
|
@@ -117,7 +118,16 @@ int GetDisabledVariableCount(VersionProblem *problem)
|
|
117
118
|
return problem->GetDisabledVariableCount();
|
118
119
|
}
|
119
120
|
|
121
|
+
void SetTimeout(VersionProblem *problem, unsigned long int timeout)
|
122
|
+
{
|
123
|
+
problem->SetTimeout(timeout);
|
124
|
+
}
|
125
|
+
|
126
|
+
int GetSolutionState(VersionProblem * problem)
|
127
|
+
{
|
128
|
+
return problem->GetSolutionState();
|
129
|
+
}
|
120
130
|
|
121
|
-
|
122
|
-
|
131
|
+
int Solve(VersionProblem * problem, VersionProblem ** solution) {
|
132
|
+
return VersionProblem::Solve(problem, solution);
|
123
133
|
}
|
@@ -25,6 +25,15 @@
|
|
25
25
|
extern "C" {
|
26
26
|
#endif // __cplusplus
|
27
27
|
|
28
|
+
#define SOLUTION_STATE_FAILED 0
|
29
|
+
#define SOLUTION_STATE_UNSTARTED 1
|
30
|
+
#define SOLUTION_STATE_FINALIZED 2
|
31
|
+
#define SOLUTION_STATE_SOLVED 3
|
32
|
+
#define SOLUTION_STATE_TIMED_OUT 4
|
33
|
+
#define SOLUTION_STATE_OPTIMAL 5
|
34
|
+
|
35
|
+
|
36
|
+
|
28
37
|
#ifdef __cplusplus
|
29
38
|
class VersionProblem;
|
30
39
|
#else
|
@@ -32,7 +41,8 @@ extern "C" {
|
|
32
41
|
#endif // __cplusplus
|
33
42
|
|
34
43
|
VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
|
35
|
-
bool debug, const char * logId
|
44
|
+
bool debug, const char * logId,
|
45
|
+
unsigned long int timeout);
|
36
46
|
void VersionProblemDestroy(VersionProblem * vp);
|
37
47
|
|
38
48
|
|
@@ -41,11 +51,11 @@ extern "C" {
|
|
41
51
|
|
42
52
|
// Return ID #
|
43
53
|
int AddPackage(VersionProblem *problem, int min, int max, int currentVersion);
|
44
|
-
// Add constraint for package pkg @ version,
|
54
|
+
// Add constraint for package pkg @ version,
|
45
55
|
// that dependentPackage is at version [minDependentVersion,maxDependentVersion]
|
46
56
|
// Returns false if system becomes insoluble.
|
47
57
|
void AddVersionConstraint(VersionProblem *problem, int packageId, int version,
|
48
|
-
|
58
|
+
int dependentPackageId, int minDependentVersion, int maxDependentVersion);
|
49
59
|
|
50
60
|
void MarkPackageSuspicious(VersionProblem *problem, int packageId);
|
51
61
|
void MarkPackageRequired(VersionProblem *problem, int packageId);
|
@@ -59,10 +69,13 @@ extern "C" {
|
|
59
69
|
|
60
70
|
int GetDisabledVariableCount(VersionProblem *problem);
|
61
71
|
|
72
|
+
void SetTimeout(VersionProblem *problem, unsigned long int timeout);
|
73
|
+
int GetSolutionState(VersionProblem *problem);
|
74
|
+
|
62
75
|
void VersionProblemDump(VersionProblem * problem);
|
63
76
|
void VersionProblemPrintPackageVar(VersionProblem * problem, int packageId);
|
64
77
|
|
65
|
-
|
78
|
+
int Solve(VersionProblem * problem, VersionProblem** solution);
|
66
79
|
|
67
80
|
#ifdef __cplusplus
|
68
81
|
}
|
data/lib/dep_selector.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Salim Alam (<salam@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2016 Chef, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'logger'
|
20
|
+
|
21
|
+
module DepSelector
|
22
|
+
class Debug
|
23
|
+
class << self
|
24
|
+
def log
|
25
|
+
@logger ||= Logger.new(STDOUT)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -38,9 +38,9 @@ module Dep_gecode
|
|
38
38
|
|
39
39
|
ffi_lib path
|
40
40
|
|
41
|
-
# VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
|
42
|
-
# bool debug, const char * log_id);
|
43
|
-
attach_function :VersionProblemCreate, [:int, :bool, :bool, :string], :pointer
|
41
|
+
# VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
|
42
|
+
# bool debug, const char * log_id, unsigned long int _timeout);
|
43
|
+
attach_function :VersionProblemCreate, [:int, :bool, :bool, :string, :ulong], :pointer
|
44
44
|
|
45
45
|
# void VersionProblemDestroy(VersionProblem * vp);
|
46
46
|
attach_function :VersionProblemDestroy, [:pointer], :void
|
@@ -48,7 +48,7 @@ module Dep_gecode
|
|
48
48
|
# int AddPackage(VersionProblem *problem, int min, int max, int currentVersion);
|
49
49
|
attach_function :AddPackage, [:pointer, :int, :int, :int], :int
|
50
50
|
|
51
|
-
# int VersionProblemSize(VersionProblem *p);
|
51
|
+
# int VersionProblemSize(VersionProblem *p);
|
52
52
|
attach_function :VersionProblemSize, [:pointer], :int
|
53
53
|
|
54
54
|
# void MarkPackagePreferredToBeAtLatest(VersionProblem *problem, int packageId, int weight);
|
@@ -62,7 +62,7 @@ module Dep_gecode
|
|
62
62
|
attach_function :AddVersionConstraint, [:pointer, :int, :int, :int, :int, :int], :void
|
63
63
|
|
64
64
|
# VersionProblem * Solve(VersionProblem * problem);
|
65
|
-
attach_function :Solve, [:pointer], :
|
65
|
+
attach_function :Solve, [:pointer, :pointer], :int
|
66
66
|
|
67
67
|
# int GetDisabledVariableCount(VersionProblem *problem);
|
68
68
|
attach_function :GetDisabledVariableCount, [:pointer], :int
|
@@ -84,6 +84,9 @@ module Dep_gecode
|
|
84
84
|
|
85
85
|
# int GetPackageMin(VersionProblem *problem, int packageId);
|
86
86
|
attach_function :GetPackageMin, [:pointer, :int], :int
|
87
|
-
|
87
|
+
|
88
|
+
# void SetTimeout(VersionProblem * problem, unsigned long int);
|
89
|
+
attach_function :SetTimeout, [:pointer, :ulong], :void
|
88
90
|
|
89
91
|
|
92
|
+
end
|
@@ -60,11 +60,17 @@ module DepSelector
|
|
60
60
|
packages.map{ |name, pkg| pkg }
|
61
61
|
end
|
62
62
|
|
63
|
+
logId = SecureRandom.uuid
|
63
64
|
debugFlag = DebugOptionFile && File::exists?(DebugOptionFile)
|
65
|
+
Debug.log.level = Logger::INFO unless debugFlag
|
66
|
+
Debug.log.formatter = proc do |severity, datetime, progname, msg|
|
67
|
+
"#{logId}: #{msg}\n"
|
68
|
+
end
|
69
|
+
|
64
70
|
# In addition to all the packages that the user specified,
|
65
71
|
# there is a "ghost" package that contains the solution
|
66
72
|
# constraints. See Selector#solve for more information.
|
67
|
-
@gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1, debugFlag)
|
73
|
+
@gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1, logId, debugFlag)
|
68
74
|
packages_in_solve.each{ |pkg| pkg.generate_gecode_wrapper_constraints }
|
69
75
|
end
|
70
76
|
end
|
@@ -37,17 +37,27 @@ module DepSelector
|
|
37
37
|
|
38
38
|
attr_reader :gecode_problem
|
39
39
|
attr_reader :debug_logs_on
|
40
|
+
attr_reader :log_id
|
41
|
+
|
40
42
|
DontCareConstraint = -1
|
41
43
|
NoMatchConstraint = -2
|
42
44
|
|
45
|
+
# from dep_selector_to_gecode_interface.h
|
46
|
+
SolutionStateUnstarted = 1
|
47
|
+
SolutionStateFinalized = 2
|
48
|
+
SolutionStateSolved = 3
|
49
|
+
SolutionStateTimedOut = 4
|
50
|
+
SolutionStateOptimal = 5
|
51
|
+
|
43
52
|
# This insures that we properly deallocate the c++ class at the heart of dep_gecode.
|
44
53
|
# modeled after http://www.mikeperham.com/2010/02/24/the-trouble-with-ruby-finalizers/
|
45
|
-
def initialize(problem_or_package_count, debug=false)
|
54
|
+
def initialize(problem_or_package_count, logId, debug=false, timeout = 10000)
|
46
55
|
if (problem_or_package_count.is_a?(Numeric))
|
47
|
-
logId = SecureRandom.uuid
|
48
56
|
dump_statistics = DepSelector.dump_statistics || debug
|
57
|
+
@log_id = logId
|
49
58
|
@debug_logs_on = debug
|
50
|
-
@
|
59
|
+
@timeout = timeout
|
60
|
+
@gecode_problem = Dep_gecode.VersionProblemCreate(problem_or_package_count, dump_statistics, debug, logId, @timeout)
|
51
61
|
else
|
52
62
|
@gecode_problem = problem_or_package_count
|
53
63
|
end
|
@@ -155,11 +165,28 @@ module DepSelector
|
|
155
165
|
Dep_gecode.MarkPackagePreferredToBeAtLatest(gecode_problem, package_id, weight);
|
156
166
|
end
|
157
167
|
|
168
|
+
def set_timeout(timeout)
|
169
|
+
raise "Gecode internal failure (set_timeout)" if gecode_problem.nil?
|
170
|
+
Dep_gecode.SetTimeout(gecode_problem, timeout)
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_solution_state()
|
174
|
+
raise "Gecode internal failure (get_solution_state)" if gecode_problem.nil?
|
175
|
+
Dep_gecode.GetSolutionState(gecode_problem);
|
176
|
+
end
|
177
|
+
|
158
178
|
def solve()
|
159
179
|
raise "Gecode internal failure (solve)" if gecode_problem.nil?
|
160
|
-
|
180
|
+
|
181
|
+
solutionPtr = FFI::MemoryPointer.new :pointer
|
182
|
+
resultCode = Dep_gecode.Solve(gecode_problem, solutionPtr)
|
183
|
+
solutionRaw = solutionPtr.get_pointer(0)
|
184
|
+
|
185
|
+
solution = GecodeWrapper.new(solutionRaw, log_id, debug_logs_on, @timeout)
|
186
|
+
|
161
187
|
raise "Gecode internal failure (no solution found)" if (solution.nil?)
|
162
188
|
|
189
|
+
raise Exceptions::TimeBoundExceeded.new() if resultCode == SolutionStateTimedOut
|
163
190
|
raise Exceptions::NoSolutionFound.new(solution) if solution.package_disabled_count > 0
|
164
191
|
solution
|
165
192
|
end
|
data/lib/dep_selector/package.rb
CHANGED
@@ -37,7 +37,14 @@ module DepSelector
|
|
37
37
|
|
38
38
|
# Note: only invoke this method after all PackageVersions have been added
|
39
39
|
def densely_packed_versions
|
40
|
-
@densely_packed_versions
|
40
|
+
if @densely_packed_versions.nil?
|
41
|
+
@densely_packed_versions = DenselyPackedSet.new(versions.map{|pkg_version| pkg_version.version})
|
42
|
+
Debug.log.debug { "Package Versions for '#{@name}' :" }
|
43
|
+
versions.each do |v|
|
44
|
+
Debug.log.debug { " #{v.to_s(true)}" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@densely_packed_versions
|
41
48
|
end
|
42
49
|
|
43
50
|
# Given a version, this method returns the corresonding
|
@@ -91,7 +98,11 @@ module DepSelector
|
|
91
98
|
# invalid portion of the state space instead of naively limiting
|
92
99
|
# it for the purposes of having failure count heuristics?
|
93
100
|
max = densely_packed_versions.range.max || -1
|
94
|
-
@gecode_package_id
|
101
|
+
if @gecode_package_id.nil?
|
102
|
+
@gecode_package_id = dependency_graph.gecode_wrapper.add_package(-1, max, 0)
|
103
|
+
Debug.log.debug { "Adding Package '#{@name}' PackageId: #{@gecode_package_id}" }
|
104
|
+
end
|
105
|
+
@gecode_package_id
|
95
106
|
end
|
96
107
|
|
97
108
|
def generate_gecode_wrapper_constraints
|
@@ -67,11 +67,9 @@ module DepSelector
|
|
67
67
|
packages_to_include_in_solve = trim_unreachable_packages(dep_graph, solution_constraints)
|
68
68
|
|
69
69
|
begin
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
rescue Exceptions::NoSolutionFound
|
70
|
+
# first, try to solve the whole set of constraints
|
71
|
+
solve(dep_graph.clone, solution_constraints, valid_packages, packages_to_include_in_solve)
|
72
|
+
rescue Exceptions::NoSolutionFound, Exceptions::TimeBoundExceededNoSolution
|
75
73
|
# since we're here, solving the whole system failed, so add
|
76
74
|
# the solution_constraints one-by-one and try to solve in
|
77
75
|
# order to find the constraint that breaks the system in order
|
@@ -148,6 +146,7 @@ module DepSelector
|
|
148
146
|
process_soln_constraints(workspace, solution_constraints, valid_packages)
|
149
147
|
|
150
148
|
# solve and trim the solution down to only the
|
149
|
+
workspace.gecode_wrapper.set_timeout(@time_bound * 1000)
|
151
150
|
soln = workspace.gecode_wrapper.solve
|
152
151
|
trim_solution(solution_constraints, soln, workspace)
|
153
152
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dep_selector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Walters
|
@@ -9,76 +9,76 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-08-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ~>
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.9'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - ~>
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.9'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: dep-selector-libgecode
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - ~>
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '1.0'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - ~>
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '1.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - ~>
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '10.0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - ~>
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '10.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - ~>
|
60
|
+
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '2.14'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - ~>
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '2.14'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: solve
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - ~>
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0.8'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - ~>
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0.8'
|
84
84
|
description: Given packages, versions, and a dependency graph, find a valid assignment
|
@@ -90,13 +90,23 @@ extensions:
|
|
90
90
|
- ext/dep_gecode/extconf.rb
|
91
91
|
extra_rdoc_files: []
|
92
92
|
files:
|
93
|
+
- ext/dep_gecode/define_dummy_init.cxx
|
94
|
+
- ext/dep_gecode/dep_gecode-all.def
|
95
|
+
- ext/dep_gecode/dep_selector_swig.i
|
96
|
+
- ext/dep_gecode/dep_selector_to_gecode.cpp
|
97
|
+
- ext/dep_gecode/dep_selector_to_gecode.h
|
98
|
+
- ext/dep_gecode/dep_selector_to_gecode_interface.cpp
|
99
|
+
- ext/dep_gecode/dep_selector_to_gecode_interface.h
|
100
|
+
- ext/dep_gecode/extconf.rb
|
101
|
+
- lib/dep_selector.rb
|
102
|
+
- lib/dep_selector/debug.rb
|
93
103
|
- lib/dep_selector/densely_packed_set.rb
|
94
104
|
- lib/dep_selector/dep_gecode.rb
|
95
105
|
- lib/dep_selector/dep_selector_version.rb
|
96
106
|
- lib/dep_selector/dependency.rb
|
97
107
|
- lib/dep_selector/dependency_graph.rb
|
98
|
-
- lib/dep_selector/error_reporter/simple_tree_traverser.rb
|
99
108
|
- lib/dep_selector/error_reporter.rb
|
109
|
+
- lib/dep_selector/error_reporter/simple_tree_traverser.rb
|
100
110
|
- lib/dep_selector/exceptions.rb
|
101
111
|
- lib/dep_selector/gecode_wrapper.rb
|
102
112
|
- lib/dep_selector/package.rb
|
@@ -105,15 +115,6 @@ files:
|
|
105
115
|
- lib/dep_selector/solution_constraint.rb
|
106
116
|
- lib/dep_selector/version.rb
|
107
117
|
- lib/dep_selector/version_constraint.rb
|
108
|
-
- lib/dep_selector.rb
|
109
|
-
- ext/dep_gecode/dep_selector_swig.i
|
110
|
-
- ext/dep_gecode/define_dummy_init.cxx
|
111
|
-
- ext/dep_gecode/dep_selector_to_gecode.h
|
112
|
-
- ext/dep_gecode/dep_selector_to_gecode_interface.h
|
113
|
-
- ext/dep_gecode/dep_selector_to_gecode.cpp
|
114
|
-
- ext/dep_gecode/dep_selector_to_gecode_interface.cpp
|
115
|
-
- ext/dep_gecode/extconf.rb
|
116
|
-
- ext/dep_gecode/dep_gecode-all.def
|
117
118
|
homepage: http://github.com/opscode/dep-selector
|
118
119
|
licenses:
|
119
120
|
- Apache v2
|
@@ -124,19 +125,19 @@ require_paths:
|
|
124
125
|
- lib
|
125
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
127
|
requirements:
|
127
|
-
- -
|
128
|
+
- - ">="
|
128
129
|
- !ruby/object:Gem::Version
|
129
|
-
version: 1.
|
130
|
+
version: 2.1.0
|
130
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
132
|
requirements:
|
132
|
-
- -
|
133
|
+
- - ">="
|
133
134
|
- !ruby/object:Gem::Version
|
134
135
|
version: '0'
|
135
136
|
requirements:
|
136
137
|
- gecode, version 3.5 or greater
|
137
138
|
- g++
|
138
139
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.
|
140
|
+
rubygems_version: 2.6.4
|
140
141
|
signing_key:
|
141
142
|
specification_version: 4
|
142
143
|
summary: Given packages, versions, and a dependency graph, find a valid assignment
|