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