2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * SAT based dependency solver
26 #define RULES_BLOCK 63
30 solver_dep_installed(Solver *solv, Id dep)
32 /* disable for now, splitprovides don't work anyway and it breaks
35 Pool *pool = solv->pool;
40 Reldep *rd = GETRELDEP(pool, dep);
41 if (rd->flags == REL_AND)
43 if (!dep_installed(solv, rd->name))
45 return dep_installed(solv, rd->evr);
47 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
48 return dep_installed(solv, rd->evr);
50 FOR_PROVIDES(p, pp, dep)
52 if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables)
60 /* this mirrors solver_dep_fulfilled but uses map m instead of the decisionmap */
62 dep_possible(Solver *solv, Id dep, Map *m)
64 Pool *pool = solv->pool;
69 Reldep *rd = GETRELDEP(pool, dep);
70 if (rd->flags == REL_AND)
72 if (!dep_possible(solv, rd->name, m))
74 return dep_possible(solv, rd->evr, m);
76 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
77 return solver_dep_installed(solv, rd->evr);
79 FOR_PROVIDES(p, pp, dep)
87 /*-----------------------------------------------------------------*/
94 printruleelement(Solver *solv, Rule *r, Id v)
96 Pool *pool = solv->pool;
100 s = pool->solvables + -v;
101 printf(" !%s-%s.%s [%d]", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), -v);
105 s = pool->solvables + v;
106 printf(" %s-%s.%s [%d]", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), v);
115 if (solv->decisionmap[s - pool->solvables] > 0)
116 printf(" I.%d", solv->decisionmap[s - pool->solvables]);
117 if (solv->decisionmap[s - pool->solvables] < 0)
118 printf(" C.%d", -solv->decisionmap[s - pool->solvables]);
120 printf(" (disabled)");
130 printrule(Solver *solv, Rule *r)
135 if (r >= solv->rules && r < solv->rules + solv->nrules) /* r is a solver rule */
136 printf("Rule #%d:\n", (int)(r - solv->rules));
138 printf("Rule:\n"); /* r is any rule */
143 else if (r->d == ID_NULL)
150 v = solv->pool->whatprovidesdata[r->d + i - 1];
153 printruleelement(solv, r, v);
155 printf(" next: %d %d\n", r->n1, r->n2);
159 /*-----------------------------------------------------------------*/
165 static Pool *unifyrules_sortcmp_data;
168 * compare rules for unification sort
172 unifyrules_sortcmp(const void *ap, const void *bp)
174 Pool *pool = unifyrules_sortcmp_data;
175 Rule *a = (Rule *)ap;
176 Rule *b = (Rule *)bp;
182 return x; /* p differs */
185 if (a->d == 0 && b->d == 0)
186 return a->w2 - b->w2; /* assertion: return w2 diff */
188 if (a->d == 0) /* a is assertion, b not */
190 x = a->w2 - pool->whatprovidesdata[b->d];
194 if (b->d == 0) /* b is assertion, a not */
196 x = pool->whatprovidesdata[a->d] - b->w2;
200 /* compare whatprovidesdata */
201 ad = pool->whatprovidesdata + a->d;
202 bd = pool->whatprovidesdata + b->d;
204 if ((x = *ad++ - *bd++) != 0)
215 unifyrules(Solver *solv)
220 if (solv->nrules <= 1) /* nothing to unify */
223 /* sort rules first */
224 unifyrules_sortcmp_data = solv->pool;
225 qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
232 for (i = j = 1, ir = solv->rules + 1; i < solv->nrules; i++, ir++)
234 if (jr && !unifyrules_sortcmp(ir, jr))
235 continue; /* prune! */
236 jr = solv->rules + j++; /* keep! */
241 /* reduced count from nrules to j rules */
242 if (solv->pool->verbose) printf("pruned rules from %d to %d\n", solv->nrules, j);
244 /* adapt rule buffer */
245 solv->rules = (Rule *)xrealloc(solv->rules, ((solv->nrules + RULES_BLOCK) & ~RULES_BLOCK) * sizeof(Rule));
248 if (solv->pool->verbose)
255 for (i = 1; i < solv->nrules; i++)
262 dp = solv->pool->whatprovidesdata + r->d;
267 printf(" binary: %d\n", binr);
268 printf(" normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
280 hashrule(Solver *solv, Id p, Id d, int n)
282 unsigned int x = (unsigned int)p;
286 return (x * 37) ^ (unsigned int)d;
287 dp = solv->pool->whatprovidesdata + d;
289 x = (x * 37) ^ (unsigned int)*dp++;
297 * p = direct literal; > 0 for learnt, < 0 for installed pkg (rpm)
298 * d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
301 * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
303 * p < 0 : rule from rpm (installed pkg)
304 * d > 0 : Offset in whatprovidesdata (list of providers)
306 * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
307 * d < 0: Id of solvable (e.g. B1)
309 * d == 0: unary rule, assertion => (A) or (-A)
311 * Install: p > 0, d = 0 (A) user requested install
312 * Remove: p < 0, d = 0 (-A) user requested remove
313 * Requires: p < 0, d > 0 (-A|B1|B2|...) d: <list of providers for requirement of p>
314 * Updates: p > 0, d > 0 (A|B1|B2|...) d: <list of updates for solvable p>
315 * Conflicts: p < 0, d < 0 (-A|-B) either p (conflict issuer) or d (conflict provider)
316 * ? p > 0, d < 0 (A|-B)
317 * No-op ?: p = 0, d = 0 (null) (used as policy rule placeholder)
321 addrule(Solver *solv, Id p, Id d)
326 int n = 0; /* number of literals in rule - 1
327 0 = direct assertion (single literal)
331 /* it often happenes that requires lead to adding the same rpm rule
332 * multiple times, so we prune those duplicates right away to make
333 * the work for unifyrules a bit easier */
335 if (solv->nrules && !solv->jobrules)
337 r = solv->rules + solv->nrules - 1; /* get the last added rule */
338 if (r->p == p && r->d == d && d != 0) /* identical and not user requested */
345 return 0; /* ignore self conflict */
348 else if (d == 0) /* user requested */
352 for (dp = solv->pool->whatprovidesdata + d; *dp; dp++, n++)
354 return 0; /* rule is self-fulfilling */
359 if (n == 0) /* direct assertion */
363 /* this is a rpm rule assertion, we do not have to allocate it */
364 /* it can be identified by a level of 1 and a zero reason */
365 /* we must not drop those rules from the decisionq when rewinding! */
368 if (solv->decisionmap[-p] > 0 || solv->decisionmap[-p] < -1)
370 if (solv->decisionmap[-p])
372 queue_push(&solv->decisionq, p);
373 queue_push(&solv->decisionq_why, 0);
374 solv->decisionmap[-p] = -1;
378 else if (n == 1 && p > d)
380 /* smallest literal first so we can find dups */
384 n = 1; /* re-set n, was used as temp var */
387 /* check if the last added rule is exactly the same as what we're looking for. */
388 if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
391 if (r && n > 1 && r->d && r->p == p)
396 dp2 = solv->pool->whatprovidesdata + r->d;
397 for (dp = solv->pool->whatprovidesdata + d; *dp; dp++, dp2++)
408 /* check and extend rule buffer */
409 if ((solv->nrules & RULES_BLOCK) == 0)
411 solv->rules = (Rule *)xrealloc(solv->rules, (solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
414 r = solv->rules + solv->nrules++; /* point to rule space */
419 /* direct assertion, no watch needed */
435 r->w2 = solv->pool->whatprovidesdata[d];
443 disablerule(Solver *solv, Rule *r)
449 enablerule(Solver *solv, Rule *r)
451 if (r->d == 0 || r->w2 != r->p)
454 r->w1 = solv->pool->whatprovidesdata[r->d];
458 /**********************************************************************************/
460 /* a problem is an item on the solver's problem list. It can either be >0, in that
461 * case it is a system (upgrade) rule, or it can be <0, which makes it refer to a job
462 * consisting of multiple job rules.
466 disableproblem(Solver *solv, Id v)
474 disablerule(solv, solv->rules + v);
478 jp = solv->ruletojob.elements;
479 for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
481 disablerule(solv, r);
485 enableproblem(Solver *solv, Id v)
493 enablerule(solv, solv->rules + v);
497 jp = solv->ruletojob.elements;
498 for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
504 printproblem(Solver *solv, Id v)
511 printrule(solv, solv->rules + v);
515 printf("JOB %d\n", v);
516 jp = solv->ruletojob.elements;
517 for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
528 /**********************************************************************************/
530 /* go through system and job rules and add direct assertions
531 * to the decisionqueue. If we find a conflict, disable rules and
532 * add them to problem queue.
535 makeruledecisions(Solver *solv)
542 /* no learnt rules for now */
543 if (solv->learntrules && solv->learntrules != solv->nrules)
546 decisionstart = solv->decisionq.count;
547 /* the loop is over jobrules, system rules and weak rules */
548 for (ri = solv->jobrules, r = solv->rules + ri; ri < solv->nrules; ri++, r++)
554 if (solv->decisionmap[vv] == 0)
556 queue_push(&solv->decisionq, v);
557 queue_push(&solv->decisionq_why, r - solv->rules);
558 solv->decisionmap[vv] = v > 0 ? 1 : -1;
561 if (v > 0 && solv->decisionmap[vv] > 0)
563 if (v < 0 && solv->decisionmap[vv] < 0)
565 /* found a conflict! */
566 /* if we are weak, just disable ourself */
567 if (ri >= solv->weakrules)
569 printf("conflict, but I am weak, disabling ");
574 /* only job and system rules left */
575 for (i = 0; i < solv->decisionq.count; i++)
576 if (solv->decisionq.elements[i] == -v)
578 if (i == solv->decisionq.count)
580 if (solv->decisionq_why.elements[i] == 0)
582 /* conflict with rpm rule, need only disable our rule */
583 printf("conflict with rpm rule, disabling rule #%d\n", ri);
585 if (ri < solv->systemrules)
586 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
587 queue_push(&solv->problems, v);
588 disableproblem(solv, v);
589 queue_push(&solv->problems, 0);
592 /* conflict with another job or system rule */
593 /* remove old decision */
594 printf("conflicting system/job rules over literal %d\n", vv);
595 /* push all of our rules asserting this literal on the problem stack */
596 for (i = solv->jobrules, rr = solv->rules + i; i < solv->nrules; i++, rr++)
598 if (!rr->w1 || rr->w2)
600 if (rr->p != v && rr->p != -v)
602 printf(" - disabling rule #%d\n", i);
604 if (i < solv->systemrules)
605 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
606 queue_push(&solv->problems, v);
607 disableproblem(solv, v);
609 queue_push(&solv->problems, 0);
612 while (solv->decisionq.count > decisionstart)
614 v = solv->decisionq.elements[--solv->decisionq.count];
615 --solv->decisionq_why.count;
617 solv->decisionmap[vv] = 0;
619 ri = solv->jobrules - 1;
620 r = solv->rules + ri;
625 /* FIXME: bad code ahead, replace as soon as possible */
627 disableupdaterules(Solver *solv, Queue *job, int jobidx)
629 Pool *pool = solv->pool;
631 Id how, what, p, *pp;
637 installed = solv->installed;
643 how = job->elements[jobidx];
646 case SOLVER_INSTALL_SOLVABLE:
647 case SOLVER_ERASE_SOLVABLE:
648 case SOLVER_ERASE_SOLVABLE_NAME:
649 case SOLVER_ERASE_SOLVABLE_PROVIDES:
655 /* go through all enabled job rules */
656 MAPZERO(&solv->noupdate);
657 for (i = solv->jobrules; i < solv->systemrules; i++)
660 if (!r->w1) /* disabled? */
662 j = solv->ruletojob.elements[i - solv->jobrules];
666 how = job->elements[j];
667 what = job->elements[j + 1];
670 case SOLVER_INSTALL_SOLVABLE: /* install specific solvable */
671 s = pool->solvables + what;
672 FOR_PROVIDES(p, pp, s->name)
674 if (pool->solvables[p].name != s->name)
676 if (p >= installed->start && p < installed->start + installed->nsolvables)
677 MAPSET(&solv->noupdate, p - installed->start);
680 case SOLVER_ERASE_SOLVABLE:
681 if (what >= installed->start && what < installed->start + installed->nsolvables)
682 MAPSET(&solv->noupdate, what - installed->start);
684 case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */
685 case SOLVER_ERASE_SOLVABLE_PROVIDES:
686 FOR_PROVIDES(p, pp, what)
688 if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
690 if (p >= installed->start && p < installed->start + installed->nsolvables)
691 MAPSET(&solv->noupdate, p - installed->start);
699 /* fixup update rule status */
700 if (solv->allowuninstall)
701 return; /* no update rules at all */
705 /* re just disabled job #jobidx. enable all update rules
706 * that aren't disabled by the remaining job rules */
707 how = job->elements[jobidx];
708 what = job->elements[jobidx + 1];
711 case SOLVER_INSTALL_SOLVABLE:
712 s = pool->solvables + what;
713 FOR_PROVIDES(p, pp, s->name)
715 if (pool->solvables[p].name != s->name)
717 if (p < installed->start || p >= installed->start + installed->nsolvables)
719 if (MAPTST(&solv->noupdate, p - installed->start))
721 r = solv->rules + solv->systemrules + (p - installed->start);
724 if (r->d == 0 || r->w2 != r->p)
727 r->w1 = solv->pool->whatprovidesdata[r->d];
730 printf("@@@ re-enabling ");
735 case SOLVER_ERASE_SOLVABLE:
736 if (what < installed->start || what >= installed->start + installed->nsolvables)
738 if (MAPTST(&solv->noupdate, what - installed->start))
740 r = solv->rules + solv->systemrules + (what - installed->start);
743 if (r->d == 0 || r->w2 != r->p)
746 r->w1 = solv->pool->whatprovidesdata[r->d];
749 printf("@@@ re-enabling ");
753 case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */
754 case SOLVER_ERASE_SOLVABLE_PROVIDES:
755 FOR_PROVIDES(p, pp, what)
757 if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
759 if (p < installed->start || p >= installed->start + installed->nsolvables)
761 if (MAPTST(&solv->noupdate, p - installed->start))
763 r = solv->rules + solv->systemrules + (p - installed->start);
766 if (r->d == 0 || r->w2 != r->p)
769 r->w1 = solv->pool->whatprovidesdata[r->d];
772 printf("@@@ re-enabling ");
783 for (i = 0; i < installed->nsolvables; i++)
785 r = solv->rules + solv->systemrules + i;
786 if (r->w1 && MAPTST(&solv->noupdate, i))
787 r->w1 = 0; /* was enabled, need to disable */
793 * add (install) rules for solvable
798 addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
800 Pool *pool = solv->pool;
801 Repo *installed = solv->installed;
815 queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
816 queue_push(&q, s - pool->solvables); /* push solvable Id */
822 * s: Pointer to solvable
826 if (MAPTST(m, n)) /* continue if already done */
830 s = pool->solvables + n; /* s = Solvable in question */
835 && n >= installed->start /* is it installed? */
836 && n < installed->start + installed->nsolvables)
838 dontfix = 1; /* dont care about broken rpm deps */
841 /*-----------------------------------------
842 * check requires of s
847 reqp = s->repo->idarraydata + s->requires;
848 while ((req = *reqp++) != 0)
850 if (req == SOLVABLE_PREREQMARKER) /* skip the marker */
853 dp = GET_PROVIDESP(req, p); /* get providers of req */
855 if (*dp == SYSTEMSOLVABLE) /* always installed */
860 /* the strategy here is to not insist on dependencies
861 * that are already broken. so if we find one provider
862 * that was already installed, we know that the
863 * dependency was not broken before so we enforce it */
864 for (i = 0; dp[i]; i++) /* for all providers */
866 if (dp[i] >= installed->start && dp[i] < installed->start + installed->nsolvables)
867 break; /* provider was installed */
869 if (!dp[i]) /* previously broken dependency */
872 printf("ignoring broken requires %s of installed package %s-%s.%s\n", dep2str(pool, req), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
879 /* nothing provides req! */
881 printf("package %s-%s.%s [%ld] is not installable (%s)\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), (long int)(s - pool->solvables), dep2str(pool, req));
882 addrule(solv, -n, 0); /* mark requestor as uninstallable */
884 printf(">!> !unflag %s-%s.%s[%s]\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), repo_name(s->repo));
889 printf("addrule %s-%s.%s %s %d %d\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), dep2str(pool, req), -n, dp - pool->whatprovidesdata);
890 for (i = 0; dp[i]; i++)
891 printf(" %s-%s.%s\n", id2str(pool, pool->solvables[dp[i]].name), id2str(pool, pool->solvables[dp[i]].evr), id2str(pool, pool->solvables[dp[i]].arch));
893 /* add 'requires' dependency */
894 /* rule: (-requestor|provider1|provider2|...|providerN) */
895 addrule(solv, -n, dp - pool->whatprovidesdata);
897 /* descend the dependency tree */
898 for (; *dp; dp++) /* loop through all providers */
904 } /* while, requirements of n */
906 } /* if, requirements */
909 /*-----------------------------------------
910 * check conflicts of s
915 conp = s->repo->idarraydata + s->conflicts;
916 while ((con = *conp++) != 0)
918 FOR_PROVIDES(p, pp, con)
920 /* dontfix: dont care about conflicts with already installed packs */
921 if (dontfix && p >= installed->start && p < installed->start + installed->nsolvables)
923 /* rule: -n|-p: either solvable _or_ provider of conflict */
924 addrule(solv, -n, -p);
929 /*-----------------------------------------
930 * check obsoletes if not installed
932 if (!installed || n < installed->start || n >= (installed->start + installed->nsolvables))
933 { /* not installed */
936 obsp = s->repo->idarraydata + s->obsoletes;
937 while ((obs = *obsp++) != 0)
939 FOR_PROVIDES(p, pp, obs)
940 addrule(solv, -n, -p);
943 FOR_PROVIDES(p, pp, s->name)
945 if (s->name == pool->solvables[p].name)
946 addrule(solv, -n, -p);
950 /*-----------------------------------------
951 * add recommends to the rule list
955 recp = s->repo->idarraydata + s->recommends;
956 while ((rec = *recp++) != 0)
958 FOR_PROVIDES(p, pp, rec)
965 sugp = s->repo->idarraydata + s->suggests;
966 while ((sug = *sugp++) != 0)
968 FOR_PROVIDES(p, pp, sug)
978 addrpmrulesforweak(Solver *solv, Map *m)
980 Pool *pool = solv->pool;
985 if (pool->verbose) printf("addrpmrulesforweak... (%d)\n", solv->nrules);
986 for (i = n = 1; n < pool->nsolvables; i++, n++)
988 if (i == pool->nsolvables)
992 s = pool->solvables + i;
993 if (!pool_installable(pool, s))
998 supp = s->repo->idarraydata + s->supplements;
999 while ((sup = *supp++) != ID_NULL)
1000 if (dep_possible(solv, sup, m))
1003 if (!sup && s->freshens)
1005 supp = s->repo->idarraydata + s->freshens;
1006 while ((sup = *supp++) != ID_NULL)
1007 if (dep_possible(solv, sup, m))
1010 if (!sup && s->enhances)
1012 supp = s->repo->idarraydata + s->enhances;
1013 while ((sup = *supp++) != ID_NULL)
1014 if (dep_possible(solv, sup, m))
1019 addrpmrulesforsolvable(solv, s, m);
1022 if (pool->verbose) printf("done. (%d)\n", solv->nrules);
1026 addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allowall)
1028 Pool *pool = solv->pool;
1033 if (!MAPTST(m, s - pool->solvables)) /* add rule for s if not already done */
1034 addrpmrulesforsolvable(solv, s, m);
1035 queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1036 policy_findupdatepackages(solv, s, &qs, allowall);
1037 for (i = 0; i < qs.count; i++)
1038 if (!MAPTST(m, qs.elements[i]))
1039 addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
1044 * add rule for update
1045 * (A|A1|A2|A3...) An = update candidates for A
1047 * s = (installed) solvable
1051 addupdaterule(Solver *solv, Solvable *s, int allowall)
1053 /* installed packages get a special upgrade allowed rule */
1054 Pool *pool = solv->pool;
1059 queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1060 policy_findupdatepackages(solv, s, &qs, allowall);
1061 if (qs.count == 0) /* no updaters found */
1064 d = pool_queuetowhatprovides(pool, &qs); /* intern computed queue */
1066 addrule(solv, s - pool->solvables, d); /* allow update of s */
1070 /*-----------------------------------------------------------------*/
1077 * initial setup for all watches
1081 makewatches(Solver *solv)
1085 int nsolvables = solv->pool->nsolvables;
1087 xfree(solv->watches);
1088 /* lower half for removals, upper half for installs */
1089 solv->watches = (Id *)xcalloc(2 * nsolvables, sizeof(Id));
1091 /* do it reverse so rpm rules get triggered first */
1092 for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
1094 for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
1097 if (!r->w1 /* rule is disabled */
1098 || !r->w2) /* rule is assertion */
1101 /* see addwatches(solv, r) */
1102 r->n1 = solv->watches[nsolvables + r->w1];
1103 solv->watches[nsolvables + r->w1] = r - solv->rules;
1105 r->n2 = solv->watches[nsolvables + r->w2];
1106 solv->watches[nsolvables + r->w2] = r - solv->rules;
1112 * add watches (for rule)
1116 addwatches(Solver *solv, Rule *r)
1118 int nsolvables = solv->pool->nsolvables;
1120 r->n1 = solv->watches[nsolvables + r->w1];
1121 solv->watches[nsolvables + r->w1] = r - solv->rules;
1123 r->n2 = solv->watches[nsolvables + r->w2];
1124 solv->watches[nsolvables + r->w2] = r - solv->rules;
1128 /*-----------------------------------------------------------------*/
1129 /* rule propagation */
1131 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
1136 * propagate decision to all rules
1140 propagate(Solver *solv, int level)
1142 Pool *pool = solv->pool;
1147 Id *decisionmap = solv->decisionmap;
1148 Id *watches = solv->watches + pool->nsolvables;
1150 while (solv->propagate_index < solv->decisionq.count)
1152 /* negate because our watches trigger if literal goes FALSE */
1153 pkg = -solv->decisionq.elements[solv->propagate_index++];
1155 printf("popagate for decision %d level %d\n", -pkg, level);
1156 printruleelement(solv, 0, -pkg);
1158 for (rp = watches + pkg; *rp; rp = nrp)
1160 r = solv->rules + *rp;
1162 printf(" watch triggered ");
1175 /* if clause is TRUE, nothing to do */
1176 if (DECISIONMAP_TRUE(ow))
1181 /* not a binary clause, check if we need to move our watch */
1182 if (r->p && r->p != ow && !DECISIONMAP_TRUE(-r->p))
1185 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
1186 if (p != ow && !DECISIONMAP_TRUE(-p))
1190 /* p is free to watch, move watch to p */
1193 printf(" -> move w%d to %s-%s.%s\n", (pkg == r->w1 ? 1 : 2), id2str(pool, pool->solvables[p].name), id2str(pool, pool->solvables[p].evr), id2str(pool, pool->solvables[p].arch));
1195 printf(" -> move w%d to !%s-%s.%s\n", (pkg == r->w1 ? 1 : 2), id2str(pool, pool->solvables[-p].name), id2str(pool, pool->solvables[-p].evr), id2str(pool, pool->solvables[-p].arch));
1209 watches[p] = r - solv->rules;
1213 /* unit clause found, set other watch to TRUE */
1214 if (DECISIONMAP_TRUE(-ow))
1215 return r; /* eek, a conflict! */
1216 if (pool->verbose > 2)
1222 decisionmap[ow] = level;
1224 decisionmap[-ow] = -level;
1225 queue_push(&solv->decisionq, ow);
1226 queue_push(&solv->decisionq_why, r - solv->rules);
1229 Solvable *s = pool->solvables + (ow > 0 ? ow : -ow);
1231 printf(" -> decided to install %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
1233 printf(" -> decided to conflict %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
1238 return 0; /* all is well */
1242 /*-----------------------------------------------------------------*/
1251 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
1253 Pool *pool = solv->pool;
1256 Map seen; /* global? */
1260 int learnt_why = solv->learnt_pool.count;
1261 Id *decisionmap = solv->decisionmap;
1265 if (pool->verbose > 1) printf("ANALYZE at %d ----------------------\n", level);
1266 map_init(&seen, pool->nsolvables);
1267 idx = solv->decisionq.count;
1270 if (pool->verbose > 1) printrule(solv, c);
1271 queue_push(&solv->learnt_pool, c - solv->rules);
1272 dp = c->d ? pool->whatprovidesdata + c->d : 0;
1283 if (DECISIONMAP_TRUE(v)) /* the one true literal */
1285 vv = v > 0 ? v : -v;
1286 if (MAPTST(&seen, vv))
1288 l = solv->decisionmap[vv];
1295 for (j = 0; j < solv->decisionq.count; j++)
1296 if (solv->decisionq.elements[j] == v)
1298 if (j == solv->decisionq.count)
1300 queue_push(&rulq, -(j + 1));
1302 continue; /* initial setting */
1306 num++; /* need to do this one as well */
1311 printf("PUSH %d ", v);
1312 printruleelement(solv, 0, v);
1319 printf("num = %d\n", num);
1325 v = solv->decisionq.elements[--idx];
1326 vv = v > 0 ? v : -v;
1327 if (MAPTST(&seen, vv))
1330 c = solv->rules + solv->decisionq_why.elements[idx];
1338 else if (r.count == 1 && r.elements[0] < 0)
1339 *dr = r.elements[0];
1341 *dr = pool_queuetowhatprovides(pool, &r);
1342 if (pool->verbose > 1)
1344 printf("learned rule for level %d (am %d)\n", rlevel, level);
1345 printruleelement(solv, 0, -v);
1346 for (i = 0; i < r.count; i++)
1349 printruleelement(solv, 0, v);
1353 queue_push(&solv->learnt_pool, 0);
1355 for (i = learnt_why; solv->learnt_pool.elements[i]; i++)
1357 printf("learnt_why ");
1358 printrule(solv, solv->rules + solv->learnt_pool.elements[i]);
1369 * reset the solver decisions to right after the rpm rules.
1370 * called after rules have been enabled/disabled
1374 reset_solver(Solver *solv)
1379 /* delete all learnt rules */
1380 solv->nrules = solv->learntrules;
1381 queue_empty(&solv->learnt_why);
1382 queue_empty(&solv->learnt_pool);
1384 /* redo all direct rpm rule decisions */
1385 /* we break at the first decision with a why attached, this is
1386 * either a job/system rule assertion or a propagated decision */
1387 for (i = 0; i < solv->decisionq.count; i++)
1389 v = solv->decisionq.elements[i];
1390 solv->decisionmap[v > 0 ? v : -v] = 0;
1392 for (i = 0; i < solv->decisionq_why.count; i++)
1393 if (solv->decisionq_why.elements[i])
1397 v = solv->decisionq.elements[i];
1398 solv->decisionmap[v > 0 ? v : -v] = v > 0 ? 1 : -1;
1401 if (solv->pool->verbose > 1)
1402 printf("decisions done reduced from %d to %d\n", solv->decisionq.count, i);
1404 solv->decisionq_why.count = i;
1405 solv->decisionq.count = i;
1406 solv->recommends_index = -1;
1407 solv->propagate_index = 0;
1409 /* redo all job/system decisions */
1410 makeruledecisions(solv);
1411 if (solv->pool->verbose > 1)
1412 printf("decisions after adding job and system rules: %d\n", solv->decisionq.count);
1413 /* recreate watches */
1419 * analyze_unsolvable_rule
1423 analyze_unsolvable_rule(Solver *solv, Rule *r)
1426 Id why = r - solv->rules;
1427 if (solv->pool->verbose > 1)
1429 if (why >= solv->jobrules && why < solv->systemrules)
1431 if (why >= solv->systemrules && why < solv->weakrules)
1432 printf("SYSTEM %d ", why - solv->systemrules);
1433 if (why >= solv->weakrules && why < solv->learntrules)
1435 if (solv->learntrules && why >= solv->learntrules)
1439 if (solv->learntrules && why >= solv->learntrules)
1441 for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1442 analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i]);
1445 /* do not add rpm rules to problem */
1446 if (why < solv->jobrules)
1448 /* turn rule into problem */
1449 if (why >= solv->jobrules && why < solv->systemrules)
1450 why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1451 /* return if problem already countains our rule */
1452 if (solv->problems.count)
1454 for (i = solv->problems.count - 1; i >= 0; i--)
1455 if (solv->problems.elements[i] == 0)
1457 else if (solv->problems.elements[i] == why)
1460 queue_push(&solv->problems, why);
1465 * analyze_unsolvable
1467 * return: 1 - disabled some rules, try again
1472 analyze_unsolvable(Solver *solv, Rule *r, int disablerules)
1474 Pool *pool = solv->pool;
1475 Map seen; /* global? */
1478 Id *decisionmap = solv->decisionmap;
1479 int oldproblemcount;
1482 if (pool->verbose > 1)
1483 printf("ANALYZE UNSOLVABLE ----------------------\n");
1484 oldproblemcount = solv->problems.count;
1485 map_init(&seen, pool->nsolvables);
1486 analyze_unsolvable_rule(solv, r);
1487 dp = r->d ? pool->whatprovidesdata + r->d : 0;
1498 if (DECISIONMAP_TRUE(v)) /* the one true literal */
1500 vv = v > 0 ? v : -v;
1501 l = solv->decisionmap[vv];
1506 idx = solv->decisionq.count;
1509 v = solv->decisionq.elements[--idx];
1510 vv = v > 0 ? v : -v;
1511 if (!MAPTST(&seen, vv))
1513 why = solv->decisionq_why.elements[idx];
1518 printruleelement(solv, 0, v);
1522 r = solv->rules + why;
1523 analyze_unsolvable_rule(solv, r);
1524 dp = r->d ? pool->whatprovidesdata + r->d : 0;
1535 if (DECISIONMAP_TRUE(v)) /* the one true literal */
1537 vv = v > 0 ? v : -v;
1538 l = solv->decisionmap[vv];
1545 queue_push(&solv->problems, 0); /* mark end of this problem */
1548 if (solv->weakrules != solv->learntrules)
1550 for (i = oldproblemcount; i < solv->problems.count - 1; i++)
1552 why = solv->problems.elements[i];
1553 if (why < solv->weakrules || why >= solv->learntrules)
1555 if (!lastweak || lastweak < why)
1561 /* disable last weak rule */
1562 solv->problems.count = oldproblemcount;
1563 r = solv->rules + lastweak;
1564 printf("disabling weak ");
1570 else if (disablerules)
1572 for (i = oldproblemcount; i < solv->problems.count - 1; i++)
1573 disableproblem(solv, solv->problems.elements[i]);
1581 /*-----------------------------------------------------------------*/
1582 /* Decision revert */
1586 * revert decision at level
1590 revert(Solver *solv, int level)
1593 while (solv->decisionq.count)
1595 v = solv->decisionq.elements[solv->decisionq.count - 1];
1596 vv = v > 0 ? v : -v;
1597 if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1600 printf("reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1602 solv->decisionmap[vv] = 0;
1603 solv->decisionq.count--;
1604 solv->decisionq_why.count--;
1605 solv->propagate_index = solv->decisionq.count;
1607 while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1609 solv->branches.count--;
1610 while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1611 solv->branches.count--;
1613 solv->recommends_index = -1;
1618 * watch2onhighest - put watch2 on literal with highest level
1622 watch2onhighest(Solver *solv, Rule *r)
1628 return; /* binary rule, both watches are set */
1629 dp = solv->pool->whatprovidesdata + r->d;
1630 while ((v = *dp++) != 0)
1632 l = solv->decisionmap[v < 0 ? -v : v];
1647 * add free decision to decision q, increase level
1648 * propagate decision, return if no conflict.
1649 * in conflict case, analyze conflict rule, add resulting
1650 * rule to learnt rule set, make decision from learnt
1651 * rule (always unit) and re-propagate.
1655 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
1665 solv->decisionmap[decision] = level;
1667 solv->decisionmap[-decision] = -level;
1668 queue_push(&solv->decisionq, decision);
1669 queue_push(&solv->decisionq_why, 0);
1673 r = propagate(solv, level);
1677 return analyze_unsolvable(solv, r, disablerules);
1678 printf("conflict with rule #%d\n", (int)(r - solv->rules));
1679 l = analyze(solv, level, r, &p, &d, &why); /* learnt rule in p and d */
1680 if (l >= level || l <= 0)
1682 printf("reverting decisions (level %d -> %d)\n", level, l);
1684 revert(solv, level);
1685 r = addrule(solv, p, d); /* p requires d */
1688 if (solv->learnt_why.count != (r - solv->rules) - solv->learntrules)
1690 printf("%d %d\n", solv->learnt_why.count, (int)(r - solv->rules) - solv->learntrules);
1693 queue_push(&solv->learnt_why, why);
1696 /* at least 2 literals, needs watches */
1697 watch2onhighest(solv, r);
1698 addwatches(solv, r);
1700 solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1701 queue_push(&solv->decisionq, p);
1702 queue_push(&solv->decisionq_why, r - solv->rules);
1703 if (solv->pool->verbose > 1)
1705 printf("decision: ");
1706 printruleelement(solv, 0, p);
1707 printf("new rule: ");
1716 * install best package from the queue. We add an extra package, inst, if
1717 * provided. See comment in weak install section.
1720 selectandinstall(Solver *solv, int level, Queue *dq, Id inst, int disablerules)
1722 Pool *pool = solv->pool;
1727 policy_filter_unwanted(solv, dq, inst, POLICY_MODE_CHOOSE);
1732 /* choose the supplemented one */
1733 for (i = 0; i < dq->count; i++)
1734 if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1738 for (i = 1; i < dq->count; i++)
1739 queue_push(&solv->branches, dq->elements[i]);
1740 queue_push(&solv->branches, -level);
1744 p = dq->elements[i];
1746 Solvable *s = pool->solvables + p;
1747 printf("installing %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
1749 return setpropagatelearn(solv, level, p, disablerules);
1753 /*-----------------------------------------------------------------*/
1754 /* Main solver interface */
1759 * create solver structure
1761 * pool: all available solvables
1762 * installed: installed Solvables
1765 * Upon solving, rules are created to flag the Solvables
1766 * of the 'installed' Repo as installed.
1770 solver_create(Pool *pool, Repo *installed)
1773 solv = (Solver *)xcalloc(1, sizeof(Solver));
1775 solv->installed = installed;
1777 queue_init(&solv->ruletojob);
1778 queue_init(&solv->decisionq);
1779 queue_init(&solv->decisionq_why);
1780 queue_init(&solv->problems);
1781 queue_init(&solv->suggestions);
1782 queue_init(&solv->learnt_why);
1783 queue_init(&solv->learnt_pool);
1784 queue_init(&solv->branches);
1786 map_init(&solv->recommendsmap, pool->nsolvables);
1787 map_init(&solv->suggestsmap, pool->nsolvables);
1788 map_init(&solv->noupdate, installed ? installed->nsolvables : 0);
1789 solv->recommends_index = 0;
1791 solv->decisionmap = (Id *)xcalloc(pool->nsolvables, sizeof(Id));
1792 solv->rules = (Rule *)xmalloc((solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
1793 memset(solv->rules, 0, sizeof(Rule));
1805 solver_free(Solver *solv)
1807 queue_free(&solv->ruletojob);
1808 queue_free(&solv->decisionq);
1809 queue_free(&solv->decisionq_why);
1810 queue_free(&solv->learnt_why);
1811 queue_free(&solv->learnt_pool);
1812 queue_free(&solv->problems);
1813 queue_free(&solv->suggestions);
1814 queue_free(&solv->branches);
1816 map_free(&solv->recommendsmap);
1817 map_free(&solv->suggestsmap);
1818 map_free(&solv->noupdate);
1819 xfree(solv->decisionmap);
1821 xfree(solv->watches);
1822 xfree(solv->weaksystemrules);
1823 xfree(solv->obsoletes);
1824 xfree(solv->obsoletes_data);
1829 /*-------------------------------------------------------*/
1834 * all rules have been set up, now actually run the solver
1839 run_solver(Solver *solv, int disablerules, int doweak)
1847 Pool *pool = solv->pool;
1851 printf("number of rules: %d\n", solv->nrules);
1852 for (i = 0; i < solv->nrules; i++)
1853 printrule(solv, solv->rules + i);
1856 /* all new rules are learnt after this point */
1857 solv->learntrules = solv->nrules;
1858 /* crate watches lists */
1861 if (pool->verbose) printf("initial decisions: %d\n", solv->decisionq.count);
1863 /* start SAT algorithm */
1865 systemlevel = level + 1;
1866 if (pool->verbose) printf("solving...\n");
1877 if (pool->verbose) printf("propagating (%d %d)...\n", solv->propagate_index, solv->decisionq.count);
1878 if ((r = propagate(solv, level)) != 0)
1880 if (analyze_unsolvable(solv, r, disablerules))
1882 printf("UNSOLVABLE\n");
1889 * installed packages
1892 if (level < systemlevel && solv->installed->nsolvables)
1894 if (!solv->updatesystem)
1896 /* try to keep as many packages as possible */
1897 if (pool->verbose) printf("installing system packages\n");
1898 for (i = solv->installed->start, n = 0; ; i++, n++)
1900 if (n == solv->installed->nsolvables)
1902 if (i == solv->installed->start + solv->installed->nsolvables)
1903 i = solv->installed->start;
1904 s = pool->solvables + i;
1905 if (solv->decisionmap[i] != 0)
1908 printf("keeping %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
1911 level = setpropagatelearn(solv, level, i, disablerules);
1914 printf("UNSOLVABLE\n");
1918 if (level <= olevel)
1922 if (solv->weaksystemrules)
1924 if (pool->verbose) printf("installing weak system packages\n");
1925 for (i = solv->installed->start, n = 0; ; i++, n++)
1927 if (n == solv->installed->nsolvables)
1929 if (solv->decisionmap[i] > 0 || (solv->decisionmap[i] < 0 && solv->weaksystemrules[i - solv->installed->start] == 0))
1931 /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
1932 if (MAPTST(&solv->noupdate, i - solv->installed->start))
1935 if (solv->weaksystemrules[i - solv->installed->start])
1937 dp = pool->whatprovidesdata + solv->weaksystemrules[i - solv->installed->start];
1938 while ((p = *dp++) != 0)
1940 if (solv->decisionmap[p] > 0)
1942 if (solv->decisionmap[p] == 0)
1946 continue; /* update package already installed */
1948 if (!dq.count && solv->decisionmap[i] != 0)
1951 /* FIXME: i is handled a bit different because we do not want
1952 * to have it pruned just because it is not recommened.
1953 * we should not prune installed packages instead */
1954 level = selectandinstall(solv, level, &dq, (solv->decisionmap[i] ? 0 : i), disablerules);
1957 printf("UNSOLVABLE\n");
1961 if (level <= olevel)
1967 if (n != solv->installed->nsolvables)
1970 systemlevel = level;
1977 if (pool->verbose) printf("deciding unresolved rules\n");
1978 for (i = 1, n = 1; ; i++, n++)
1980 if (n == solv->nrules)
1982 if (i == solv->nrules)
1984 r = solv->rules + i;
1990 /* binary or unary rule */
1991 /* need two positive undecided literals */
1992 if (r->p < 0 || r->w2 <= 0)
1994 if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
1996 queue_push(&dq, r->p);
1997 queue_push(&dq, r->w2);
2002 * all negative literals are installed
2003 * no positive literal is installed
2004 * i.e. the rule is not fulfilled and we
2005 * just need to decide on the positive literals
2009 if (solv->decisionmap[-r->p] <= 0)
2014 if (solv->decisionmap[r->p] > 0)
2016 if (solv->decisionmap[r->p] == 0)
2017 queue_push(&dq, r->p);
2019 dp = pool->whatprovidesdata + r->d;
2020 while ((p = *dp++) != 0)
2024 if (solv->decisionmap[-p] <= 0)
2029 if (solv->decisionmap[p] > 0)
2031 if (solv->decisionmap[p] == 0)
2040 /* cannot happen as this means that
2041 * the rule is unit */
2045 if (pool->verbose > 2)
2049 level = selectandinstall(solv, level, &dq, 0, disablerules);
2052 printf("UNSOLVABLE\n");
2056 if (level < systemlevel)
2059 } /* for(), decide */
2061 if (n != solv->nrules) /* continue if level < systemlevel */
2064 if (doweak && !solv->problems.count)
2068 if (pool->verbose) printf("installing recommended packages\n");
2070 for (i = 1; i < pool->nsolvables; i++)
2072 if (solv->decisionmap[i] < 0)
2074 if (solv->decisionmap[i] > 0)
2076 Id *recp, rec, *pp, p;
2077 s = pool->solvables + i;
2078 /* installed, check for recommends */
2079 /* XXX need to special case AND ? */
2082 recp = s->repo->idarraydata + s->recommends;
2083 while ((rec = *recp++) != 0)
2086 FOR_PROVIDES(p, pp, rec)
2088 if (solv->decisionmap[p] > 0)
2093 else if (solv->decisionmap[p] == 0)
2095 queue_pushunique(&dq, p);
2103 s = pool->solvables + i;
2104 if (!s->supplements && !s->freshens)
2106 if (!pool_installable(pool, s))
2108 if (solver_is_supplementing(solv, s))
2109 queue_pushunique(&dq, i);
2115 policy_filter_unwanted(solv, &dq, 0, POLICY_MODE_RECOMMEND);
2117 s = pool->solvables + p;
2119 printf("installing recommended %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2121 level = setpropagatelearn(solv, level, p, 0);
2126 if (solv->solution_callback)
2128 solv->solution_callback(solv, solv->solution_callback_data);
2129 if (solv->branches.count)
2131 int i = solv->branches.count - 1;
2132 int l = -solv->branches.elements[i];
2134 if (solv->branches.elements[i - 1] < 0)
2136 p = solv->branches.elements[i];
2138 s = pool->solvables + p;
2139 printf("branching with %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2142 for (j = i + 1; j < solv->branches.count; j++)
2143 queue_push(&dq, solv->branches.elements[j]);
2144 solv->branches.count = i;
2146 revert(solv, level);
2148 for (j = 0; j < dq.count; j++)
2149 queue_push(&solv->branches, dq.elements[j]);
2151 level = setpropagatelearn(solv, level, p, disablerules);
2154 printf("UNSOLVABLE\n");
2160 /* all branches done, we're finally finished */
2164 /* minimization step */
2165 if (solv->branches.count)
2167 int l = 0, lasti = -1, lastl = -1;
2169 for (i = solv->branches.count - 1; i >= 0; i--)
2171 p = solv->branches.elements[i];
2174 else if (p > 0 && solv->decisionmap[p] > l + 1)
2182 /* kill old solvable so that we do not loop */
2183 p = solv->branches.elements[lasti];
2184 solv->branches.elements[lasti] = 0;
2185 s = pool->solvables + p;
2187 printf("minimizing %d -> %d with %s-%s.%s\n", solv->decisionmap[p], l, id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2190 revert(solv, level);
2192 level = setpropagatelearn(solv, level, p, disablerules);
2195 printf("UNSOLVABLE\n");
2210 * at this point, all rules that led to conflicts are disabled.
2211 * we re-enable all rules of a problem set but rule "sug", then
2212 * continue to disable more rules until there as again a solution.
2215 /* FIXME: think about conflicting assertions */
2218 refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
2226 printf("refine_suggestion start\n");
2228 queue_init(&disabled);
2229 queue_empty(refined);
2230 queue_push(refined, sug);
2232 /* re-enable all problem rules with the exception of "sug" */
2236 for (i = 0; problem[i]; i++)
2237 if (problem[i] != sug)
2238 enableproblem(solv, problem[i]);
2241 disableupdaterules(solv, job, -(sug + 1));
2245 /* re-enable as many weak rules as possible */
2246 for (i = solv->weakrules; i < solv->learntrules; i++)
2248 r = solv->rules + i;
2251 if (r->d == 0 || r->w2 != r->p)
2254 r->w1 = solv->pool->whatprovidesdata[r->d];
2257 queue_empty(&solv->problems);
2258 revert(solv, 1); /* XXX move to reset_solver? */
2260 run_solver(solv, 0, 0);
2261 if (!solv->problems.count)
2263 printf("no more problems!\n");
2265 printdecisions(solv);
2267 break; /* great, no more problems */
2269 disabledcnt = disabled.count;
2270 for (i = 0; i < solv->problems.count - 1; i++)
2272 /* ignore solutions in refined */
2273 v = solv->problems.elements[i];
2274 for (j = 0; problem[j]; j++)
2275 if (problem[j] != sug && problem[j] == v)
2279 queue_push(&disabled, v);
2281 if (disabled.count == disabledcnt)
2283 /* no solution found, this was an invalid suggestion! */
2284 printf("no solution found!\n");
2288 if (disabled.count == disabledcnt + 1)
2290 /* just one suggestion, add it to refined list */
2291 v = disabled.elements[disabledcnt];
2292 queue_push(refined, v);
2293 disableproblem(solv, v);
2295 disableupdaterules(solv, job, -(v + 1));
2299 /* more than one solution, disable all */
2300 /* do not push anything on refine list */
2301 if (solv->pool->verbose > 1)
2303 printf("more than one solution found:\n");
2304 for (i = disabledcnt; i < disabled.count; i++)
2305 printproblem(solv, disabled.elements[i]);
2307 for (i = disabledcnt; i < disabled.count; i++)
2308 disableproblem(solv, disabled.elements[i]);
2311 /* all done, get us back into the same state as before */
2312 /* enable refined rules again */
2313 for (i = 0; i < disabled.count; i++)
2314 enableproblem(solv, disabled.elements[i]);
2315 /* disable problem rules again */
2316 for (i = 0; problem[i]; i++)
2317 disableproblem(solv, problem[i]);
2318 printf("refine_suggestion end\n");
2327 id2rc(Solver *solv, Id id)
2330 if (solv->rc_output != 2)
2332 evr = id2str(solv->pool, id);
2333 if (*evr < '0' || *evr > '9')
2335 while (*evr >= '0' && *evr <= '9')
2343 printdecisions(Solver *solv)
2345 Pool *pool = solv->pool;
2346 Id p, *obsoletesmap;
2350 obsoletesmap = (Id *)xcalloc(pool->nsolvables, sizeof(Id));
2351 for (i = 0; i < solv->decisionq.count; i++)
2355 n = solv->decisionq.elements[i];
2358 if (n == SYSTEMSOLVABLE)
2360 if (n >= solv->installed->start && n < solv->installed->start + solv->installed->nsolvables)
2362 s = pool->solvables + n;
2363 FOR_PROVIDES(p, pp, s->name)
2364 if (s->name == pool->solvables[p].name)
2366 if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables && !obsoletesmap[p])
2368 obsoletesmap[p] = n;
2373 for (i = 0; i < solv->decisionq.count; i++)
2378 n = solv->decisionq.elements[i];
2381 if (n == SYSTEMSOLVABLE)
2383 if (n >= solv->installed->start && n < solv->installed->start + solv->installed->nsolvables)
2385 s = pool->solvables + n;
2388 obsp = s->repo->idarraydata + s->obsoletes;
2389 while ((obs = *obsp++) != 0)
2390 FOR_PROVIDES(p, pp, obs)
2392 if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables && !obsoletesmap[p])
2394 obsoletesmap[p] = n;
2400 if (solv->rc_output)
2401 printf(">!> Solution #1:\n");
2403 int installs = 0, uninstalls = 0, upgrades = 0;
2405 /* print solvables to be erased */
2407 for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
2409 if (solv->decisionmap[i] > 0)
2411 if (obsoletesmap[i])
2413 s = pool->solvables + i;
2414 if (solv->rc_output == 2)
2415 printf(">!> remove %s-%s%s\n", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
2416 else if (solv->rc_output)
2417 printf(">!> remove %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2419 printf("erase %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2423 /* print solvables to be installed */
2425 for (i = 0; i < solv->decisionq.count; i++)
2428 p = solv->decisionq.elements[i];
2431 if (p == SYSTEMSOLVABLE)
2433 if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables)
2435 s = pool->solvables + p;
2437 if (!obsoletesmap[p])
2439 if (solv->rc_output)
2441 printf("install %s-%s%s", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
2442 if (solv->rc_output != 2)
2443 printf(".%s", id2str(pool, s->arch));
2446 else if (!solv->rc_output)
2448 printf("update %s-%s.%s (obsoletes", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2449 for (j = solv->installed->start; j < solv->installed->start + solv->installed->nsolvables; j++)
2451 if (obsoletesmap[j] != p)
2453 s = pool->solvables + j;
2454 printf(" %s-%s.%s", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2461 Solvable *f, *fn = 0;
2462 for (j = solv->installed->start; j < solv->installed->start + solv->installed->nsolvables; j++)
2464 if (obsoletesmap[j] != p)
2466 f = pool->solvables + j;
2467 if (fn || f->name != s->name)
2469 if (solv->rc_output == 2)
2470 printf(">!> remove %s-%s%s\n", id2str(pool, f->name), id2rc(solv, f->evr), id2str(pool, f->evr));
2471 else if (solv->rc_output)
2472 printf(">!> remove %s-%s.%s\n", id2str(pool, f->name), id2str(pool, f->evr), id2str(pool, f->arch));
2480 printf(">!> install %s-%s%s", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
2481 if (solv->rc_output != 2)
2482 printf(".%s", id2str(pool, s->arch));
2487 if (solv->rc_output == 2)
2488 printf(">!> upgrade %s-%s => %s-%s%s", id2str(pool, fn->name), id2str(pool, fn->evr), id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
2490 printf(">!> upgrade %s-%s.%s => %s-%s.%s", id2str(pool, fn->name), id2str(pool, fn->evr), id2str(pool, fn->arch), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2494 if (solv->rc_output)
2496 Repo *repo = s->repo;
2497 if (repo && strcmp(repo_name(repo), "locales"))
2498 printf("[%s]", repo_name(repo));
2503 if (solv->rc_output)
2504 printf(">!> installs=%d, upgrades=%d, uninstalls=%d\n", installs, upgrades, uninstalls);
2506 xfree(obsoletesmap);
2511 /* for each installed solvable find which packages with *different* names
2512 * obsolete the solvable.
2513 * this index is used in policy_findupdatepackages if noupdateprovide is set.
2517 create_obsolete_index(Solver *solv)
2519 Pool *pool = solv->pool;
2521 Repo *installed = solv->installed;
2522 Id p, *pp, obs, *obsp, *obsoletes, *obsoletes_data;
2525 /* create reverse obsoletes map for installed solvables */
2526 solv->obsoletes = obsoletes = xcalloc(installed->nsolvables, sizeof(Id));
2527 for (i = 1; i < pool->nsolvables; i++)
2529 s = pool->solvables + i;
2532 if (!pool_installable(pool, s))
2534 obsp = s->repo->idarraydata + s->obsoletes;
2535 while ((obs = *obsp++) != 0)
2536 FOR_PROVIDES(p, pp, obs)
2538 if (p < installed->start || p >= installed->start + installed->nsolvables)
2540 if (pool->solvables[p].name == s->name)
2542 obsoletes[p - installed->start]++;
2546 for (i = 0; i < installed->nsolvables; i++)
2549 n += obsoletes[i] + 1;
2552 solv->obsoletes_data = obsoletes_data = xcalloc(n + 1, sizeof(Id));
2553 if (pool->verbose) printf("obsoletes data: %d entries\n", n + 1);
2554 for (i = pool->nsolvables - 1; i > 0; i--)
2556 s = pool->solvables + i;
2559 if (!pool_installable(pool, s))
2561 obsp = s->repo->idarraydata + s->obsoletes;
2562 while ((obs = *obsp++) != 0)
2563 FOR_PROVIDES(p, pp, obs)
2565 if (p < installed->start || p >= installed->start + installed->nsolvables)
2567 if (pool->solvables[p].name == s->name)
2569 p -= installed->start;
2570 if (obsoletes_data[obsoletes[p]] != i)
2571 obsoletes_data[--obsoletes[p]] = i;
2577 /*-----------------------------------------------------------------*/
2587 solve(Solver *solv, Queue *job)
2589 Pool *pool = solv->pool;
2591 Map addedmap; /* '1' == have rule for solvable */
2592 Id how, what, p, *pp, d;
2597 * create basic rule set of all involved packages
2602 map_init(&addedmap, pool->nsolvables);
2607 * always install our system solvable
2609 MAPSET(&addedmap, SYSTEMSOLVABLE);
2610 queue_push(&solv->decisionq, SYSTEMSOLVABLE);
2611 queue_push(&solv->decisionq_why, 0);
2612 solv->decisionmap[SYSTEMSOLVABLE] = 1;
2615 * create rules for installed solvables -> keep them installed
2616 * so called: rpm rules
2620 for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
2621 addrpmrulesforsolvable(solv, pool->solvables + i, &addedmap);
2624 * create install rules
2626 * two passes, as we want to keep the rpm rules distinct from the job rules
2630 if (solv->noupdateprovide && solv->installed->nsolvables)
2631 create_obsolete_index(solv);
2635 * process job rules for solvables
2638 for (i = 0; i < job->count; i += 2)
2640 how = job->elements[i];
2641 what = job->elements[i + 1];
2645 case SOLVER_INSTALL_SOLVABLE:
2646 addrpmrulesforsolvable(solv, pool->solvables + what, &addedmap);
2648 case SOLVER_INSTALL_SOLVABLE_NAME:
2649 case SOLVER_INSTALL_SOLVABLE_PROVIDES:
2651 FOR_PROVIDES(p, pp, what)
2653 /* if by name, ensure that the name matches */
2654 if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
2656 addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
2659 case SOLVER_INSTALL_SOLVABLE_UPDATE:
2660 /* dont allow downgrade */
2661 addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
2666 for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
2667 addrpmrulesforupdaters(solv, pool->solvables + i, &addedmap, 1);
2669 addrpmrulesforweak(solv, &addedmap);
2674 int possible = 0, installable = 0;
2675 for (i = 1; i < pool->nsolvables; i++)
2677 if (pool_installable(pool, pool->solvables + i))
2679 if (MAPTST(&addedmap, i))
2682 printf("%d of %d installable solvables used for solving\n", possible, installable);
2687 * first pass done, we now have all the rpm rules we need.
2688 * unify existing rules before going over all job rules and
2690 * at this point the system is always solvable,
2691 * as an empty system (remove all packages) is a valid solution
2694 unifyrules(solv); /* remove duplicate rpm rules */
2696 if (pool->verbose) printf("decisions based on rpms: %d\n", solv->decisionq.count);
2699 * now add all job rules
2702 solv->jobrules = solv->nrules;
2704 for (i = 0; i < job->count; i += 2)
2706 how = job->elements[i];
2707 what = job->elements[i + 1];
2710 case SOLVER_INSTALL_SOLVABLE: /* install specific solvable */
2711 s = pool->solvables + what;
2712 if (solv->rc_output)
2714 printf(">!> Installing %s from channel %s\n", id2str(pool, s->name), repo_name(s->repo));
2717 printf("job: install solvable %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2718 addrule(solv, what, 0); /* install by Id */
2719 queue_push(&solv->ruletojob, i);
2721 case SOLVER_ERASE_SOLVABLE:
2722 s = pool->solvables + what;
2724 printf("job: erase solvable %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2725 addrule(solv, -what, 0); /* remove by Id */
2726 queue_push(&solv->ruletojob, i);
2728 case SOLVER_INSTALL_SOLVABLE_NAME: /* install by capability */
2729 case SOLVER_INSTALL_SOLVABLE_PROVIDES:
2730 if (pool->verbose && how == SOLVER_INSTALL_SOLVABLE_NAME)
2731 printf("job: install name %s\n", id2str(pool, what));
2732 if (pool->verbose && how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
2733 printf("job: install provides %s\n", dep2str(pool, what));
2735 FOR_PROVIDES(p, pp, what)
2737 /* if by name, ensure that the name matches */
2738 if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
2744 /* no provider, make this an impossible rule */
2745 queue_push(&q, -SYSTEMSOLVABLE);
2748 p = queue_shift(&q); /* get first provider */
2750 d = 0; /* single provider ? -> make assertion */
2752 d = pool_queuetowhatprovides(pool, &q); /* get all providers */
2753 addrule(solv, p, d); /* add 'requires' rule */
2754 queue_push(&solv->ruletojob, i);
2756 case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */
2757 case SOLVER_ERASE_SOLVABLE_PROVIDES:
2758 if (pool->verbose && how == SOLVER_ERASE_SOLVABLE_NAME)
2759 printf("job: erase name %s\n", id2str(pool, what));
2760 if (pool->verbose && how == SOLVER_ERASE_SOLVABLE_PROVIDES)
2761 printf("job: erase provides %s\n", dep2str(pool, what));
2762 FOR_PROVIDES(p, pp, what)
2764 /* if by name, ensure that the name matches */
2765 if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
2767 addrule(solv, -p, 0); /* add 'remove' rule */
2768 queue_push(&solv->ruletojob, i);
2771 case SOLVER_INSTALL_SOLVABLE_UPDATE: /* find update for solvable */
2772 s = pool->solvables + what;
2774 printf("job: update %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2775 addupdaterule(solv, s, 0);
2776 queue_push(&solv->ruletojob, i);
2781 if (solv->ruletojob.count != solv->nrules - solv->jobrules)
2784 if (pool->verbose) printf("problems so far: %d\n", solv->problems.count);
2787 * now add policy rules
2791 solv->systemrules = solv->nrules;
2794 * create rules for updating installed solvables
2798 if (!solv->allowuninstall)
2799 { /* loop over all installed solvables */
2800 /* we create all update rules, but disable some later on depending on the job */
2801 for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
2802 addupdaterule(solv, pool->solvables + i, 0);
2803 /* consistency check: we added a rule for _every_ system solvable */
2804 if (solv->nrules - solv->systemrules != solv->installed->nsolvables)
2808 if (pool->verbose) printf("problems so far: %d\n", solv->problems.count);
2810 /* create special weak system rules */
2811 if (solv->installed->nsolvables)
2813 solv->weaksystemrules = xcalloc(solv->installed->nsolvables, sizeof(Id));
2814 for (i = 0; i < solv->installed->nsolvables; i++)
2816 policy_findupdatepackages(solv, pool->solvables + solv->installed->start + i, &q, 1);
2818 solv->weaksystemrules[i] = pool_queuetowhatprovides(pool, &q);
2822 /* free unneeded memory */
2823 map_free(&addedmap);
2826 solv->weakrules = solv->nrules;
2828 /* try real hard to keep packages installed */
2831 for (i = 0; i < solv->installed->nsolvables; i++)
2833 /* FIXME: can't work with refine_suggestion! */
2834 /* need to always add the rule but disable it */
2835 if (MAPTST(&solv->noupdate, i))
2837 d = solv->weaksystemrules[i];
2838 addrule(solv, solv->installed->start + i, d);
2847 disableupdaterules(solv, job, -1);
2848 makeruledecisions(solv);
2849 run_solver(solv, 1, 1);
2851 /* find suggested packages */
2852 if (!solv->problems.count)
2854 Id sug, *sugp, p, *pp;
2856 /* create map of all suggests that are still open */
2857 solv->recommends_index = -1;
2858 MAPZERO(&solv->suggestsmap);
2859 for (i = 0; i < solv->decisionq.count; i++)
2861 p = solv->decisionq.elements[i];
2864 s = pool->solvables + p;
2867 sugp = s->repo->idarraydata + s->suggests;
2868 while ((sug = *sugp++) != 0)
2870 FOR_PROVIDES(p, pp, sug)
2871 if (solv->decisionmap[p] > 0)
2874 continue; /* already fulfilled */
2875 FOR_PROVIDES(p, pp, sug)
2876 MAPSET(&solv->suggestsmap, p);
2880 for (i = 1; i < pool->nsolvables; i++)
2882 if (solv->decisionmap[i] != 0)
2884 s = pool->solvables + i;
2885 if (!MAPTST(&solv->suggestsmap, i))
2889 if (!pool_installable(pool, s))
2891 if (!solver_is_enhancing(solv, s))
2894 queue_push(&solv->suggestions, i);
2896 policy_filter_unwanted(solv, &solv->suggestions, 0, POLICY_MODE_SUGGEST);
2901 * print solver result
2905 if (pool->verbose) printf("-------------------------------------------------------------\n");
2907 if (solv->problems.count)
2917 queue_clone(&problems, &solv->problems);
2918 queue_init(&solution);
2919 printf("Encountered problems! Here are the solutions:\n");
2920 problem = problems.elements;
2923 printf("Problem %d:\n", pcnt);
2924 printf("====================================\n");
2925 for (i = 0; i < problems.count; i++)
2927 Id v = problems.elements[i];
2931 if (i + 1 == problems.count)
2933 printf("Problem %d:\n", ++pcnt);
2934 printf("====================================\n");
2935 problem = problems.elements + i + 1;
2938 refine_suggestion(solv, job, problem, v, &solution);
2939 for (j = 0; j < solution.count; j++)
2941 why = solution.elements[j];
2943 printproblem(solv, why);
2948 what = job->elements[ji + 1];
2949 switch (job->elements[ji])
2951 case SOLVER_INSTALL_SOLVABLE:
2952 s = pool->solvables + what;
2953 if (what >= solv->installed->start && what < solv->installed->start + solv->installed->nsolvables)
2954 printf("- do not keep %s-%s.%s installed\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2956 printf("- do not install %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2958 case SOLVER_ERASE_SOLVABLE:
2959 s = pool->solvables + what;
2960 if (what >= solv->installed->start && what < solv->installed->start + solv->installed->nsolvables)
2961 printf("- do not deinstall %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2963 printf("- do not forbid installation of %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2965 case SOLVER_INSTALL_SOLVABLE_NAME:
2966 printf("- do not install %s\n", id2str(pool, what));
2968 case SOLVER_ERASE_SOLVABLE_NAME:
2969 printf("- do not deinstall %s\n", id2str(pool, what));
2971 case SOLVER_INSTALL_SOLVABLE_PROVIDES:
2972 printf("- do not install a solvable providing %s\n", dep2str(pool, what));
2974 case SOLVER_ERASE_SOLVABLE_PROVIDES:
2975 printf("- do not deinstall all solvables providing %s\n", dep2str(pool, what));
2977 case SOLVER_INSTALL_SOLVABLE_UPDATE:
2978 s = pool->solvables + what;
2979 printf("- do not install most recent version of %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
2982 printf("- do something different\n");
2986 else if (why >= solv->systemrules && why < solv->weakrules)
2989 s = pool->solvables + solv->installed->start + (why - solv->systemrules);
2990 if (solv->weaksystemrules && solv->weaksystemrules[why - solv->systemrules])
2992 Id *dp = pool->whatprovidesdata + solv->weaksystemrules[why - solv->systemrules];
2995 if (*dp >= solv->installed->start && *dp < solv->installed->start + solv->installed->nsolvables)
2997 if (solv->decisionmap[*dp] > 0)
2999 sd = pool->solvables + *dp;
3007 if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr) > 0)
3009 printf("- allow downgrade of %s-%s.%s to %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
3012 if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(pool, s, sd))
3014 printf("- allow architecture change of %s-%s.%s to %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
3017 if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(pool, s, sd))
3020 printf("- allow vendor change from '%s' (%s-%s.%s) to '%s' (%s-%s.%s)\n", id2str(pool, s->vendor), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->vendor), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
3022 printf("- allow vendor change from '%s' (%s-%s.%s) to no vendor (%s-%s.%s)\n", id2str(pool, s->vendor), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
3026 printf("- allow replacement of %s-%s.%s with %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
3030 printf("- allow deinstallation of %s-%s.%s [%ld]\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), (long int)(s - pool->solvables));
3038 printf("------------------------------------\n");
3040 queue_free(&solution);
3041 queue_free(&problems);
3045 printdecisions(solv);
3046 if (solv->suggestions.count)
3048 printf("\nsuggested packages:\n");
3049 for (i = 0; i < solv->suggestions.count; i++)
3051 s = pool->solvables + solv->suggestions.elements[i];
3052 printf("- %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));