Fix helix2solv conflicts error
[platform/upstream/libsolv.git] / src / decision.c
1 /*
2  * Copyright (c) 2022, SUSE LLC
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * decision.c
10  *
11  * solver decision and alternative introspection code
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include "solver.h"
21 #include "solver_private.h"
22 #include "bitmap.h"
23 #include "pool.h"
24 #include "util.h"
25 #include "evr.h"
26
27 int
28 solver_get_decisionlevel(Solver *solv, Id p)
29 {
30   return solv->decisionmap[p];
31 }
32
33 void
34 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
35 {
36   queue_free(decisionq);
37   queue_init_clone(decisionq, &solv->decisionq);
38 }
39
40 int
41 solver_get_lastdecisionblocklevel(Solver *solv)
42 {
43   Id p;
44   if (solv->decisionq.count == 0)
45     return 0;
46   p = solv->decisionq.elements[solv->decisionq.count - 1];
47   if (p < 0)
48     p = -p;
49   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
50 }
51
52 void
53 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
54 {
55   Id p;
56   int i;
57
58   queue_empty(decisionq);
59   for (i = 0; i < solv->decisionq.count; i++)
60     {
61       p = solv->decisionq.elements[i];
62       if (p < 0)
63         p = -p;
64       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
65         break;
66     }
67   if (i == solv->decisionq.count)
68     return;
69   for (i = 0; i < solv->decisionq.count; i++)
70     {
71       p = solv->decisionq.elements[i];
72       if (p < 0)
73         p = -p;
74       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
75         queue_push(decisionq, p);
76       else
77         break;
78     }
79 }
80
81 /* return the reason and some extra info (i.e. a rule id) why
82  * a package was installed/conflicted */
83 int
84 solver_describe_decision(Solver *solv, Id p, Id *infop)
85 {
86   int i;
87   Id pp, why;
88
89   if (infop)
90     *infop = 0;
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)
96       break;
97   if (i == solv->decisionq.count)       /* just in case... */
98     return SOLVER_REASON_UNRELATED;
99   why = solv->decisionq_why.elements[i];
100   if (infop)
101     *infop = why >= 0 ? why : -why;
102   if (why > 0)
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];
106 }
107
108 /* create pseudo ruleinfo elements why a package was installed if
109  * the reason was SOLVER_REASON_WEAKDEP */
110 int
111 solver_allweakdepinfos(Solver *solv, Id p, Queue *whyq)
112 {
113   Pool *pool = solv->pool;
114   int i;
115   int level = solv->decisionmap[p];
116   int decisionno;
117   Solvable *s;
118
119   queue_empty(whyq);
120   if (level < 0)
121     return 0;   /* huh? */
122   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
123     if (solv->decisionq.elements[decisionno] == p)
124       break;
125   if (decisionno == solv->decisionq.count)
126     return 0;   /* huh? */
127   i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
128   if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
129     return 0;   /* huh? */
130
131   /* 1) list all packages that recommend us */
132   for (i = 1; i < pool->nsolvables; i++)
133     {
134       Id *recp, rec, pp2, p2;
135       if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
136         continue;
137       s = pool->solvables + i;
138       if (!s->recommends)
139         continue;
140       if (!solv->addalreadyrecommended && s->repo == solv->installed)
141         continue;
142       recp = s->repo->idarraydata + s->recommends;
143       while ((rec = *recp++) != 0)
144         {
145           int found = 0;
146           FOR_PROVIDES(p2, pp2, rec)
147             {
148               if (p2 == p)
149                 found = 1;
150               else
151                 {
152                   /* if p2 is already installed, this recommends is ignored */
153                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
154                     break;
155                 }
156             }
157           if (!p2 && found)
158             {
159               queue_push2(whyq, SOLVER_RULE_PKG_RECOMMENDS, i);
160               queue_push2(whyq, 0, rec);
161             }
162         }
163     }
164   /* 2) list all supplements */
165   s = pool->solvables + p;
166   if (s->supplements && level > 0)
167     {
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++ )
172         {
173           p2 = solv->decisionq.elements[i];
174           if (p2 > 0)
175             solv->decisionmap[p2] = -solv->decisionmap[p2];
176         }
177       supp = s->repo->idarraydata + s->supplements;
178       while ((sup = *supp++) != 0)
179         if (solver_dep_fulfilled(solv, sup))
180           {
181             int found = 0;
182             /* let's see if this is an easy supp */
183             FOR_PROVIDES(p2, pp2, sup)
184               {
185                 if (!solv->addalreadyrecommended && solv->installed)
186                   {
187                     if (pool->solvables[p2].repo == solv->installed)
188                       continue;
189                   }
190                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
191                   {
192                     queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
193                     queue_push2(whyq, p2, sup);
194                     found = 1;
195                   }
196               }
197             if (!found)
198               {
199                 /* hard case, just note dependency with no package */
200                 queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
201                 queue_push2(whyq, 0, sup);
202               }
203           }
204       for (i = decisionno; i < solv->decisionq.count; i++)
205         {
206           p2 = solv->decisionq.elements[i];
207           if (p2 > 0)
208             solv->decisionmap[p2] = -solv->decisionmap[p2];
209         }
210     }
211   return whyq->count / 4;
212 }
213
214 SolverRuleinfo
215 solver_weakdepinfo(Solver *solv, Id p, Id *fromp, Id *top, Id *depp)
216 {
217   Queue iq;
218   queue_init(&iq);
219   solver_allweakdepinfos(solv, p, &iq);
220   if (fromp)
221     *fromp = iq.count ? iq.elements[1] : 0;
222   if (top)
223     *top = iq.count ? iq.elements[2] : 0;
224   if (depp)
225     *depp = iq.count ? iq.elements[3] : 0;
226   return iq.count ? iq.elements[0] : SOLVER_RULE_UNKNOWN;
227 }
228
229 /* deprecated, use solver_allweakdepinfos instead */
230 void
231 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
232 {
233   int i, j;
234   solver_allweakdepinfos(solv, p, whyq);
235   for (i = j = 0; i < whyq->count; i += 4)
236     {
237       if (whyq->elements[i] == SOLVER_RULE_PKG_RECOMMENDS)
238         {
239           whyq->elements[j++] = SOLVER_REASON_RECOMMENDED;
240           whyq->elements[j++] = whyq->elements[i + 1];
241           whyq->elements[j++] = whyq->elements[i + 3];
242         }
243       else if (whyq->elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
244         {
245           whyq->elements[j++] = SOLVER_REASON_SUPPLEMENTED;
246           whyq->elements[j++] = whyq->elements[i + 2];
247           whyq->elements[j++] = whyq->elements[i + 3];
248         }
249     }
250   queue_truncate(whyq, j);
251 }
252
253 static int
254 decisionsort_cmp(const void *va, const void *vb, void *vd)
255 {
256   Solver *solv = vd;
257   Pool *pool = solv->pool;
258   const Id *a = va, *b = vb;    /* (decision, reason, rid, bits, type, from, to, dep) */
259   Solvable *as, *bs;
260   if (a[4] != b[4])     /* type */
261     return a[4] - b[4];
262   if (a[7] != b[7])     /* dep id */
263     return a[7] - b[7];
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)
269     {
270       int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
271       if (r)
272         return r;
273     }
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)
279     {
280       int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
281       if (r)
282         return r;
283     }
284   return 0;
285 }
286
287 static void
288 decisionmerge(Solver *solv, Queue *q)
289 {
290   Pool *pool = solv->pool;
291   int i, j;
292
293   for (i = 0; i < q->count; i += 8)
294     {
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)
300         {
301           int merged;
302           p = q->elements[j] >= 0 ? q->elements[j] : -q->elements[j];
303           if (reason != q->elements[j + 1] || name != pool->solvables[p].name)
304             break;
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]);
306           if (!merged)
307             break;
308           bits = merged;
309         }
310       j -= 8;
311       for (; i < j; i += 8)
312         q->elements[i + 3] = bits;
313     }
314 }
315
316 /* move a decison from position "from" to a smaller position "to" */
317 static inline void
318 move_decision(Queue *q, int to, int from)
319 {
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); 
323 }
324
325 /* sort a block of SOLVER_REASON_UNIT_RULE decisions */
326 static void
327 sort_unit_decisions(Solver *solv, Queue *q, int start, int end, Map *m)
328 {
329   Pool *pool = solv->pool;
330   int i, j, k, doing = 1;
331   if (start + 8 == end)
332     {
333       Id truelit = q->elements[start];
334       MAPSET(m, truelit >= 0 ? truelit : -truelit);
335       return;
336     }
337   /* alternate between conflicts and installs, starting with conflicts */
338   for (i = start; i < end; doing ^= 1)
339     {
340       for (j = k = i; j < end; j += 8)
341         {
342           Rule *or;
343           Id p, pp;
344           Id truelit = q->elements[j];
345           if ((doing == 0 && truelit < 0) || (doing != 0 && truelit >= 0))
346             continue;
347           or = solv->rules + q->elements[j + 2];
348           FOR_RULELITERALS(p, pp, or)
349             if (p != truelit && !MAPTST(m, p >= 0 ? p : -p))
350               break;
351           if (p)
352             continue;   /* not unit yet */
353           if (j > k)
354             move_decision(q, k, j);
355           k += 8;
356         }
357       if (k == i)
358         continue;
359       if (i + 8 < k)
360         solv_sort(q->elements + i, (k - i) / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
361       for (; i < k; i += 8)
362         {
363           Id truelit = q->elements[i];
364           MAPSET(m, truelit >= 0 ? truelit : -truelit);
365         }
366     }
367 }
368
369 static void
370 solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
371 {
372   Pool *pool = solv->pool;
373   Map seen, seent;      /* seent: was the literal true or false */
374   Id rid, truelit;
375   int first = 1;
376   int why, i, cnt;
377
378   queue_empty(q);
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];
383   else
384     return;
385   if (!solv->learnt_pool.elements[why])
386     return;
387
388   map_init(&seen, pool->nsolvables);
389   map_init(&seent, pool->nsolvables);
390   while ((rid = solv->learnt_pool.elements[why++]) != 0)
391     {
392       Rule *r = solv->rules + rid;
393       Id p, pp;
394       truelit = 0;
395       FOR_RULELITERALS(p, pp, r)
396         {
397           Id vv = p > 0 ? p : -p;
398           if (MAPTST(&seen, vv))
399             {
400               if ((p > 0 ? 1 : 0) == (MAPTST(&seent, vv) ? 1 : 0))
401                 {
402                   if (truelit)
403                     abort();
404                   truelit = p;          /* the one true literal! */
405                 }
406             }
407           else
408             {
409               /* a new literal. it must be false as the rule is unit */
410               MAPSET(&seen, vv);
411               if (p < 0)
412                 MAPSET(&seent, vv);
413             }
414         }
415       if (truelit)
416         queue_push(q, truelit);
417       else if (!first)
418         abort();
419       queue_push(q, rid);
420       first = 0;
421     }
422
423   /* add ruleinfo data to all rules (and also reverse the queue) */
424   cnt = q->count;
425   for (i = q->count - 1; i >= 0; i -= 2)
426     {
427       SolverRuleinfo type;
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)
432         {
433           /* use pkg ruleinfo for choice/recommends rules */
434           Id rid2 = solver_rule2pkgrule(solv, rid);
435           if (rid2)
436             type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
437         }
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;
446     }
447   queue_deleten(q, 0, cnt);
448
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)
451     {
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))
456         {
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;
461         }
462     }
463
464   /* put learnt rule premises in front */
465   MAPZERO(&seen);
466   MAPSET(&seen, 1);
467   i = 0;
468   if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE)
469     {
470       /* insert learnt prereqs at front */
471       Rule *r = solv->rules + id;
472       Id p, pp;
473       i = 0;
474       FOR_RULELITERALS(p, pp, r)
475         {
476           queue_insertn(q, i, 8, 0);
477           q->elements[i] = -p;
478           q->elements[i + 1] = SOLVER_REASON_PREMISE;
479           q->elements[i + 5] = p >= 0 ? p : -p;
480           MAPSET(&seen, p >= 0 ? p : -p);
481           i += 8;
482         }
483     }
484
485   if (flags & SOLVER_DECISIONLIST_SORTED)
486     {
487       /* sort premise block */
488       if (i > 8)
489         solv_sort(q->elements, i / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
490       sort_unit_decisions(solv, q, i, q->count - 8, &seen);
491     }
492
493   map_free(&seen);
494   map_free(&seent);
495
496   if (!(flags & SOLVER_DECISIONLIST_WITHINFO))
497     {
498       int j;
499       for (i = j = 0; i < q->count; i += 8)
500         {
501           q->elements[j++] = q->elements[i];
502           q->elements[j++] = q->elements[i + 1];
503           q->elements[j++] = q->elements[i + 2];
504         }
505       queue_truncate(q, j);
506     }
507   else
508     {
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);
514     }
515 }
516
517 void
518 solver_get_learnt(Solver *solv, Id id, int flags, Queue *q)
519 {
520   int why = -1;
521   Queue todo;
522
523   queue_empty(q);
524   queue_init(&todo);
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)
530     {
531       int i, j, cnt;
532       solver_get_decisionlist(solv, id, 0, &todo);
533       cnt = todo.count;
534       for (i = 0; i < cnt; i += 3)
535         {
536           int rid = todo.elements[i + 2];
537           if (rid < solv->learntrules || rid >= solv->nrules)
538             continue;
539           /* insert sorted and unified */
540           for (j = 0; j < q->count; j++)
541             {
542               if (q->elements[j] < rid)
543                 continue;
544               if (q->elements[j] == rid)
545                 rid = 0;
546               break;
547             }
548           if (!rid)
549             continue;   /* already in list */
550           queue_insert(q, j, rid);
551           queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
552         }
553       queue_deleten(&todo, 0, cnt);
554     }
555   else
556     {
557       queue_free(&todo);
558       return;
559     }
560   if (why >= 0)
561     queue_push(&todo, why);
562   while (todo.count)
563     {
564       int i, rid;
565       why = queue_pop(&todo);
566       while ((rid = solv->learnt_pool.elements[why++]) != 0)
567         {
568           if (rid < solv->learntrules || rid >= solv->nrules)
569             continue;
570           /* insert sorted and unified */
571           for (i = 0; i < q->count; i++)
572             {
573               if (q->elements[i] < rid)
574                 continue;
575               if (q->elements[i] == rid)
576                 rid = 0;
577               break;
578             }
579           if (!rid)
580             continue;   /* already in list */
581           queue_insert(q, i, rid);
582           queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
583         }
584     }
585   queue_free(&todo);
586 }
587
588 static void
589 getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
590 {
591   Pool *pool = solv->pool;
592   int i, ii, reason, info;
593   Queue iq;
594
595   queue_empty(decisionlistq);
596   if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
597     return;
598   queue_init(&iq);
599   for (ii = solv->decisionq.count - 1; ii > 0; ii--)
600     {
601       Id v = solv->decisionq.elements[ii];
602       Id vv = (v > 0 ? v : -v);
603       if (!MAPTST(dm, vv))
604         continue;
605       info = solv->decisionq_why.elements[ii];
606       if (info > 0)
607         reason = SOLVER_REASON_UNIT_RULE;
608       else if (info <= 0)
609         {
610           info = -info;
611           reason = solv->decisionmap[vv];
612           reason = solv->decisionq_reason.elements[reason >= 0 ? reason : -reason];
613         }
614       if (flags & (SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO))
615         {
616           queue_insertn(decisionlistq, 0, 5, 0);
617           if (reason == SOLVER_REASON_WEAKDEP)
618             {
619               solver_allweakdepinfos(solv, v, &iq);
620               if (iq.count)
621                 {
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];
626                 }
627             }
628           else if (info > 0)
629             {
630               Id from, to, dep;
631               int type = solver_ruleinfo(solv, info, &from, &to, &dep);
632               if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
633                 {
634                   /* use pkg ruleinfo for choice/recommends rules */
635                   Id rid2 = solver_rule2pkgrule(solv, info);
636                   if (rid2)
637                     type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
638                 }
639               decisionlistq->elements[1] = type;
640               decisionlistq->elements[2] = from;
641               decisionlistq->elements[3] = to;
642               decisionlistq->elements[4] = dep;
643             }
644         }
645       queue_unshift(decisionlistq, info);
646       queue_unshift(decisionlistq, reason);
647       queue_unshift(decisionlistq, v);
648       switch (reason)
649         {
650         case SOLVER_REASON_WEAKDEP:
651           if (v <= 0)
652             break;
653           solver_allweakdepinfos(solv, v, &iq);
654           for (i = 0; i < iq.count; i += 4)
655             {
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)
661                 {
662                   Id p2, pp2, id = iq.elements[i + 3];
663                   FOR_PROVIDES(p2, pp2, id)
664                     if (solv->decisionmap[p2] > 0)
665                       MAPSET(dm, p2);
666                 }
667             }
668           break;
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++)
674             {
675               Id p2 = iq.elements[i];
676               if (p2 < 0)
677                 MAPSET(dm, -p2);
678               else if (solv->decisionmap[p2] > 0)
679                 MAPSET(dm, p2);
680             }
681           break;
682         default:
683           break;
684         }
685     }
686   queue_free(&iq);
687   if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
688     {
689       /* reuse dm as "seen" map */
690       MAPZERO(dm);
691       MAPSET(dm, 1);
692       for (i = 0; i < decisionlistq->count; i += 8)
693         {
694           if (decisionlistq->elements[i + 1] != SOLVER_REASON_UNIT_RULE)
695             {
696               Id p = decisionlistq->elements[i] < 0 ? -decisionlistq->elements[i] : decisionlistq->elements[i];
697               MAPSET(dm, p);
698             }
699           else
700             {
701               int j;
702               for (j = i + 8; j < decisionlistq->count; j += 8)
703                 if (decisionlistq->elements[j + 1] != SOLVER_REASON_UNIT_RULE)
704                   break;
705               sort_unit_decisions(solv, decisionlistq, i, j, dm);
706             }
707         }
708     }
709   if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
710     {
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);
716     }
717   else if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
718     {
719       /* strip the info elements we added for sorting */
720       int j;
721       for (i = j = 0; i < decisionlistq->count; i += 8)
722         {
723           decisionlistq->elements[j++] = decisionlistq->elements[i];
724           decisionlistq->elements[j++] = decisionlistq->elements[i + 1];
725           decisionlistq->elements[j++] = decisionlistq->elements[i + 2];
726         }
727       queue_truncate(decisionlistq, j);
728     }
729 }
730
731 void
732 solver_get_decisionlist(Solver *solv, Id id, int flags, Queue *decisionlistq)
733 {
734   Pool *pool = solv->pool;
735   Map dm;
736   if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
737     return solver_get_proof(solv, id, flags, decisionlistq);
738   map_init(&dm, pool->nsolvables);
739   MAPSET(&dm, id);
740   getdecisionlist(solv, &dm, flags, decisionlistq);
741   map_free(&dm);
742   if (!decisionlistq->count)
743     {
744       queue_push(decisionlistq, -id);
745       queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
746       if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
747         {
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);
751         }
752     }
753 }
754
755 void
756 solver_get_decisionlist_multiple(Solver *solv, Queue *idq, int flags, Queue *decisionlistq)
757 {
758   Pool *pool = solv->pool;
759   int i;
760   Map dm;
761   queue_empty(decisionlistq);
762   if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
763     return;
764   map_init(&dm, pool->nsolvables);
765   for (i = 0; i < idq->count; i++)
766     {
767       Id p = idq->elements[i];
768       if (solv->decisionmap[p] != 0)
769         MAPSET(&dm, p);
770     }
771   getdecisionlist(solv, &dm, flags, decisionlistq);
772   map_free(&dm);
773   for (i = 0; i < idq->count; i++)
774     {
775       Id p = idq->elements[i];
776       if (solv->decisionmap[p] != 0)
777         continue;
778       queue_push(decisionlistq, -p);
779       queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
780       if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
781         {
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);
785         }
786     }
787 }
788
789
790 const char *
791 solver_reason2str(Solver *solv, int reason)
792 {
793   switch(reason)
794     {
795     case SOLVER_REASON_WEAKDEP:
796       return "a weak dependency";
797     case SOLVER_REASON_RESOLVE_JOB:
798       return "a job rule";
799     case SOLVER_REASON_RESOLVE:
800       return "a rule";
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:
812       return "unsolvable";
813     case SOLVER_REASON_PREMISE:
814       return "learnt rule premise";
815     case SOLVER_REASON_UNRELATED:
816       return "it is unrelated";
817     default:
818       break;
819     }
820   return "an unknown reason";
821 }
822
823 static const char *
824 decisionruleinfo2str(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
825 {
826   int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
827   return solver_decisioninfo2str(solv, bits, type, from, to, dep);
828 }
829
830 const char *
831 solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
832 {
833   if (reason == SOLVER_REASON_WEAKDEP && decision > 0)
834     {
835       Id from, to, dep;
836       int type = solver_weakdepinfo(solv, decision, &from, &to, &dep);
837       if (type)
838         return decisionruleinfo2str(solv, decision, type, from, to, dep);
839     }
840   if ((reason == SOLVER_REASON_RESOLVE_JOB || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE || reason == SOLVER_REASON_UNSOLVABLE) && info > 0)
841     {
842       Id from, to, dep;
843       int type = solver_ruleinfo(solv, info, &from, &to, &dep);
844       if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
845         {
846           Id rid2 = solver_rule2pkgrule(solv, info);
847           if (rid2)
848             {
849               type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
850               if (type)
851                 return decisionruleinfo2str(solv, decision, type, from, to, dep);
852             }
853         }
854       if (type)
855         return decisionruleinfo2str(solv, decision, type, from, to, dep);
856     }
857   return solver_reason2str(solv, reason);
858 }
859
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)
867
868 /* add some bits about the decision and the ruleinfo so we can join decisions */
869 int
870 solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
871 {
872   Id decisionpkg = decision >= 0 ? decision : -decision;
873   int bits = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0);
874   if (!decision)
875     return bits | DMS_NOMERGE;
876   switch (type)
877     {
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;
890       break;
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;
901       break;
902     default:
903       break;
904     }
905   return bits;
906 }
907
908 /* try to merge the ruleinfos of two decisions */
909 int
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)
911 {
912   int merged = 0;
913   if (type1 != type2 || dep1 != dep2)
914     return 0;
915   if (!bits1 || !bits2 || ((bits1 | bits2) & DMS_NOMERGE) != 0 || ((bits1 ^ bits2) & DMS_NEGATIVE) != 0)
916     return 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))
919     return 0;
920   if (((merged & DMS_IDENTICAL_FROM) == 0 && from1 != from2) || ((merged & DMS_IDENTICAL_TO) == 0 && to1 != to2))
921     return 0;
922   return merged;
923 }
924
925 void
926 solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q)
927 {
928   queue_empty(q);
929   for (; pos < decisionlistq->count; pos += 8)
930     {
931       Id p = decisionlistq->elements[pos];
932       queue_push(q, p > 0 ? p : -p);
933       if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
934         break;
935     }
936 }
937
938 int
939 solver_decisionlist_merged(Solver *solv, Queue *decisionlistq, int pos)
940 {
941   int cnt = 0;
942   for (; pos < decisionlistq->count; pos += 8, cnt++)
943     if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
944       break;
945   return cnt;
946 }
947
948 /* special version of solver_ruleinfo2str which supports merged decisions */
949 const char *
950 solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep)
951 {
952   Pool *pool = solv->pool;
953   const char *s;
954   int multiple = bits & DMS_MERGED;
955
956   /* use it/they variants if DMS_IDENTICAL_FROM is set */
957   if ((bits & DMS_IDENTICAL_FROM) != 0)
958     {
959       switch (type)
960         {
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";
973
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);
982           if (to)
983             s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
984           return s;
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);
989           if (to)
990             s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
991           return s;
992         case SOLVER_RULE_PKG_OBSOLETES:
993           s = pool_tmpappend(pool, multiple ? "they obsolete " : "it obsoletes ", pool_dep2str(pool, dep), 0);
994           if (to)
995             s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
996           return s;
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);
999           if (to)
1000             s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
1001           return s;
1002         case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
1003           s = pool_tmpjoin(pool, multiple ? "they implicitly obsolete " : "it implicitly obsoletes ", pool_dep2str(pool, dep), 0);
1004           if (to)
1005             s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
1006           return s;
1007         case SOLVER_RULE_PKG_CONSTRAINS:
1008           s = pool_tmpappend(pool, multiple ? "they have constraint " : "it has constraint ", pool_dep2str(pool, dep), 0);
1009           if (to)
1010             s = pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, to));
1011           return s;
1012         default:
1013           break;
1014         }
1015     }
1016
1017   /* in some cases we can drop the "to" part if DMS_IDENTICAL_TO is set */
1018   if ((bits & DMS_IDENTICAL_TO) != 0)
1019     {
1020       switch (type)
1021         {
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;
1030           to = 0;
1031           break;
1032         default:
1033           break;
1034         }
1035     }
1036
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);
1041 }
1042
1043 int
1044 solver_alternatives_count(Solver *solv)
1045 {
1046   Id *elements = solv->branches.elements;
1047   int res, count;
1048   for (res = 0, count = solv->branches.count; count; res++)
1049     count -= elements[count - 2];
1050   return res;
1051 }
1052
1053 int
1054 solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
1055 {
1056   int cnt = solver_alternatives_count(solv);
1057   int count = solv->branches.count;
1058   Id *elements = solv->branches.elements;
1059   if (choices)
1060     queue_empty(choices);
1061   if (alternative <= 0 || alternative > cnt)
1062     return 0;
1063   elements += count;
1064   for (; cnt > alternative; cnt--)
1065     elements -= elements[-2];
1066   if (levelp)
1067     *levelp = elements[-1];
1068   if (fromp)
1069     *fromp = elements[-4];
1070   if (idp)
1071     *idp = elements[-3];
1072   if (chosenp)
1073     {
1074       int i;
1075       *chosenp = 0;
1076       for (i = elements[-2]; i > 4; i--)
1077         {
1078           Id p = -elements[-i];
1079           if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
1080             {
1081               *chosenp = p;
1082               break;
1083             }
1084         }
1085     }
1086   if (choices)
1087     queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
1088   return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
1089 }
1090
1091 static int
1092 find_alternative_rule_from_learnt_rec(Solver *solv, int rid, Map *m, int cnt)
1093 {
1094   Pool *pool = solv->pool;
1095   int why = solv->learnt_why.elements[rid - solv->learntrules];
1096   while ((rid = solv->learnt_pool.elements[why++]) != 0)
1097     {
1098       Rule *r = solv->rules + rid;
1099       Id p, pp;
1100       int c;
1101       if (rid >= solv->learntrules)
1102         {
1103           if ((rid = find_alternative_rule_from_learnt_rec(solv, rid, m, cnt)))
1104             return rid;
1105           continue;
1106         }
1107       c = 0;
1108       FOR_RULELITERALS(p, pp, r)
1109         if (p > 0 && MAPTST(m, p))
1110           c++;
1111       if (c == cnt)     /* all bits hit */
1112         return rid;
1113     }
1114   return 0;
1115 }
1116
1117 static int
1118 find_alternative_rule_from_learnt(Solver *solv, int rid)
1119 {
1120   Pool *pool = solv->pool;
1121   Map m;
1122   int i, count, cnt;
1123   Id *elements = solv->branches.elements;
1124
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)
1128       break;
1129   if (!count)
1130     return 0;
1131   map_init(&m, pool->nsolvables);
1132   cnt = 0;
1133   for (i = count - elements[count - 2]; i < count - 4; i++)
1134     if (elements[i] > 0)
1135       {
1136         MAPSET(&m, elements[i]);
1137         cnt++;
1138       }
1139   rid = find_alternative_rule_from_learnt_rec(solv, rid, &m, cnt);
1140   map_free(&m);
1141   return rid;
1142 }
1143
1144 int
1145 solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp)
1146 {
1147   if (fromp)
1148     *fromp = 0;
1149   if (top)
1150     *top = 0;
1151   if (depp)
1152     *depp = 0;
1153   if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
1154     {
1155       if (fromp)
1156         *fromp = from;
1157       if (depp)
1158         *depp = id;
1159       return SOLVER_RULE_PKG_RECOMMENDS;
1160     }
1161   else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
1162     {
1163       int rclass = solver_ruleclass(solv, id);
1164       if (rclass == SOLVER_RULE_LEARNT)
1165         {
1166           id = find_alternative_rule_from_learnt(solv, id);
1167           if (!id)
1168             return SOLVER_RULE_LEARNT;
1169           rclass = solver_ruleclass(solv, id);
1170         }
1171       if (rclass == SOLVER_RULE_CHOICE || rclass == SOLVER_RULE_RECOMMENDS)
1172         id = solver_rule2pkgrule(solv, id);
1173       else if (rclass == SOLVER_RULE_BEST)
1174         {
1175           Id info = solv->bestrules_info[id - solv->bestrules];
1176           if (info > 0)
1177             {
1178               /* best update */
1179               if (fromp)
1180                 *fromp = info;
1181               return SOLVER_RULE_UPDATE;
1182             }
1183           id = -info;           /* best job, delegate to job rule */
1184         }
1185       return solver_ruleinfo(solv, id, fromp, top, depp);
1186     }
1187   return 0;
1188 }
1189
1190 const char *
1191 solver_alternative2str(Solver *solv, int type, Id id, Id from)
1192 {
1193   const char *s;
1194   Pool *pool = solv->pool;
1195   Id to, dep;
1196   type = solver_alternativeinfo(solv, type, id, from, &from, &to, &dep);
1197   switch (type)
1198     {
1199     case SOLVER_RULE_PKG_RECOMMENDS:
1200       s = pool_dep2str(pool, dep);
1201       if (from)
1202         s =  pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
1203       return s;
1204     case SOLVER_RULE_PKG_REQUIRES:
1205       s = pool_dep2str(pool, dep);
1206       if (from)
1207         s =  pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, from));
1208       return s;
1209     case SOLVER_RULE_PKG_CONFLICTS:
1210       s = pool_dep2str(pool, dep);
1211       if (from)
1212         s =  pool_tmpappend(pool, s, ", conflicted by  ", pool_solvid2str(pool, from));
1213       return s;
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);
1223     default:
1224       break;
1225     }
1226   return solver_ruleinfo2str(solv, type, from, to, dep);
1227 }
1228