From 498125adbe76475341bd7094cf233c8b4e52778b Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 7 Jun 2011 22:43:26 +0200 Subject: [PATCH] Assertions are now properly decided before running the main solver. Updating does not work yet. The test case works fine for installing/removing the correct packages however. Weak (update/feature) rules are entirely ignored so far. Watches are on literal ids rather than literals to save on function calls and memory usage. So a few methods for literals now have an id counter part. This should probably be refactored to have the literal versions call the id ones instead. --- src/Composer/DependencyResolver/Literal.php | 4 +- src/Composer/DependencyResolver/Pool.php | 11 + src/Composer/DependencyResolver/Rule.php | 6 +- src/Composer/DependencyResolver/Solver.php | 820 ++---------------- .../Test/DependencyResolver/SolverTest.php | 18 +- 5 files changed, 78 insertions(+), 781 deletions(-) diff --git a/src/Composer/DependencyResolver/Literal.php b/src/Composer/DependencyResolver/Literal.php index acbadec8c..39f0e4cc5 100644 --- a/src/Composer/DependencyResolver/Literal.php +++ b/src/Composer/DependencyResolver/Literal.php @@ -39,12 +39,12 @@ class Literal public function getPackageId() { - return spl_object_hash($this->package); + return $this->package->getId(); } public function getId() { - return ($this->wanted ? '' : '-') . spl_object_hash($this->package); + return ($this->wanted ? '' : '-') . $this->package->getId(); } public function __toString() diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index d6bcb0404..2cee0a1b9 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -45,6 +45,17 @@ class Pool } } + /** + * Retrieves the package object for a given package id. + * + * @param int $id + * @return PackageInterface + */ + public function packageById($id) + { + return $this->packages[$id]; + } + /** * Searches all packages providing the given package name and match the constraint * diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php index 9b7ae6fa2..6dd5b7160 100644 --- a/src/Composer/DependencyResolver/Rule.php +++ b/src/Composer/DependencyResolver/Rule.php @@ -109,7 +109,7 @@ class Rule public function getNext(Literal $literal) { - if ($this->watch1->equals($literal)) { + if ($this->watch1 == $literal->getId()) { return $this->next1; } else { return $this->next2; @@ -118,7 +118,7 @@ class Rule public function getOtherWatch(Literal $literal) { - if ($this->watch1->equals($literal)) { + if ($this->watch1 == $literal->getId()) { return $this->watch2; } else { return $this->watch1; @@ -132,7 +132,7 @@ class Rule */ public function __toString() { - $result = '('; + $result = ($this->isDisabled()) ? 'disabled(' : '('; foreach ($this->literals as $i => $literal) { if ($i != 0) { diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 60627e72a..0bba115e1 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -368,14 +368,14 @@ class Solver } if (!isset($this->watches[$rule->watch1])) { - $this->watches[$rule->watch1] = 0; + $this->watches[$rule->watch1] = null; } $rule->next1 = $this->watches[$rule->watch1]; $this->watches[$rule->watch1] = $rule; if (!isset($this->watches[$rule->watch2])) { - $this->watches[$rule->watch2] = 0; + $this->watches[$rule->watch2] = null; } $rule->next2 = $this->watches[$rule->watch2]; @@ -413,7 +413,10 @@ class Solver $literal = $literals[0]; if (!$this->decided($literal->getPackage())) { - + $this->decisionQueue[] = $literal; + $this->decisionQueueWhy[] = $rule; + $this->addDecision($literal, 1); + continue; } if ($this->decisionsSatisfy($literal)) { @@ -611,6 +614,12 @@ class Solver protected $decisionMap = array(); protected $branches = array(); + protected function literalFromId($id) + { + $package = $this->pool->packageById($id); + return new Literal($package, $id > 0); + } + protected function addDecision(Literal $l, $level) { if ($l->isWanted()) { @@ -620,6 +629,16 @@ class Solver } } + protected function addDecisionId($literalId, $level) + { + $packageId = abs($literalId); + if ($literalId > 0) { + $this->decisionMap[$packageId] = $level; + } else { + $this->decisionMap[$packageId] = -$level; + } + } + protected function decisionsContain(Literal $l) { return (isset($this->decisionMap[$l->getPackageId()]) && ( @@ -628,6 +647,15 @@ class Solver )); } + protected function decisionsContainId($literalId) + { + $packageId = abs($literalId); + return (isset($this->decisionMap[$packageId]) && ( + $this->decisionMap[$packageId] > 0 && $literalId > 0 || + $this->decisionMap[$packageId] < 0 && $literalId < 0 + )); + } + protected function decisionsSatisfy(Literal $l) { return ($l->isWanted() && isset($this->decisionMap[$l->getPackageId()]) && $this->decisionMap[$l->getPackageId()] > 0) || @@ -642,6 +670,15 @@ class Solver )); } + protected function decisionsConflictId($literalId) + { + $packageId = abs($literalId); + return (isset($this->decisionMap[$packageId]) && ( + $this->decisionMap[$packageId] > 0 && !$literalId < 0 || + $this->decisionMap[$packageId] < 0 && $literalId > 0 + )); + } + protected function decided(PackageInterface $p) { return isset($this->decisionMap[$p->getId()]); @@ -690,7 +727,7 @@ class Solver $otherWatch = $rule->getOtherWatch($literal); - if ($this->decisionsContain($otherWatch)) { + if ($this->decisionsContainId($otherWatch)) { continue; } @@ -717,13 +754,13 @@ class Solver } // yay, we found a unit clause! try setting it to true - if ($this->decisionsConflict($otherWatch)) { + if ($this->decisionsConflictId($otherWatch)) { return $rule; } - $this->addDecision($otherWatch, $level); + $this->addDecisionId($otherWatch, $level); - $this->decisionQueue[] = $otherWatch; + $this->decisionQueue[] = $this->literalFromId($otherWatch); $this->decisionQueueWhy[] = $rule; } } @@ -753,6 +790,11 @@ class Solver return $this->setPropagateLearn($level, $literals[0], $disableRules, $rule); } + private function analyzeUnsolvable($conflictRule, $disableRules) + { + return false; + } + private function runSat($disableRules = true, $installRecommended = false) { $this->propagateIndex = 0; @@ -868,7 +910,8 @@ class Solver } // only process updates in first pass - if (0 === $pass && !isset($this->updateMap[$literal->getPackageId()])) { + /** TODO: && or || ? **/ + if (0 === $pass || !isset($this->updateMap[$literal->getPackageId()])) { continue; } @@ -980,7 +1023,7 @@ class Solver } } } -$this->printRules(); + // // /* // * decide @@ -1074,761 +1117,4 @@ $this->printRules(); // } } - -// void -// solver_run_sat(Solver *solv, int disablerules, int doweak) -// { -// Queue dq; /* local decisionqueue */ -// Queue dqs; /* local decisionqueue for supplements */ -// int systemlevel; -// int level, olevel; -// Rule *r; -// int i, j, n; -// Solvable *s; -// Pool *pool = solv->pool; -// Id p, *dp; -// int minimizationsteps; -// int installedpos = solv->installed ? solv->installed->start : 0; -// -// IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION) -// { -// POOL_DEBUG (SAT_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules); -// for (i = 1; i < solv->nrules; i++) -// solver_printruleclass(solv, SAT_DEBUG_RULE_CREATION, solv->rules + i); -// } -// -// POOL_DEBUG(SAT_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count); -// -// IF_POOLDEBUG (SAT_DEBUG_SCHUBI) -// solver_printdecisions(solv); -// -// /* start SAT algorithm */ -// level = 1; -// systemlevel = level + 1; -// POOL_DEBUG(SAT_DEBUG_SOLVER, "solving...\n"); -// -// queue_init(&dq); -// queue_init(&dqs); -// -// /* -// * here's the main loop: -// * 1) propagate new decisions (only needed once) -// * 2) fulfill jobs -// * 3) try to keep installed packages -// * 4) fulfill all unresolved rules -// * 5) install recommended packages -// * 6) minimalize solution if we had choices -// * if we encounter a problem, we rewind to a safe level and restart -// * with step 1 -// */ -// -// minimizationsteps = 0; -// for (;;) -// { -// /* -// * initial propagation of the assertions -// */ -// if (level == 1) -// { -// POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagating (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count); -// if ((r = propagate(solv, level)) != 0) -// { -// if (analyze_unsolvable(solv, r, disablerules)) -// continue; -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// } -// -// /* -// * resolve jobs first -// */ -// if (level < systemlevel) -// { -// POOL_DEBUG(SAT_DEBUG_SOLVER, "resolving job rules\n"); -// for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) -// { -// Id l; -// if (r->d < 0) /* ignore disabled rules */ -// continue; -// queue_empty(&dq); -// FOR_RULELITERALS(l, dp, r) -// { -// if (l < 0) -// { -// if (solv->decisionmap[-l] <= 0) -// break; -// } -// else -// { -// if (solv->decisionmap[l] > 0) -// break; -// if (solv->decisionmap[l] == 0) -// queue_push(&dq, l); -// } -// } -// if (l || !dq.count) -// continue; -// /* prune to installed if not updating */ -// if (dq.count > 1 && solv->installed && !solv->updatemap_all) -// { -// int j, k; -// for (j = k = 0; j < dq.count; j++) -// { -// Solvable *s = pool->solvables + dq.elements[j]; -// if (s->repo == solv->installed) -// { -// dq.elements[k++] = dq.elements[j]; -// if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start)) -// { -// k = 0; /* package wants to be updated, do not prune */ -// break; -// } -// } -// } -// if (k) -// dq.count = k; -// } -// olevel = level; -// level = selectandinstall(solv, level, &dq, disablerules, i); -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// if (level <= olevel) -// break; -// } -// systemlevel = level + 1; -// if (i < solv->jobrules_end) -// continue; -// } -// -// -// /* -// * installed packages -// */ -// if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) -// { -// Repo *installed = solv->installed; -// int pass; -// -// POOL_DEBUG(SAT_DEBUG_SOLVER, "resolving installed packages\n"); -// /* we use two passes if we need to update packages -// * to create a better user experience */ -// for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) -// { -// int passlevel = level; -// /* start with installedpos, the position that gave us problems last time */ -// for (i = installedpos, n = installed->start; n < installed->end; i++, n++) -// { -// Rule *rr; -// Id d; -// -// if (i == installed->end) -// i = installed->start; -// s = pool->solvables + i; -// if (s->repo != installed) -// continue; -// -// if (solv->decisionmap[i] > 0) -// continue; -// if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) -// continue; /* updates first */ -// r = solv->rules + solv->updaterules + (i - installed->start); -// rr = r; -// if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ -// rr -= solv->installed->end - solv->installed->start; -// if (!rr->p) /* identical to update rule? */ -// rr = r; -// if (!rr->p) -// continue; /* orpaned package */ -// -// /* XXX: noupdate check is probably no longer needed, as all jobs should -// * already be satisfied */ -// /* Actually we currently still need it because of erase jobs */ -// /* if noupdate is set we do not look at update candidates */ -// queue_empty(&dq); -// if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)) -// { -// if (solv->noobsoletes.size && solv->multiversionupdaters -// && (d = solv->multiversionupdaters[i - installed->start]) != 0) -// { -// /* special multiversion handling, make sure best version is chosen */ -// queue_push(&dq, i); -// while ((p = pool->whatprovidesdata[d++]) != 0) -// if (solv->decisionmap[p] >= 0) -// queue_push(&dq, p); -// policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); -// p = dq.elements[0]; -// if (p != i && solv->decisionmap[p] == 0) -// { -// rr = solv->rules + solv->featurerules + (i - solv->installed->start); -// if (!rr->p) /* update rule == feature rule? */ -// rr = rr - solv->featurerules + solv->updaterules; -// dq.count = 1; -// } -// else -// dq.count = 0; -// } -// else -// { -// /* update to best package */ -// FOR_RULELITERALS(p, dp, rr) -// { -// if (solv->decisionmap[p] > 0) -// { -// dq.count = 0; /* already fulfilled */ -// break; -// } -// if (!solv->decisionmap[p]) -// queue_push(&dq, p); -// } -// } -// } -// /* install best version */ -// if (dq.count) -// { -// olevel = level; -// level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// if (level <= olevel) -// { -// if (level == 1 || level < passlevel) -// break; /* trouble */ -// if (level < olevel) -// n = installed->start; /* redo all */ -// i--; -// n--; -// continue; -// } -// } -// /* if still undecided keep package */ -// if (solv->decisionmap[i] == 0) -// { -// olevel = level; -// if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) -// { -// POOL_DEBUG(SAT_DEBUG_POLICY, "cleandeps erasing %s\n", solvid2str(pool, i)); -// level = setpropagatelearn(solv, level, -i, disablerules, 0); -// } -// else -// { -// POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i)); -// level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); -// } -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// if (level <= olevel) -// { -// if (level == 1 || level < passlevel) -// break; /* trouble */ -// if (level < olevel) -// n = installed->start; /* redo all */ -// i--; -// n--; -// continue; /* retry with learnt rule */ -// } -// } -// } -// if (n < installed->end) -// { -// installedpos = i; /* retry problem solvable next time */ -// break; /* ran into trouble */ -// } -// installedpos = installed->start; /* reset installedpos */ -// } -// systemlevel = level + 1; -// if (pass < 2) -// continue; /* had trouble, retry */ -// } -// -// if (level < systemlevel) -// systemlevel = level; -// -// /* -// * decide -// */ -// POOL_DEBUG(SAT_DEBUG_POLICY, "deciding unresolved rules\n"); -// for (i = 1, n = 1; n < solv->nrules; i++, n++) -// { -// if (i == solv->nrules) -// i = 1; -// r = solv->rules + i; -// if (r->d < 0) /* ignore disabled rules */ -// continue; -// queue_empty(&dq); -// if (r->d == 0) -// { -// /* binary or unary rule */ -// /* need two positive undecided literals */ -// if (r->p < 0 || r->w2 <= 0) -// continue; -// if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) -// continue; -// queue_push(&dq, r->p); -// queue_push(&dq, r->w2); -// } -// else -// { -// /* make sure that -// * all negative literals are installed -// * no positive literal is installed -// * i.e. the rule is not fulfilled and we -// * just need to decide on the positive literals -// */ -// if (r->p < 0) -// { -// if (solv->decisionmap[-r->p] <= 0) -// continue; -// } -// else -// { -// if (solv->decisionmap[r->p] > 0) -// continue; -// if (solv->decisionmap[r->p] == 0) -// queue_push(&dq, r->p); -// } -// dp = pool->whatprovidesdata + r->d; -// while ((p = *dp++) != 0) -// { -// if (p < 0) -// { -// if (solv->decisionmap[-p] <= 0) -// break; -// } -// else -// { -// if (solv->decisionmap[p] > 0) -// break; -// if (solv->decisionmap[p] == 0) -// queue_push(&dq, p); -// } -// } -// if (p) -// continue; -// } -// IF_POOLDEBUG (SAT_DEBUG_PROPAGATE) -// { -// POOL_DEBUG(SAT_DEBUG_PROPAGATE, "unfulfilled "); -// solver_printruleclass(solv, SAT_DEBUG_PROPAGATE, r); -// } -// /* dq.count < 2 cannot happen as this means that -// * the rule is unit */ -// assert(dq.count > 1); -// -// olevel = level; -// level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// if (level < systemlevel || level == 1) -// break; /* trouble */ -// /* something changed, so look at all rules again */ -// n = 0; -// } -// -// if (n != solv->nrules) /* ran into trouble, restart */ -// continue; -// -// /* at this point we have a consistent system. now do the extras... */ -// -// if (doweak) -// { -// int qcount; -// -// POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended packages\n"); -// queue_empty(&dq); /* recommended packages */ -// queue_empty(&dqs); /* supplemented packages */ -// for (i = 1; i < pool->nsolvables; i++) -// { -// if (solv->decisionmap[i] < 0) -// continue; -// if (solv->decisionmap[i] > 0) -// { -// /* installed, check for recommends */ -// Id *recp, rec, pp, p; -// s = pool->solvables + i; -// if (solv->ignorealreadyrecommended && s->repo == solv->installed) -// continue; -// /* XXX need to special case AND ? */ -// if (s->recommends) -// { -// recp = s->repo->idarraydata + s->recommends; -// while ((rec = *recp++) != 0) -// { -// qcount = dq.count; -// FOR_PROVIDES(p, pp, rec) -// { -// if (solv->decisionmap[p] > 0) -// { -// dq.count = qcount; -// break; -// } -// else if (solv->decisionmap[p] == 0) -// { -// queue_pushunique(&dq, p); -// } -// } -// } -// } -// } -// else -// { -// s = pool->solvables + i; -// if (!s->supplements) -// continue; -// if (!pool_installable(pool, s)) -// continue; -// if (!solver_is_supplementing(solv, s)) -// continue; -// queue_push(&dqs, i); -// } -// } -// -// /* filter out all packages obsoleted by installed packages */ -// /* this is no longer needed if we have reverse obsoletes */ -// if ((dqs.count || dq.count) && solv->installed) -// { -// Map obsmap; -// Id obs, *obsp, po, ppo; -// -// map_init(&obsmap, pool->nsolvables); -// for (p = solv->installed->start; p < solv->installed->end; p++) -// { -// s = pool->solvables + p; -// if (s->repo != solv->installed || !s->obsoletes) -// continue; -// if (solv->decisionmap[p] <= 0) -// continue; -// if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p)) -// continue; -// obsp = s->repo->idarraydata + s->obsoletes; -// /* foreach obsoletes */ -// while ((obs = *obsp++) != 0) -// FOR_PROVIDES(po, ppo, obs) -// MAPSET(&obsmap, po); -// } -// for (i = j = 0; i < dqs.count; i++) -// if (!MAPTST(&obsmap, dqs.elements[i])) -// dqs.elements[j++] = dqs.elements[i]; -// dqs.count = j; -// for (i = j = 0; i < dq.count; i++) -// if (!MAPTST(&obsmap, dq.elements[i])) -// dq.elements[j++] = dq.elements[i]; -// dq.count = j; -// map_free(&obsmap); -// } -// -// /* filter out all already supplemented packages if requested */ -// if (solv->ignorealreadyrecommended && dqs.count) -// { -// /* turn off all new packages */ -// for (i = 0; i < solv->decisionq.count; i++) -// { -// p = solv->decisionq.elements[i]; -// if (p < 0) -// continue; -// s = pool->solvables + p; -// if (s->repo && s->repo != solv->installed) -// solv->decisionmap[p] = -solv->decisionmap[p]; -// } -// /* filter out old supplements */ -// for (i = j = 0; i < dqs.count; i++) -// { -// p = dqs.elements[i]; -// s = pool->solvables + p; -// if (!s->supplements) -// continue; -// if (!solver_is_supplementing(solv, s)) -// dqs.elements[j++] = p; -// } -// dqs.count = j; -// /* undo turning off */ -// for (i = 0; i < solv->decisionq.count; i++) -// { -// p = solv->decisionq.elements[i]; -// if (p < 0) -// continue; -// s = pool->solvables + p; -// if (s->repo && s->repo != solv->installed) -// solv->decisionmap[p] = -solv->decisionmap[p]; -// } -// } -// -// /* multiversion doesn't mix well with supplements. -// * filter supplemented packages where we already decided -// * to install a different version (see bnc#501088) */ -// if (dqs.count && solv->noobsoletes.size) -// { -// for (i = j = 0; i < dqs.count; i++) -// { -// p = dqs.elements[i]; -// if (MAPTST(&solv->noobsoletes, p)) -// { -// Id p2, pp2; -// s = pool->solvables + p; -// FOR_PROVIDES(p2, pp2, s->name) -// if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) -// break; -// if (p2) -// continue; /* ignore this package */ -// } -// dqs.elements[j++] = p; -// } -// dqs.count = j; -// } -// -// /* make dq contain both recommended and supplemented pkgs */ -// if (dqs.count) -// { -// for (i = 0; i < dqs.count; i++) -// queue_pushunique(&dq, dqs.elements[i]); -// } -// -// if (dq.count) -// { -// Map dqmap; -// int decisioncount = solv->decisionq.count; -// -// if (dq.count == 1) -// { -// /* simple case, just one package. no need to choose */ -// p = dq.elements[0]; -// if (dqs.count) -// POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p)); -// else -// POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p)); -// queue_push(&solv->recommendations, p); -// level = setpropagatelearn(solv, level, p, 0, 0); -// continue; /* back to main loop */ -// } -// -// /* filter packages, this gives us the best versions */ -// policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND); -// -// /* create map of result */ -// map_init(&dqmap, pool->nsolvables); -// for (i = 0; i < dq.count; i++) -// MAPSET(&dqmap, dq.elements[i]); -// -// /* install all supplemented packages */ -// for (i = 0; i < dqs.count; i++) -// { -// p = dqs.elements[i]; -// if (solv->decisionmap[p] || !MAPTST(&dqmap, p)) -// continue; -// POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p)); -// queue_push(&solv->recommendations, p); -// olevel = level; -// level = setpropagatelearn(solv, level, p, 0, 0); -// if (level <= olevel) -// break; -// } -// if (i < dqs.count || solv->decisionq.count < decisioncount) -// { -// map_free(&dqmap); -// continue; -// } -// -// /* install all recommended packages */ -// /* more work as we want to created branches if multiple -// * choices are valid */ -// for (i = 0; i < decisioncount; i++) -// { -// Id rec, *recp, pp; -// p = solv->decisionq.elements[i]; -// if (p < 0) -// continue; -// s = pool->solvables + p; -// if (!s->repo || (solv->ignorealreadyrecommended && s->repo == solv->installed)) -// continue; -// if (!s->recommends) -// continue; -// recp = s->repo->idarraydata + s->recommends; -// while ((rec = *recp++) != 0) -// { -// queue_empty(&dq); -// FOR_PROVIDES(p, pp, rec) -// { -// if (solv->decisionmap[p] > 0) -// { -// dq.count = 0; -// break; -// } -// else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) -// queue_pushunique(&dq, p); -// } -// if (!dq.count) -// continue; -// if (dq.count > 1) -// { -// /* multiple candidates, open a branch */ -// for (i = 1; i < dq.count; i++) -// queue_push(&solv->branches, dq.elements[i]); -// queue_push(&solv->branches, -level); -// } -// p = dq.elements[0]; -// POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p)); -// queue_push(&solv->recommendations, p); -// olevel = level; -// level = setpropagatelearn(solv, level, p, 0, 0); -// if (level <= olevel || solv->decisionq.count < decisioncount) -// break; /* we had to revert some decisions */ -// } -// if (rec) -// break; /* had a problem above, quit loop */ -// } -// map_free(&dqmap); -// -// continue; /* back to main loop so that all deps are checked */ -// } -// } -// -// if (solv->dupmap_all && solv->installed) -// { -// int installedone = 0; -// -// /* let's see if we can install some unsupported package */ -// POOL_DEBUG(SAT_DEBUG_SOLVER, "deciding orphaned packages\n"); -// for (i = 0; i < solv->orphaned.count; i++) -// { -// p = solv->orphaned.elements[i]; -// if (solv->decisionmap[p]) -// continue; /* already decided */ -// olevel = level; -// if (solv->droporphanedmap_all) -// continue; -// if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) -// continue; -// POOL_DEBUG(SAT_DEBUG_SOLVER, "keeping orphaned %s\n", solvid2str(pool, p)); -// level = setpropagatelearn(solv, level, p, 0, 0); -// installedone = 1; -// if (level < olevel) -// break; -// } -// if (installedone || i < solv->orphaned.count) -// continue; /* back to main loop */ -// for (i = 0; i < solv->orphaned.count; i++) -// { -// p = solv->orphaned.elements[i]; -// if (solv->decisionmap[p]) -// continue; /* already decided */ -// POOL_DEBUG(SAT_DEBUG_SOLVER, "removing orphaned %s\n", solvid2str(pool, p)); -// olevel = level; -// level = setpropagatelearn(solv, level, -p, 0, 0); -// if (level < olevel) -// break; -// } -// if (i < solv->orphaned.count) -// continue; /* back to main loop */ -// } -// -// if (solv->solution_callback) -// { -// solv->solution_callback(solv, solv->solution_callback_data); -// if (solv->branches.count) -// { -// int i = solv->branches.count - 1; -// int l = -solv->branches.elements[i]; -// Id why; -// -// for (; i > 0; i--) -// if (solv->branches.elements[i - 1] < 0) -// break; -// p = solv->branches.elements[i]; -// POOL_DEBUG(SAT_DEBUG_SOLVER, "branching with %s\n", solvid2str(pool, p)); -// queue_empty(&dq); -// for (j = i + 1; j < solv->branches.count; j++) -// queue_push(&dq, solv->branches.elements[j]); -// solv->branches.count = i; -// level = l; -// revert(solv, level); -// if (dq.count > 1) -// for (j = 0; j < dq.count; j++) -// queue_push(&solv->branches, dq.elements[j]); -// olevel = level; -// why = -solv->decisionq_why.elements[solv->decisionq_why.count]; -// assert(why >= 0); -// level = setpropagatelearn(solv, level, p, disablerules, why); -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// continue; -// } -// /* all branches done, we're finally finished */ -// break; -// } -// -// /* minimization step */ -// if (solv->branches.count) -// { -// int l = 0, lasti = -1, lastl = -1; -// Id why; -// -// p = 0; -// for (i = solv->branches.count - 1; i >= 0; i--) -// { -// p = solv->branches.elements[i]; -// if (p < 0) -// l = -p; -// else if (p > 0 && solv->decisionmap[p] > l + 1) -// { -// lasti = i; -// lastl = l; -// } -// } -// if (lasti >= 0) -// { -// /* kill old solvable so that we do not loop */ -// p = solv->branches.elements[lasti]; -// solv->branches.elements[lasti] = 0; -// POOL_DEBUG(SAT_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvid2str(pool, p)); -// minimizationsteps++; -// -// level = lastl; -// revert(solv, level); -// why = -solv->decisionq_why.elements[solv->decisionq_why.count]; -// assert(why >= 0); -// olevel = level; -// level = setpropagatelearn(solv, level, p, disablerules, why); -// if (level == 0) -// { -// queue_free(&dq); -// queue_free(&dqs); -// return; -// } -// continue; /* back to main loop */ -// } -// } -// /* no minimization found, we're finally finished! */ -// break; -// } -// -// POOL_DEBUG(SAT_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps); -// -// POOL_DEBUG(SAT_DEBUG_STATS, "done solving.\n\n"); -// queue_free(&dq); -// queue_free(&dqs); -// #if 0 -// solver_printdecisionq(solv, SAT_DEBUG_RESULT); -// #endif -// } -} +} \ No newline at end of file diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index c1294b94f..3b43d092d 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -28,15 +28,15 @@ class SolverTest extends \PHPUnit_Framework_TestCase $pool = new Pool; $repoInstalled = new ArrayRepository; - $repoInstalled->addPackage(new MemoryPackage('old', '1.0')); + $repoInstalled->addPackage($oldPackage = new MemoryPackage('old', '1.0')); $repoInstalled->addPackage(new MemoryPackage('C', '1.0')); $repo = new ArrayRepository; $repo->addPackage($packageA = new MemoryPackage('A', '2.0')); $repo->addPackage($packageB = new MemoryPackage('B', '1.0')); $repo->addPackage($newPackageB = new MemoryPackage('B', '1.1')); - $repo->addPackage($packageC = new MemoryPackage('C', '1.0')); - $repo->addPackage($oldPackage = new MemoryPackage('old', '1.0')); + $repo->addPackage($packageC = new MemoryPackage('C', '1.1')); + $repo->addPackage(new MemoryPackage('old', '1.0')); $packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('<', '1.1'), 'requires'))); $pool->addRepository($repoInstalled); @@ -56,18 +56,18 @@ class SolverTest extends \PHPUnit_Framework_TestCase 'job' => 'install', 'package' => $packageA, ), + array( + 'job' => 'remove', + 'package' => $oldPackage, + ), array( 'job' => 'install', 'package' => $newPackageB, ), - array( +/* array( 'job' => 'update', 'package' => $packageC, - ), - array( - 'job' => 'remove', - 'package' => $oldPackage, - ), + ),*/ ); $this->assertEquals($expected, $result);