2 * Copyright (c) 2022, SUSE LLC
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * solver decision and alternative introspection code
21 #include "solver_private.h"
28 solver_get_decisionlevel(Solver *solv, Id p)
30 return solv->decisionmap[p];
34 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
36 queue_free(decisionq);
37 queue_init_clone(decisionq, &solv->decisionq);
41 solver_get_lastdecisionblocklevel(Solver *solv)
44 if (solv->decisionq.count == 0)
46 p = solv->decisionq.elements[solv->decisionq.count - 1];
49 return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
53 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
58 queue_empty(decisionq);
59 for (i = 0; i < solv->decisionq.count; i++)
61 p = solv->decisionq.elements[i];
64 if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
67 if (i == solv->decisionq.count)
69 for (i = 0; i < solv->decisionq.count; i++)
71 p = solv->decisionq.elements[i];
74 if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
75 queue_push(decisionq, p);
81 /* return the reason and some extra info (i.e. a rule id) why
82 * a package was installed/conflicted */
84 solver_describe_decision(Solver *solv, Id p, Id *infop)
91 if (!solv->decisionmap[p])
92 return SOLVER_REASON_UNRELATED;
93 pp = solv->decisionmap[p] < 0 ? -p : p;
94 for (i = 0; i < solv->decisionq.count; i++)
95 if (solv->decisionq.elements[i] == pp)
97 if (i == solv->decisionq.count) /* just in case... */
98 return SOLVER_REASON_UNRELATED;
99 why = solv->decisionq_why.elements[i];
101 *infop = why >= 0 ? why : -why;
103 return SOLVER_REASON_UNIT_RULE;
104 i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
105 return solv->decisionq_reason.elements[i];
108 /* create pseudo ruleinfo elements why a package was installed if
109 * the reason was SOLVER_REASON_WEAKDEP */
111 solver_allweakdepinfos(Solver *solv, Id p, Queue *whyq)
113 Pool *pool = solv->pool;
115 int level = solv->decisionmap[p];
122 for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
123 if (solv->decisionq.elements[decisionno] == p)
125 if (decisionno == solv->decisionq.count)
127 i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
128 if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
131 /* 1) list all packages that recommend us */
132 for (i = 1; i < pool->nsolvables; i++)
134 Id *recp, rec, pp2, p2;
135 if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
137 s = pool->solvables + i;
140 if (!solv->addalreadyrecommended && s->repo == solv->installed)
142 recp = s->repo->idarraydata + s->recommends;
143 while ((rec = *recp++) != 0)
146 FOR_PROVIDES(p2, pp2, rec)
152 /* if p2 is already installed, this recommends is ignored */
153 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
159 queue_push2(whyq, SOLVER_RULE_PKG_RECOMMENDS, i);
160 queue_push2(whyq, 0, rec);
164 /* 2) list all supplements */
165 s = pool->solvables + p;
166 if (s->supplements && level > 0)
168 Id *supp, sup, pp2, p2;
169 /* this is a hack. to use solver_dep_fulfilled we temporarily clear
170 * everything above our level in the decisionmap */
171 for (i = decisionno; i < solv->decisionq.count; i++ )
173 p2 = solv->decisionq.elements[i];
175 solv->decisionmap[p2] = -solv->decisionmap[p2];
177 supp = s->repo->idarraydata + s->supplements;
178 while ((sup = *supp++) != 0)
179 if (solver_dep_fulfilled(solv, sup))
182 /* let's see if this is an easy supp */
183 FOR_PROVIDES(p2, pp2, sup)
185 if (!solv->addalreadyrecommended && solv->installed)
187 if (pool->solvables[p2].repo == solv->installed)
190 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
192 queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
193 queue_push2(whyq, p2, sup);
199 /* hard case, just note dependency with no package */
200 queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
201 queue_push2(whyq, 0, sup);
204 for (i = decisionno; i < solv->decisionq.count; i++)
206 p2 = solv->decisionq.elements[i];
208 solv->decisionmap[p2] = -solv->decisionmap[p2];
211 return whyq->count / 4;
215 solver_weakdepinfo(Solver *solv, Id p, Id *fromp, Id *top, Id *depp)
219 solver_allweakdepinfos(solv, p, &iq);
221 *fromp = iq.count ? iq.elements[1] : 0;
223 *top = iq.count ? iq.elements[2] : 0;
225 *depp = iq.count ? iq.elements[3] : 0;
226 return iq.count ? iq.elements[0] : SOLVER_RULE_UNKNOWN;
229 /* deprecated, use solver_allweakdepinfos instead */
231 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
234 solver_allweakdepinfos(solv, p, whyq);
235 for (i = j = 0; i < whyq->count; i += 4)
237 if (whyq->elements[i] == SOLVER_RULE_PKG_RECOMMENDS)
239 whyq->elements[j++] = SOLVER_REASON_RECOMMENDED;
240 whyq->elements[j++] = whyq->elements[i + 1];
241 whyq->elements[j++] = whyq->elements[i + 3];
243 else if (whyq->elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
245 whyq->elements[j++] = SOLVER_REASON_SUPPLEMENTED;
246 whyq->elements[j++] = whyq->elements[i + 2];
247 whyq->elements[j++] = whyq->elements[i + 3];
250 queue_truncate(whyq, j);
254 decisionsort_cmp(const void *va, const void *vb, void *vd)
257 Pool *pool = solv->pool;
258 const Id *a = va, *b = vb; /* (decision, reason, rid, bits, type, from, to, dep) */
260 if (a[4] != b[4]) /* type */
262 if (a[7] != b[7]) /* dep id */
264 as = pool->solvables + a[5];
265 bs = pool->solvables + b[5];
266 if (as->name != bs->name)
267 return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
268 if (as->evr != bs->evr)
270 int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
274 as = pool->solvables + a[6];
275 bs = pool->solvables + b[6];
276 if (as->name != bs->name)
277 return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
278 if (as->evr != bs->evr)
280 int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
288 decisionmerge(Solver *solv, Queue *q)
290 Pool *pool = solv->pool;
293 for (i = 0; i < q->count; i += 8)
295 Id p = q->elements[i] >= 0 ? q->elements[i] : -q->elements[i];
296 int reason = q->elements[i + 1];
297 int bits = q->elements[i + 3];
298 Id name = pool->solvables[p].name;
299 for (j = i + 8; j < q->count; j += 8)
302 p = q->elements[j] >= 0 ? q->elements[j] : -q->elements[j];
303 if (reason != q->elements[j + 1] || name != pool->solvables[p].name)
305 merged = solver_merge_decisioninfo_bits(solv, bits, q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7], q->elements[j + 3], q->elements[j + 4], q->elements[j + 5], q->elements[j + 6], q->elements[j + 7]);
311 for (; i < j; i += 8)
312 q->elements[i + 3] = bits;
316 /* move a decison from position "from" to a smaller position "to" */
318 move_decision(Queue *q, int to, int from)
320 queue_insertn(q, to, 8, 0);
321 memmove(q->elements + to, q->elements + from + 8, 8 * sizeof(Id));
322 queue_deleten(q, from + 8, 8);
325 /* sort a block of SOLVER_REASON_UNIT_RULE decisions */
327 sort_unit_decisions(Solver *solv, Queue *q, int start, int end, Map *m)
329 Pool *pool = solv->pool;
330 int i, j, k, doing = 1;
331 if (start + 8 == end)
333 Id truelit = q->elements[start];
334 MAPSET(m, truelit >= 0 ? truelit : -truelit);
337 /* alternate between conflicts and installs, starting with conflicts */
338 for (i = start; i < end; doing ^= 1)
340 for (j = k = i; j < end; j += 8)
344 Id truelit = q->elements[j];
345 if ((doing == 0 && truelit < 0) || (doing != 0 && truelit >= 0))
347 or = solv->rules + q->elements[j + 2];
348 FOR_RULELITERALS(p, pp, or)
349 if (p != truelit && !MAPTST(m, p >= 0 ? p : -p))
352 continue; /* not unit yet */
354 move_decision(q, k, j);
360 solv_sort(q->elements + i, (k - i) / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
361 for (; i < k; i += 8)
363 Id truelit = q->elements[i];
364 MAPSET(m, truelit >= 0 ? truelit : -truelit);
370 solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
372 Pool *pool = solv->pool;
373 Map seen, seent; /* seent: was the literal true or false */
379 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_PROBLEM)
380 why = solv->problems.elements[2 * id - 2];
381 else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE && id >= solv->learntrules && id < solv->nrules)
382 why = solv->learnt_why.elements[id - solv->learntrules];
385 if (!solv->learnt_pool.elements[why])
388 map_init(&seen, pool->nsolvables);
389 map_init(&seent, pool->nsolvables);
390 while ((rid = solv->learnt_pool.elements[why++]) != 0)
392 Rule *r = solv->rules + rid;
395 FOR_RULELITERALS(p, pp, r)
397 Id vv = p > 0 ? p : -p;
398 if (MAPTST(&seen, vv))
400 if ((p > 0 ? 1 : 0) == (MAPTST(&seent, vv) ? 1 : 0))
404 truelit = p; /* the one true literal! */
409 /* a new literal. it must be false as the rule is unit */
416 queue_push(q, truelit);
423 /* add ruleinfo data to all rules (and also reverse the queue) */
425 for (i = q->count - 1; i >= 0; i -= 2)
428 Id from = 0, to = 0, dep = 0;
429 rid = q->elements[i];
430 type = solver_ruleinfo(solv, rid, &from, &to, &dep);
431 if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
433 /* use pkg ruleinfo for choice/recommends rules */
434 Id rid2 = solver_rule2pkgrule(solv, rid);
436 type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
438 queue_insertn(q, q->count, 8, 0);
439 q->elements[q->count - 8] = i > 0 ? q->elements[i - 1] : 0;
440 q->elements[q->count - 8 + 1] = i > 0 ? SOLVER_REASON_UNIT_RULE : SOLVER_REASON_UNSOLVABLE;
441 q->elements[q->count - 8 + 2] = rid;
442 q->elements[q->count - 8 + 4] = type;
443 q->elements[q->count - 8 + 5] = from;
444 q->elements[q->count - 8 + 6] = to;
445 q->elements[q->count - 8 + 7] = dep;
447 queue_deleten(q, 0, cnt);
449 /* switch last two decisions if the unsolvable rule is of type SOLVER_RULE_RPM_SAME_NAME */
450 if (q->count >= 16 && q->elements[q->count - 8 + 3] == SOLVER_RULE_RPM_SAME_NAME && q->elements[q->count - 16] > 0)
452 Rule *r = solv->rules + q->elements[q->count - 8 + 1];
453 /* make sure that the rule is a binary conflict and it matches the installed element */
454 if (r->p < 0 && (r->d == 0 || r->d == -1) && r->w2 < 0
455 && (q->elements[q->count - 16] == -r->p || q->elements[q->count - 16] -r->w2))
457 /* looks good! swap decisions and fixup truelit entries */
458 move_decision(q, q->count - 16, q->count - 8);
459 q->elements[q->count - 16] = -q->elements[q->count - 8];
460 q->elements[q->count - 8] = 0;
464 /* put learnt rule premises in front */
468 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE)
470 /* insert learnt prereqs at front */
471 Rule *r = solv->rules + id;
474 FOR_RULELITERALS(p, pp, r)
476 queue_insertn(q, i, 8, 0);
478 q->elements[i + 1] = SOLVER_REASON_PREMISE;
479 q->elements[i + 5] = p >= 0 ? p : -p;
480 MAPSET(&seen, p >= 0 ? p : -p);
485 if (flags & SOLVER_DECISIONLIST_SORTED)
487 /* sort premise block */
489 solv_sort(q->elements, i / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
490 sort_unit_decisions(solv, q, i, q->count - 8, &seen);
496 if (!(flags & SOLVER_DECISIONLIST_WITHINFO))
499 for (i = j = 0; i < q->count; i += 8)
501 q->elements[j++] = q->elements[i];
502 q->elements[j++] = q->elements[i + 1];
503 q->elements[j++] = q->elements[i + 2];
505 queue_truncate(q, j);
509 /* set decisioninfo bits */
510 for (i = 0; i < q->count; i += 8)
511 q->elements[i + 3] = solver_calc_decisioninfo_bits(solv, q->elements[i], q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7]);
512 if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
513 decisionmerge(solv, q);
518 solver_get_learnt(Solver *solv, Id id, int flags, Queue *q)
525 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_PROBLEM)
526 why = solv->problems.elements[2 * id - 2];
527 else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE && id >= solv->learntrules && id < solv->nrules)
528 why = solv->learnt_why.elements[id - solv->learntrules];
529 else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_SOLVABLE)
532 solver_get_decisionlist(solv, id, 0, &todo);
534 for (i = 0; i < cnt; i += 3)
536 int rid = todo.elements[i + 2];
537 if (rid < solv->learntrules || rid >= solv->nrules)
539 /* insert sorted and unified */
540 for (j = 0; j < q->count; j++)
542 if (q->elements[j] < rid)
544 if (q->elements[j] == rid)
549 continue; /* already in list */
550 queue_insert(q, j, rid);
551 queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
553 queue_deleten(&todo, 0, cnt);
561 queue_push(&todo, why);
565 why = queue_pop(&todo);
566 while ((rid = solv->learnt_pool.elements[why++]) != 0)
568 if (rid < solv->learntrules || rid >= solv->nrules)
570 /* insert sorted and unified */
571 for (i = 0; i < q->count; i++)
573 if (q->elements[i] < rid)
575 if (q->elements[i] == rid)
580 continue; /* already in list */
581 queue_insert(q, i, rid);
582 queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
589 getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
591 Pool *pool = solv->pool;
592 int i, ii, reason, info;
595 queue_empty(decisionlistq);
596 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
599 for (ii = solv->decisionq.count - 1; ii > 0; ii--)
601 Id v = solv->decisionq.elements[ii];
602 Id vv = (v > 0 ? v : -v);
605 info = solv->decisionq_why.elements[ii];
607 reason = SOLVER_REASON_UNIT_RULE;
611 reason = solv->decisionmap[vv];
612 reason = solv->decisionq_reason.elements[reason >= 0 ? reason : -reason];
614 if (flags & (SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO))
616 queue_insertn(decisionlistq, 0, 5, 0);
617 if (reason == SOLVER_REASON_WEAKDEP)
619 solver_allweakdepinfos(solv, v, &iq);
622 decisionlistq->elements[1] = iq.elements[0];
623 decisionlistq->elements[2] = iq.elements[1];
624 decisionlistq->elements[3] = iq.elements[2];
625 decisionlistq->elements[4] = iq.elements[3];
631 int type = solver_ruleinfo(solv, info, &from, &to, &dep);
632 if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
634 /* use pkg ruleinfo for choice/recommends rules */
635 Id rid2 = solver_rule2pkgrule(solv, info);
637 type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
639 decisionlistq->elements[1] = type;
640 decisionlistq->elements[2] = from;
641 decisionlistq->elements[3] = to;
642 decisionlistq->elements[4] = dep;
645 queue_unshift(decisionlistq, info);
646 queue_unshift(decisionlistq, reason);
647 queue_unshift(decisionlistq, v);
650 case SOLVER_REASON_WEAKDEP:
653 solver_allweakdepinfos(solv, v, &iq);
654 for (i = 0; i < iq.count; i += 4)
656 if (iq.elements[i + 1])
657 MAPSET(dm, iq.elements[i + 1]);
658 if (iq.elements[i + 2])
659 MAPSET(dm, iq.elements[i + 2]);
660 else if (iq.elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
662 Id p2, pp2, id = iq.elements[i + 3];
663 FOR_PROVIDES(p2, pp2, id)
664 if (solv->decisionmap[p2] > 0)
669 case SOLVER_REASON_RESOLVE_JOB:
670 case SOLVER_REASON_UNIT_RULE:
671 case SOLVER_REASON_RESOLVE:
672 solver_ruleliterals(solv, info, &iq);
673 for (i = 0; i < iq.count; i++)
675 Id p2 = iq.elements[i];
678 else if (solv->decisionmap[p2] > 0)
687 if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
689 /* reuse dm as "seen" map */
692 for (i = 0; i < decisionlistq->count; i += 8)
694 if (decisionlistq->elements[i + 1] != SOLVER_REASON_UNIT_RULE)
696 Id p = decisionlistq->elements[i] < 0 ? -decisionlistq->elements[i] : decisionlistq->elements[i];
702 for (j = i + 8; j < decisionlistq->count; j += 8)
703 if (decisionlistq->elements[j + 1] != SOLVER_REASON_UNIT_RULE)
705 sort_unit_decisions(solv, decisionlistq, i, j, dm);
709 if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
711 /* set decisioninfo bits */
712 for (i = 0; i < decisionlistq->count; i += 8)
713 decisionlistq->elements[i + 3] = solver_calc_decisioninfo_bits(solv, decisionlistq->elements[i], decisionlistq->elements[i + 4], decisionlistq->elements[i + 5], decisionlistq->elements[i + 6], decisionlistq->elements[i + 7]);
714 if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
715 decisionmerge(solv, decisionlistq);
717 else if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
719 /* strip the info elements we added for sorting */
721 for (i = j = 0; i < decisionlistq->count; i += 8)
723 decisionlistq->elements[j++] = decisionlistq->elements[i];
724 decisionlistq->elements[j++] = decisionlistq->elements[i + 1];
725 decisionlistq->elements[j++] = decisionlistq->elements[i + 2];
727 queue_truncate(decisionlistq, j);
732 solver_get_decisionlist(Solver *solv, Id id, int flags, Queue *decisionlistq)
734 Pool *pool = solv->pool;
736 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
737 return solver_get_proof(solv, id, flags, decisionlistq);
738 map_init(&dm, pool->nsolvables);
740 getdecisionlist(solv, &dm, flags, decisionlistq);
742 if (!decisionlistq->count)
744 queue_push(decisionlistq, -id);
745 queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
746 if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
748 queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -id, 0, 0, 0, 0));
749 queue_push2(decisionlistq, 0, 0);
750 queue_push2(decisionlistq, 0, 0);
756 solver_get_decisionlist_multiple(Solver *solv, Queue *idq, int flags, Queue *decisionlistq)
758 Pool *pool = solv->pool;
761 queue_empty(decisionlistq);
762 if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
764 map_init(&dm, pool->nsolvables);
765 for (i = 0; i < idq->count; i++)
767 Id p = idq->elements[i];
768 if (solv->decisionmap[p] != 0)
771 getdecisionlist(solv, &dm, flags, decisionlistq);
773 for (i = 0; i < idq->count; i++)
775 Id p = idq->elements[i];
776 if (solv->decisionmap[p] != 0)
778 queue_push(decisionlistq, -p);
779 queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
780 if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
782 queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -p, 0, 0, 0, 0));
783 queue_push2(decisionlistq, 0, 0);
784 queue_push2(decisionlistq, 0, 0);
791 solver_reason2str(Solver *solv, int reason)
795 case SOLVER_REASON_WEAKDEP:
796 return "a weak dependency";
797 case SOLVER_REASON_RESOLVE_JOB:
799 case SOLVER_REASON_RESOLVE:
801 case SOLVER_REASON_UNIT_RULE:
802 return "an unit rule";
803 case SOLVER_REASON_KEEP_INSTALLED:
804 return "update/keep installed";
805 case SOLVER_REASON_UPDATE_INSTALLED:
806 return "update installed";
807 case SOLVER_REASON_CLEANDEPS_ERASE:
808 return "cleandeps erase";
809 case SOLVER_REASON_RESOLVE_ORPHAN:
810 return "orphaned package";
811 case SOLVER_REASON_UNSOLVABLE:
813 case SOLVER_REASON_PREMISE:
814 return "learnt rule premise";
815 case SOLVER_REASON_UNRELATED:
816 return "it is unrelated";
820 return "an unknown reason";
824 decisionruleinfo2str(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
826 int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
827 return solver_decisioninfo2str(solv, bits, type, from, to, dep);
831 solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
833 if (reason == SOLVER_REASON_WEAKDEP && decision > 0)
836 int type = solver_weakdepinfo(solv, decision, &from, &to, &dep);
838 return decisionruleinfo2str(solv, decision, type, from, to, dep);
840 if ((reason == SOLVER_REASON_RESOLVE_JOB || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE || reason == SOLVER_REASON_UNSOLVABLE) && info > 0)
843 int type = solver_ruleinfo(solv, info, &from, &to, &dep);
844 if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
846 Id rid2 = solver_rule2pkgrule(solv, info);
849 type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
851 return decisionruleinfo2str(solv, decision, type, from, to, dep);
855 return decisionruleinfo2str(solv, decision, type, from, to, dep);
857 return solver_reason2str(solv, reason);
860 /* decision merge state bits */
861 #define DMS_INITED (1 << 0)
862 #define DMS_IDENTICAL_FROM (1 << 1)
863 #define DMS_IDENTICAL_TO (1 << 2)
864 #define DMS_MERGED (1 << 3)
865 #define DMS_NEGATIVE (1 << 4)
866 #define DMS_NOMERGE (1 << 5)
868 /* add some bits about the decision and the ruleinfo so we can join decisions */
870 solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
872 Id decisionpkg = decision >= 0 ? decision : -decision;
873 int bits = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0);
875 return bits | DMS_NOMERGE;
878 case SOLVER_RULE_DISTUPGRADE:
879 case SOLVER_RULE_INFARCH:
880 case SOLVER_RULE_UPDATE:
881 case SOLVER_RULE_FEATURE:
882 case SOLVER_RULE_BLACK:
883 case SOLVER_RULE_STRICT_REPO_PRIORITY:
884 case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
885 case SOLVER_RULE_PKG_REQUIRES:
886 case SOLVER_RULE_PKG_RECOMMENDS:
887 case SOLVER_RULE_PKG_SUPPLEMENTS:
888 if (decisionpkg == from)
889 bits |= DMS_IDENTICAL_FROM;
891 case SOLVER_RULE_PKG_SAME_NAME:
892 case SOLVER_RULE_PKG_CONFLICTS:
893 case SOLVER_RULE_PKG_OBSOLETES:
894 case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
895 case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
896 case SOLVER_RULE_PKG_CONSTRAINS:
897 if (decisionpkg == from)
898 bits |= DMS_IDENTICAL_FROM;
899 else if (decisionpkg == to)
900 bits |= DMS_IDENTICAL_TO;
908 /* try to merge the ruleinfos of two decisions */
910 solver_merge_decisioninfo_bits(Solver *solv, int bits1, int type1, Id from1, Id to1, Id dep1, int bits2, int type2, Id from2, Id to2, Id dep2)
913 if (type1 != type2 || dep1 != dep2)
915 if (!bits1 || !bits2 || ((bits1 | bits2) & DMS_NOMERGE) != 0 || ((bits1 ^ bits2) & DMS_NEGATIVE) != 0)
917 merged = (((bits1 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | (bits2 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO))) ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | DMS_MERGED;
918 if (((bits1 & DMS_MERGED) != 0 && bits1 != merged) || ((bits2 & DMS_MERGED) != 0 && bits2 != merged))
920 if (((merged & DMS_IDENTICAL_FROM) == 0 && from1 != from2) || ((merged & DMS_IDENTICAL_TO) == 0 && to1 != to2))
926 solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q)
929 for (; pos < decisionlistq->count; pos += 8)
931 Id p = decisionlistq->elements[pos];
932 queue_push(q, p > 0 ? p : -p);
933 if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
939 solver_decisionlist_merged(Solver *solv, Queue *decisionlistq, int pos)
942 for (; pos < decisionlistq->count; pos += 8, cnt++)
943 if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
948 /* special version of solver_ruleinfo2str which supports merged decisions */
950 solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep)
952 Pool *pool = solv->pool;
954 int multiple = bits & DMS_MERGED;
956 /* use it/they variants if DMS_IDENTICAL_FROM is set */
957 if ((bits & DMS_IDENTICAL_FROM) != 0)
961 case SOLVER_RULE_DISTUPGRADE:
962 return multiple ? "they do not belong to a distupgrade repository" : "it does not belong to a distupgrade repository";
963 case SOLVER_RULE_INFARCH:
964 return multiple ? "they have inferior architecture": "it has inferior architecture";
965 case SOLVER_RULE_UPDATE:
966 return multiple ? "they need to stay installed or be updated" : "it needs to stay installed or be updated";
967 case SOLVER_RULE_FEATURE:
968 return multiple ? "they need to stay installed or be updated/downgraded" : "it needs to stay installed or be updated/downgraded";
969 case SOLVER_RULE_BLACK:
970 return multiple ? "they can only be installed by a direct request" : "it can only be installed by a direct request";
971 case SOLVER_RULE_STRICT_REPO_PRIORITY:
972 return multiple ? "they are excluded by strict repo priority" : "it is excluded by strict repo priority";
974 case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
975 return pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
976 case SOLVER_RULE_PKG_REQUIRES:
977 return pool_tmpjoin(pool, multiple ? "they require " : "it requires ", pool_dep2str(pool, dep), 0);
978 case SOLVER_RULE_PKG_RECOMMENDS:
979 return pool_tmpjoin(pool, multiple ? "they recommend " : "it recommends ", pool_dep2str(pool, dep), 0);
980 case SOLVER_RULE_PKG_SUPPLEMENTS:
981 s = pool_tmpjoin(pool, multiple ? "they supplement " : "it supplements ", pool_dep2str(pool, dep), 0);
983 s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
985 case SOLVER_RULE_PKG_SAME_NAME:
986 return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, to), 0);
987 case SOLVER_RULE_PKG_CONFLICTS:
988 s = pool_tmpappend(pool, multiple ? "they conflict with " : "it conflicts with ", pool_dep2str(pool, dep), 0);
990 s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
992 case SOLVER_RULE_PKG_OBSOLETES:
993 s = pool_tmpappend(pool, multiple ? "they obsolete " : "it obsoletes ", pool_dep2str(pool, dep), 0);
995 s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
997 case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
998 s = pool_tmpjoin(pool, multiple ? "they are installed and obsolete " : "it is installed and obsoletes ", pool_dep2str(pool, dep), 0);
1000 s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
1002 case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
1003 s = pool_tmpjoin(pool, multiple ? "they implicitly obsolete " : "it implicitly obsoletes ", pool_dep2str(pool, dep), 0);
1005 s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
1007 case SOLVER_RULE_PKG_CONSTRAINS:
1008 s = pool_tmpappend(pool, multiple ? "they have constraint " : "it has constraint ", pool_dep2str(pool, dep), 0);
1010 s = pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, to));
1017 /* in some cases we can drop the "to" part if DMS_IDENTICAL_TO is set */
1018 if ((bits & DMS_IDENTICAL_TO) != 0)
1022 case SOLVER_RULE_PKG_SAME_NAME:
1023 return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, from), 0);
1024 case SOLVER_RULE_PKG_CONFLICTS:
1025 case SOLVER_RULE_PKG_OBSOLETES:
1026 case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
1027 case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
1028 case SOLVER_RULE_PKG_CONSTRAINS:
1029 bits &= ~DMS_IDENTICAL_TO;
1037 /* fallback to solver_ruleinfo2str if we can */
1038 if (multiple && (bits & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0)
1039 return "unsupported decision merge?";
1040 return solver_ruleinfo2str(solv, type, from, to, dep);
1044 solver_alternatives_count(Solver *solv)
1046 Id *elements = solv->branches.elements;
1048 for (res = 0, count = solv->branches.count; count; res++)
1049 count -= elements[count - 2];
1054 solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
1056 int cnt = solver_alternatives_count(solv);
1057 int count = solv->branches.count;
1058 Id *elements = solv->branches.elements;
1060 queue_empty(choices);
1061 if (alternative <= 0 || alternative > cnt)
1064 for (; cnt > alternative; cnt--)
1065 elements -= elements[-2];
1067 *levelp = elements[-1];
1069 *fromp = elements[-4];
1071 *idp = elements[-3];
1076 for (i = elements[-2]; i > 4; i--)
1078 Id p = -elements[-i];
1079 if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
1087 queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
1088 return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
1092 find_alternative_rule_from_learnt_rec(Solver *solv, int rid, Map *m, int cnt)
1094 Pool *pool = solv->pool;
1095 int why = solv->learnt_why.elements[rid - solv->learntrules];
1096 while ((rid = solv->learnt_pool.elements[why++]) != 0)
1098 Rule *r = solv->rules + rid;
1101 if (rid >= solv->learntrules)
1103 if ((rid = find_alternative_rule_from_learnt_rec(solv, rid, m, cnt)))
1108 FOR_RULELITERALS(p, pp, r)
1109 if (p > 0 && MAPTST(m, p))
1111 if (c == cnt) /* all bits hit */
1118 find_alternative_rule_from_learnt(Solver *solv, int rid)
1120 Pool *pool = solv->pool;
1123 Id *elements = solv->branches.elements;
1125 /* find alternative by rule id */
1126 for (count = solv->branches.count; count; count -= elements[count - 2])
1127 if (elements[count - 4] == 0 && elements[count - 3] == rid)
1131 map_init(&m, pool->nsolvables);
1133 for (i = count - elements[count - 2]; i < count - 4; i++)
1134 if (elements[i] > 0)
1136 MAPSET(&m, elements[i]);
1139 rid = find_alternative_rule_from_learnt_rec(solv, rid, &m, cnt);
1145 solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp)
1153 if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
1159 return SOLVER_RULE_PKG_RECOMMENDS;
1161 else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
1163 int rclass = solver_ruleclass(solv, id);
1164 if (rclass == SOLVER_RULE_LEARNT)
1166 id = find_alternative_rule_from_learnt(solv, id);
1168 return SOLVER_RULE_LEARNT;
1169 rclass = solver_ruleclass(solv, id);
1171 if (rclass == SOLVER_RULE_CHOICE || rclass == SOLVER_RULE_RECOMMENDS)
1172 id = solver_rule2pkgrule(solv, id);
1173 else if (rclass == SOLVER_RULE_BEST)
1175 Id info = solv->bestrules_info[id - solv->bestrules];
1181 return SOLVER_RULE_UPDATE;
1183 id = -info; /* best job, delegate to job rule */
1185 return solver_ruleinfo(solv, id, fromp, top, depp);
1191 solver_alternative2str(Solver *solv, int type, Id id, Id from)
1194 Pool *pool = solv->pool;
1196 type = solver_alternativeinfo(solv, type, id, from, &from, &to, &dep);
1199 case SOLVER_RULE_PKG_RECOMMENDS:
1200 s = pool_dep2str(pool, dep);
1202 s = pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
1204 case SOLVER_RULE_PKG_REQUIRES:
1205 s = pool_dep2str(pool, dep);
1207 s = pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, from));
1209 case SOLVER_RULE_PKG_CONFLICTS:
1210 s = pool_dep2str(pool, dep);
1212 s = pool_tmpappend(pool, s, ", conflicted by ", pool_solvid2str(pool, from));
1214 case SOLVER_RULE_YUMOBS:
1215 return pool_tmpjoin(pool, pool_id2str(pool, pool->solvables[to].name), ", obsoleting ", pool_dep2str(pool, dep));;
1216 case SOLVER_RULE_JOB:
1217 if ((to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES || (to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME)
1218 return pool_dep2str(pool, dep);
1219 return solver_select2str(pool, to & SOLVER_SELECTMASK, dep);
1220 case SOLVER_RULE_UPDATE:
1221 case SOLVER_RULE_FEATURE:
1222 return pool_solvid2str(pool, from);
1226 return solver_ruleinfo2str(solv, type, from, to, dep);