don't free obsoletes/obsoetes_data in solver cleanup
[platform/upstream/libsolv.git] / src / solver.c
1 /*
2  * Copyright (c) 2007-2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solver.c
10  *
11  * SAT based dependency solver
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 "policy.h"
26 #include "poolarch.h"
27 #include "solverdebug.h"
28
29 #define RULES_BLOCK 63
30
31 /********************************************************************
32  *
33  * dependency check helpers
34  *
35  */
36
37 /*-------------------------------------------------------------------
38  * handle split provides
39  *
40  * a splitprovides dep looks like
41  *     namespace:splitprovides(pkg REL_WITH path)
42  * and is only true if pkg is installed and contains the specified path.
43  * we also make sure that pkg is selected for an update, otherwise the
44  * update would always be forced onto the user.
45  */
46 int
47 solver_splitprovides(Solver *solv, Id dep)
48 {
49   Pool *pool = solv->pool;
50   Id p, pp;
51   Reldep *rd;
52   Solvable *s;
53
54   if (!solv->dosplitprovides || !solv->installed || (!solv->updatemap_all && !solv->updatemap.size))
55     return 0;
56   if (!ISRELDEP(dep))
57     return 0;
58   rd = GETRELDEP(pool, dep);
59   if (rd->flags != REL_WITH)
60     return 0;
61   FOR_PROVIDES(p, pp, dep)
62     {
63       /* here we have packages that provide the correct name and contain the path,
64        * now do extra filtering */
65       s = pool->solvables + p;
66       if (s->repo == solv->installed && s->name == rd->name &&
67           (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
68         return 1;
69     }
70   return 0;
71 }
72
73
74 /*-------------------------------------------------------------------
75  * solver_dep_installed
76  */
77
78 int
79 solver_dep_installed(Solver *solv, Id dep)
80 {
81 #if 0
82   Pool *pool = solv->pool;
83   Id p, pp;
84
85   if (ISRELDEP(dep))
86     {
87       Reldep *rd = GETRELDEP(pool, dep);
88       if (rd->flags == REL_AND)
89         {
90           if (!solver_dep_installed(solv, rd->name))
91             return 0;
92           return solver_dep_installed(solv, rd->evr);
93         }
94       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
95         return solver_dep_installed(solv, rd->evr);
96     }
97   FOR_PROVIDES(p, pp, dep)
98     {
99       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
100         return 1;
101     }
102 #endif
103   return 0;
104 }
105
106 /* mirrors solver_dep_installed, but returns 2 if a
107  * dependency listed in solv->installsuppdepq was involved */
108 static int
109 solver_check_installsuppdepq_dep(Solver *solv, Id dep)
110 {
111   Pool *pool = solv->pool;
112   Id p, pp;
113   Queue *q;
114
115   if (ISRELDEP(dep))
116     {
117       Reldep *rd = GETRELDEP(pool, dep);
118       if (rd->flags == REL_AND)
119         {
120           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
121           if (!r1)
122             return 0;
123           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
124           if (!r2)
125             return 0;
126           return r1 == 2 || r2 == 2 ? 2 : 1;
127         }
128       if (rd->flags == REL_OR)
129         {
130           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
131           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
132           if (!r1 && !r2)
133             return 0;
134           return r1 == 2 || r2 == 2 ? 2 : 1;
135         }
136       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
137         return solver_splitprovides(solv, rd->evr);
138       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
139         return solver_dep_installed(solv, rd->evr);
140       if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
141         {
142           int i;
143           for (i = 0; i < q->count; i++)
144             if (q->elements[i] == dep || q->elements[i] == rd->name)
145               return 2;
146         }
147     }
148   FOR_PROVIDES(p, pp, dep)
149     if (solv->decisionmap[p] > 0)
150       return 1;
151   return 0;
152 }
153
154 static int
155 solver_check_installsuppdepq(Solver *solv, Solvable *s)
156 {
157   Id sup, *supp;
158   supp = s->repo->idarraydata + s->supplements;
159   while ((sup = *supp++) != 0)
160     if (solver_check_installsuppdepq_dep(solv, sup) == 2)
161       return 1;
162   return 0;
163 }
164
165 static Id
166 autouninstall(Solver *solv, Id *problem)
167 {
168   Pool *pool = solv->pool;
169   int i;
170   int lastfeature = 0, lastupdate = 0;
171   Id v;
172   Id extraflags = -1;
173
174   for (i = 0; (v = problem[i]) != 0; i++)
175     {
176       if (v < 0)
177         extraflags &= solv->job.elements[-v - 1];
178       if (v >= solv->featurerules && v < solv->featurerules_end)
179         if (v > lastfeature)
180           lastfeature = v;
181       if (v >= solv->updaterules && v < solv->updaterules_end)
182         {
183           /* check if identical to feature rule */
184           Id p = solv->rules[v].p;
185           if (p <= 0)
186             continue;
187           Rule *r = solv->rules + solv->featurerules + (p - solv->installed->start);
188           if (!r->p)
189             {
190               /* update rule == feature rule */
191               if (v > lastfeature)
192                 lastfeature = v;
193               continue;
194             }
195           if (v > lastupdate)
196             lastupdate = v;
197         }
198     }
199   if (!lastupdate && !lastfeature)
200     return 0;
201   v = lastupdate ? lastupdate : lastfeature;
202   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
203   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
204   solver_disableproblem(solv, v);
205   if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
206     {
207       /* add the package to the updatepkgs list, this will automatically turn
208        * on cleandeps mode */
209       Id p = solv->rules[v].p;
210       if (!solv->cleandeps_updatepkgs)
211         {
212           solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
213           queue_init(solv->cleandeps_updatepkgs);
214         }
215       if (p > 0)
216         {
217           int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
218           queue_pushunique(solv->cleandeps_updatepkgs, p);
219           if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
220             solver_disablepolicyrules(solv);
221         }
222     }
223   return v;
224 }
225
226 /************************************************************************/
227
228 /*
229  * enable/disable learnt rules 
230  *
231  * we have enabled or disabled some of our rules. We now reenable all
232  * of our learnt rules except the ones that were learnt from rules that
233  * are now disabled.
234  */
235 static void
236 enabledisablelearntrules(Solver *solv)
237 {
238   Pool *pool = solv->pool;
239   Rule *r;
240   Id why, *whyp;
241   int i;
242
243   POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
244   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
245     {
246       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
247       while ((why = *whyp++) != 0)
248         {
249           assert(why > 0 && why < i);
250           if (solv->rules[why].d < 0)
251             break;
252         }
253       /* why != 0: we found a disabled rule, disable the learnt rule */
254       if (why && r->d >= 0)
255         {
256           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
257             {
258               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
259               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
260             }
261           solver_disablerule(solv, r);
262         }
263       else if (!why && r->d < 0)
264         {
265           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
266             {
267               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
268               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
269             }
270           solver_enablerule(solv, r);
271         }
272     }
273 }
274
275
276 /*
277  * make assertion rules into decisions
278  * 
279  * Go through rules and add direct assertions to the decisionqueue.
280  * If we find a conflict, disable rules and add them to problem queue.
281  */
282
283 static void
284 makeruledecisions(Solver *solv)
285 {
286   Pool *pool = solv->pool;
287   int i, ri, ii;
288   Rule *r, *rr;
289   Id v, vv;
290   int decisionstart;
291   int record_proof = 1;
292   int oldproblemcount;
293   int havedisabled = 0;
294
295   /* The system solvable is always installed first */
296   assert(solv->decisionq.count == 0);
297   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
298   queue_push(&solv->decisionq_why, 0);
299   solv->decisionmap[SYSTEMSOLVABLE] = 1;        /* installed at level '1' */
300
301   decisionstart = solv->decisionq.count;
302   for (;;)
303     {
304       /* if we needed to re-run, back up decisions to decisionstart */
305       while (solv->decisionq.count > decisionstart)
306         {
307           v = solv->decisionq.elements[--solv->decisionq.count];
308           --solv->decisionq_why.count;
309           vv = v > 0 ? v : -v;
310           solv->decisionmap[vv] = 0;
311         }
312
313       /* note that the ruleassertions queue is ordered */
314       for (ii = 0; ii < solv->ruleassertions.count; ii++)
315         {
316           ri = solv->ruleassertions.elements[ii];
317           r = solv->rules + ri;
318             
319           if (havedisabled && ri >= solv->learntrules)
320             {
321               /* just started with learnt rule assertions. If we have disabled
322                * some rules, adapt the learnt rule status */
323               enabledisablelearntrules(solv);
324               havedisabled = 0;
325             }
326             
327           if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
328             continue;
329
330           /* do weak rules in phase 2 */
331           if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
332             continue;
333
334           v = r->p;
335           vv = v > 0 ? v : -v;
336             
337           if (!solv->decisionmap[vv])          /* if not yet decided */
338             {
339               queue_push(&solv->decisionq, v);
340               queue_push(&solv->decisionq_why, r - solv->rules);
341               solv->decisionmap[vv] = v > 0 ? 1 : -1;
342               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
343                 {
344                   Solvable *s = solv->pool->solvables + vv;
345                   if (v < 0)
346                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
347                   else
348                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
349                 }
350               continue;
351             }
352
353           /* check against previous decision: is there a conflict? */
354           if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
355             continue;
356           if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
357             continue;
358             
359           /*
360            * found a conflict!
361            * 
362            * The rule (r) we're currently processing says something
363            * different (v = r->p) than a previous decision (decisionmap[abs(v)])
364            * on this literal
365            */
366             
367           if (ri >= solv->learntrules)
368             {
369               /* conflict with a learnt rule */
370               /* can happen when packages cannot be installed for multiple reasons. */
371               /* we disable the learnt rule in this case */
372               /* (XXX: we should really call analyze_unsolvable_rule here!) */
373               solver_disablerule(solv, r);
374               continue;
375             }
376             
377           /*
378            * find the decision which is the "opposite" of the rule
379            */
380           for (i = 0; i < solv->decisionq.count; i++)
381             if (solv->decisionq.elements[i] == -v)
382               break;
383           assert(i < solv->decisionq.count);         /* assert that we found it */
384           oldproblemcount = solv->problems.count;
385             
386           /*
387            * conflict with system solvable ?
388            */
389           if (v == -SYSTEMSOLVABLE)
390             {
391               if (record_proof)
392                 {
393                   queue_push(&solv->problems, solv->learnt_pool.count);
394                   queue_push(&solv->learnt_pool, ri);
395                   queue_push(&solv->learnt_pool, 0);
396                 }
397               else
398                 queue_push(&solv->problems, 0);
399               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
400               if  (ri >= solv->jobrules && ri < solv->jobrules_end)
401                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
402               else
403                 v = ri;
404               queue_push(&solv->problems, v);
405               queue_push(&solv->problems, 0);
406               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
407                 solv->problems.count = oldproblemcount;
408               solver_disableproblem(solv, v);
409               havedisabled = 1;
410               break;    /* start over */
411             }
412
413           assert(solv->decisionq_why.elements[i] > 0);
414
415           /*
416            * conflict with an rpm rule ?
417            */
418           if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
419             {
420               if (record_proof)
421                 {
422                   queue_push(&solv->problems, solv->learnt_pool.count);
423                   queue_push(&solv->learnt_pool, ri);
424                   queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
425                   queue_push(&solv->learnt_pool, 0);
426                 }
427               else
428                 queue_push(&solv->problems, 0);
429               assert(v > 0 || v == -SYSTEMSOLVABLE);
430               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
431               if (ri >= solv->jobrules && ri < solv->jobrules_end)
432                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
433               else
434                 v = ri;
435               queue_push(&solv->problems, v);
436               queue_push(&solv->problems, 0);
437               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
438                 solv->problems.count = oldproblemcount;
439               solver_disableproblem(solv, v);
440               havedisabled = 1;
441               break;    /* start over */
442             }
443
444           /*
445            * conflict with another job or update/feature rule
446            */
447             
448           /* record proof */
449           if (record_proof)
450             {
451               queue_push(&solv->problems, solv->learnt_pool.count);
452               queue_push(&solv->learnt_pool, ri);
453               queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
454               queue_push(&solv->learnt_pool, 0);
455             }
456           else
457             queue_push(&solv->problems, 0);
458
459           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
460
461           /*
462            * push all of our rules (can only be feature or job rules)
463            * asserting this literal on the problem stack
464            */
465           for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
466             {
467               if (rr->d < 0                          /* disabled */
468                   || rr->w2)                         /*  or no assertion */
469                 continue;
470               if (rr->p != vv                        /* not affecting the literal */
471                   && rr->p != -vv)
472                 continue;
473               if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
474                 continue;
475                 
476               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
477               solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
478                 
479               v = i;
480               if (i >= solv->jobrules && i < solv->jobrules_end)
481                 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
482               queue_push(&solv->problems, v);
483             }
484           queue_push(&solv->problems, 0);
485
486           if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
487             solv->problems.count = oldproblemcount;
488
489           for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
490             solver_disableproblem(solv, solv->problems.elements[i]);
491           havedisabled = 1;
492           break;        /* start over */
493         }
494       if (ii < solv->ruleassertions.count)
495         continue;
496
497       /*
498        * phase 2: now do the weak assertions
499        */
500       for (ii = 0; ii < solv->ruleassertions.count; ii++)
501         {
502           ri = solv->ruleassertions.elements[ii];
503           r = solv->rules + ri;
504           if (r->d < 0 || r->w2)                         /* disabled or no assertion */
505             continue;
506           if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
507             continue;
508           v = r->p;
509           vv = v > 0 ? v : -v;
510
511           if (!solv->decisionmap[vv])          /* if not yet decided */
512             {
513               queue_push(&solv->decisionq, v);
514               queue_push(&solv->decisionq_why, r - solv->rules);
515               solv->decisionmap[vv] = v > 0 ? 1 : -1;
516               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
517                 {
518                   Solvable *s = solv->pool->solvables + vv;
519                   if (v < 0)
520                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
521                   else
522                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
523                 }
524               continue;
525             }
526           /* check against previous decision: is there a conflict? */
527           if (v > 0 && solv->decisionmap[vv] > 0)
528             continue;
529           if (v < 0 && solv->decisionmap[vv] < 0)
530             continue;
531             
532           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
533           solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
534
535           if (ri >= solv->jobrules && ri < solv->jobrules_end)
536             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
537           else
538             v = ri;
539           solver_disableproblem(solv, v);
540           if (v < 0)
541             solver_reenablepolicyrules(solv, -v);
542           havedisabled = 1;
543           break;        /* start over */
544         }
545       if (ii == solv->ruleassertions.count)
546         break;  /* finished! */
547     }
548 }
549
550
551 /********************************************************************/
552 /* watches */
553
554
555 /*-------------------------------------------------------------------
556  * makewatches
557  *
558  * initial setup for all watches
559  */
560
561 static void
562 makewatches(Solver *solv)
563 {
564   Rule *r;
565   int i;
566   int nsolvables = solv->pool->nsolvables;
567
568   solv_free(solv->watches);
569                                        /* lower half for removals, upper half for installs */
570   solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
571 #if 1
572   /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
573   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
574 #else
575   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
576 #endif
577     {
578       if (!r->w2)               /* assertions do not need watches */
579         continue;
580
581       /* see addwatches_rule(solv, r) */
582       r->n1 = solv->watches[nsolvables + r->w1];
583       solv->watches[nsolvables + r->w1] = r - solv->rules;
584
585       r->n2 = solv->watches[nsolvables + r->w2];
586       solv->watches[nsolvables + r->w2] = r - solv->rules;
587     }
588 }
589
590
591 /*-------------------------------------------------------------------
592  *
593  * add watches (for a new learned rule)
594  * sets up watches for a single rule
595  * 
596  * see also makewatches() above.
597  */
598
599 static inline void
600 addwatches_rule(Solver *solv, Rule *r)
601 {
602   int nsolvables = solv->pool->nsolvables;
603
604   r->n1 = solv->watches[nsolvables + r->w1];
605   solv->watches[nsolvables + r->w1] = r - solv->rules;
606
607   r->n2 = solv->watches[nsolvables + r->w2];
608   solv->watches[nsolvables + r->w2] = r - solv->rules;
609 }
610
611
612 /********************************************************************/
613 /*
614  * rule propagation
615  */
616
617
618 /* shortcuts to check if a literal (positive or negative) assignment
619  * evaluates to 'true' or 'false'
620  */
621 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
622 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
623 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
624
625 /*-------------------------------------------------------------------
626  * 
627  * propagate
628  *
629  * make decision and propagate to all rules
630  * 
631  * Evaluate each term affected by the decision (linked through watches).
632  * If we find unit rules we make new decisions based on them.
633  * 
634  * return : 0 = everything is OK
635  *          rule = conflict found in this rule
636  */
637
638 static Rule *
639 propagate(Solver *solv, int level)
640 {
641   Pool *pool = solv->pool;
642   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
643   Rule *r;                    /* rule */
644   Id p, pkg, other_watch;
645   Id *dp;
646   Id *decisionmap = solv->decisionmap;
647     
648   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
649
650   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
651
652   /* foreach non-propagated decision */
653   while (solv->propagate_index < solv->decisionq.count)
654     {
655         /*
656          * 'pkg' was just decided
657          * negate because our watches trigger if literal goes FALSE
658          */
659       pkg = -solv->decisionq.elements[solv->propagate_index++];
660         
661       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
662         {
663           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
664           solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
665         }
666
667       /* foreach rule where 'pkg' is now FALSE */
668       for (rp = watches + pkg; *rp; rp = next_rp)
669         {
670           r = solv->rules + *rp;
671           if (r->d < 0)
672             {
673               /* rule is disabled, goto next */
674               if (pkg == r->w1)
675                 next_rp = &r->n1;
676               else
677                 next_rp = &r->n2;
678               continue;
679             }
680
681           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
682             {
683               POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
684               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
685             }
686
687             /* 'pkg' was just decided (was set to FALSE)
688              * 
689              *  now find other literal watch, check clause
690              *   and advance on linked list
691              */
692           if (pkg == r->w1)
693             {
694               other_watch = r->w2;
695               next_rp = &r->n1;
696             }
697           else
698             {
699               other_watch = r->w1;
700               next_rp = &r->n2;
701             }
702             
703             /* 
704              * This term is already true (through the other literal)
705              * so we have nothing to do
706              */
707           if (DECISIONMAP_TRUE(other_watch))
708             continue;
709
710             /*
711              * The other literal is FALSE or UNDEF
712              * 
713              */
714             
715           if (r->d)
716             {
717               /* Not a binary clause, try to move our watch.
718                * 
719                * Go over all literals and find one that is
720                *   not other_watch
721                *   and not FALSE
722                * 
723                * (TRUE is also ok, in that case the rule is fulfilled)
724                */
725               if (r->p                                /* we have a 'p' */
726                   && r->p != other_watch              /* which is not watched */
727                   && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
728                 {
729                   p = r->p;
730                 }
731               else                                    /* go find a 'd' to make 'true' */
732                 {
733                   /* foreach p in 'd'
734                      we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
735                    */
736                   for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
737                     {
738                       if (p != other_watch              /* which is not watched */
739                           && !DECISIONMAP_FALSE(p))     /* and not FALSE */
740                         break;
741                     }
742                 }
743
744               if (p)
745                 {
746                   /*
747                    * if we found some p that is UNDEF or TRUE, move
748                    * watch to it
749                    */
750                   IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
751                     {
752                       if (p > 0)
753                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
754                       else
755                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
756                     }
757                     
758                   *rp = *next_rp;
759                   next_rp = rp;
760                     
761                   if (pkg == r->w1)
762                     {
763                       r->w1 = p;
764                       r->n1 = watches[p];
765                     }
766                   else
767                     {
768                       r->w2 = p;
769                       r->n2 = watches[p];
770                     }
771                   watches[p] = r - solv->rules;
772                   continue;
773                 }
774               /* search failed, thus all unwatched literals are FALSE */
775                 
776             } /* not binary */
777             
778           /*
779            * unit clause found, set literal other_watch to TRUE
780            */
781
782           if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
783             return r;                              /* eek, a conflict! */
784             
785           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
786             {
787               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "   unit ");
788               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
789             }
790
791           if (other_watch > 0)
792             decisionmap[other_watch] = level;    /* install! */
793           else
794             decisionmap[-other_watch] = -level;  /* remove! */
795             
796           queue_push(&solv->decisionq, other_watch);
797           queue_push(&solv->decisionq_why, r - solv->rules);
798
799           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
800             {
801               if (other_watch > 0)
802                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
803               else
804                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
805             }
806             
807         } /* foreach rule involving 'pkg' */
808         
809     } /* while we have non-decided decisions */
810     
811   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
812
813   return 0;     /* all is well */
814 }
815
816
817 /********************************************************************/
818 /* Analysis */
819
820 /*-------------------------------------------------------------------
821  * 
822  * analyze
823  *   and learn
824  */
825
826 static int
827 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
828 {
829   Pool *pool = solv->pool;
830   Queue r;
831   Id r_buf[4];
832   int rlevel = 1;
833   Map seen;             /* global? */
834   Id d, v, vv, *dp, why;
835   int l, i, idx;
836   int num = 0, l1num = 0;
837   int learnt_why = solv->learnt_pool.count;
838   Id *decisionmap = solv->decisionmap;
839
840   queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
841
842   POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
843   map_init(&seen, pool->nsolvables);
844   idx = solv->decisionq.count;
845   for (;;)
846     {
847       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
848         solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
849       queue_push(&solv->learnt_pool, c - solv->rules);
850       d = c->d < 0 ? -c->d - 1 : c->d;
851       dp = d ? pool->whatprovidesdata + d : 0;
852       /* go through all literals of the rule */
853       for (i = -1; ; i++)
854         {
855           if (i == -1)
856             v = c->p;
857           else if (d == 0)
858             v = i ? 0 : c->w2;
859           else
860             v = *dp++;
861           if (v == 0)
862             break;
863
864           if (DECISIONMAP_TRUE(v))      /* the one true literal */
865             continue;
866           vv = v > 0 ? v : -v;
867           if (MAPTST(&seen, vv))
868             continue;
869           l = solv->decisionmap[vv];
870           if (l < 0)
871             l = -l;
872           MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
873           if (l == 1)
874             l1num++;                    /* need to do this one in level1 pass */
875           else if (l == level)
876             num++;                      /* need to do this one as well */
877           else
878             {
879               queue_push(&r, v);        /* not level1 or conflict level, add to new rule */
880               if (l > rlevel)
881                 rlevel = l;
882             }
883         }
884 l1retry:
885       if (!num && !--l1num)
886         break;  /* all level 1 literals done */
887
888       /* find the next literal to investigate */
889       /* (as num + l1num > 0, we know that we'll always find one) */
890       for (;;)
891         {
892           assert(idx > 0);
893           v = solv->decisionq.elements[--idx];
894           vv = v > 0 ? v : -v;
895           if (MAPTST(&seen, vv))
896             break;
897         }
898       MAPCLR(&seen, vv);
899
900       if (num && --num == 0)
901         {
902           *pr = -v;     /* so that v doesn't get lost */
903           if (!l1num)
904             break;
905           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
906           /* clear non-l1 bits from seen map */
907           for (i = 0; i < r.count; i++)
908             {
909               v = r.elements[i];
910               MAPCLR(&seen, v > 0 ? v : -v);
911             }
912           /* only level 1 marks left in seen map */
913           l1num++;      /* as l1retry decrements it */
914           goto l1retry;
915         }
916
917       why = solv->decisionq_why.elements[idx];
918       if (why <= 0)     /* just in case, maybe for SYSTEMSOLVABLE */
919         goto l1retry;
920       c = solv->rules + why;
921     }
922   map_free(&seen);
923
924   if (r.count == 0)
925     *dr = 0;
926   else if (r.count == 1 && r.elements[0] < 0)
927     *dr = r.elements[0];
928   else
929     *dr = pool_queuetowhatprovides(pool, &r);
930   IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
931     {
932       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
933       solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
934       for (i = 0; i < r.count; i++)
935         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
936     }
937   /* push end marker on learnt reasons stack */
938   queue_push(&solv->learnt_pool, 0);
939   if (whyp)
940     *whyp = learnt_why;
941   queue_free(&r);
942   solv->stats_learned++;
943   return rlevel;
944 }
945
946
947 /*-------------------------------------------------------------------
948  * 
949  * solver_reset
950  * 
951  * reset all solver decisions
952  * called after rules have been enabled/disabled
953  */
954
955 void
956 solver_reset(Solver *solv)
957 {
958   Pool *pool = solv->pool;
959   int i;
960   Id v;
961
962   /* rewind all decisions */
963   for (i = solv->decisionq.count - 1; i >= 0; i--)
964     {
965       v = solv->decisionq.elements[i];
966       solv->decisionmap[v > 0 ? v : -v] = 0;
967     }
968   solv->decisionq_why.count = 0;
969   solv->decisionq.count = 0;
970   solv->recommends_index = -1;
971   solv->propagate_index = 0;
972   solv->branches.count = 0;
973
974   /* adapt learnt rule status to new set of enabled/disabled rules */
975   enabledisablelearntrules(solv);
976
977   /* redo all assertion rule decisions */
978   makeruledecisions(solv);
979   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
980 }
981
982
983 /*-------------------------------------------------------------------
984  * 
985  * analyze_unsolvable_rule
986  *
987  * recursion helper used by analyze_unsolvable
988  */
989
990 static void
991 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
992 {
993   Pool *pool = solv->pool;
994   int i;
995   Id why = r - solv->rules;
996
997   IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
998     solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
999   if (solv->learntrules && why >= solv->learntrules)
1000     {
1001       if (MAPTST(rseen, why - solv->learntrules))
1002         return;
1003       MAPSET(rseen, why - solv->learntrules);
1004       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1005         if (solv->learnt_pool.elements[i] > 0)
1006           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
1007       return;
1008     }
1009   if (MAPTST(&solv->weakrulemap, why))
1010     if (!*lastweakp || why > *lastweakp)
1011       *lastweakp = why;
1012   /* do not add rpm rules to problem */
1013   if (why < solv->rpmrules_end)
1014     return;
1015   /* turn rule into problem */
1016   if (why >= solv->jobrules && why < solv->jobrules_end)
1017     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1018   /* normalize dup/infarch rules */
1019   if (why > solv->infarchrules && why < solv->infarchrules_end)
1020     {
1021       Id name = pool->solvables[-solv->rules[why].p].name;
1022       while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
1023         why--;
1024     }
1025   if (why > solv->duprules && why < solv->duprules_end)
1026     {
1027       Id name = pool->solvables[-solv->rules[why].p].name;
1028       while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
1029         why--;
1030     }
1031
1032   /* return if problem already countains our rule */
1033   if (solv->problems.count)
1034     {
1035       for (i = solv->problems.count - 1; i >= 0; i--)
1036         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1037           break;
1038         else if (solv->problems.elements[i] == why)
1039           return;
1040     }
1041   queue_push(&solv->problems, why);
1042 }
1043
1044
1045 /*-------------------------------------------------------------------
1046  * 
1047  * analyze_unsolvable
1048  *
1049  * We know that the problem is not solvable. Record all involved
1050  * rules (i.e. the "proof") into solv->learnt_pool.
1051  * Record the learnt pool index and all non-rpm rules into
1052  * solv->problems. (Our solutions to fix the problems are to
1053  * disable those rules.)
1054  *
1055  * If the proof contains at least one weak rule, we disable the
1056  * last of them.
1057  *
1058  * Otherwise we return 0 if disablerules is not set or disable
1059  * _all_ of the problem rules and return 1.
1060  *
1061  * return: 1 - disabled some rules, try again
1062  *         0 - hopeless
1063  */
1064
1065 static int
1066 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1067 {
1068   Pool *pool = solv->pool;
1069   Rule *r;
1070   Map seen;             /* global to speed things up? */
1071   Map rseen;
1072   Id d, v, vv, *dp, why;
1073   int l, i, idx;
1074   Id *decisionmap = solv->decisionmap;
1075   int oldproblemcount;
1076   int oldlearntpoolcount;
1077   Id lastweak;
1078   int record_proof = 1;
1079
1080   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1081   solv->stats_unsolvable++;
1082   oldproblemcount = solv->problems.count;
1083   oldlearntpoolcount = solv->learnt_pool.count;
1084
1085   /* make room for proof index */
1086   /* must update it later, as analyze_unsolvable_rule would confuse
1087    * it with a rule index if we put the real value in already */
1088   queue_push(&solv->problems, 0);
1089
1090   r = cr;
1091   map_init(&seen, pool->nsolvables);
1092   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1093   if (record_proof)
1094     queue_push(&solv->learnt_pool, r - solv->rules);
1095   lastweak = 0;
1096   analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1097   d = r->d < 0 ? -r->d - 1 : r->d;
1098   dp = d ? pool->whatprovidesdata + d : 0;
1099   for (i = -1; ; i++)
1100     {
1101       if (i == -1)
1102         v = r->p;
1103       else if (d == 0)
1104         v = i ? 0 : r->w2;
1105       else
1106         v = *dp++;
1107       if (v == 0)
1108         break;
1109       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1110           continue;
1111       vv = v > 0 ? v : -v;
1112       l = solv->decisionmap[vv];
1113       if (l < 0)
1114         l = -l;
1115       MAPSET(&seen, vv);
1116     }
1117   idx = solv->decisionq.count;
1118   while (idx > 0)
1119     {
1120       v = solv->decisionq.elements[--idx];
1121       vv = v > 0 ? v : -v;
1122       if (!MAPTST(&seen, vv))
1123         continue;
1124       why = solv->decisionq_why.elements[idx];
1125       assert(why > 0);
1126       if (record_proof)
1127         queue_push(&solv->learnt_pool, why);
1128       r = solv->rules + why;
1129       analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1130       d = r->d < 0 ? -r->d - 1 : r->d;
1131       dp = d ? pool->whatprovidesdata + d : 0;
1132       for (i = -1; ; i++)
1133         {
1134           if (i == -1)
1135             v = r->p;
1136           else if (d == 0)
1137             v = i ? 0 : r->w2;
1138           else
1139             v = *dp++;
1140           if (v == 0)
1141             break;
1142           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1143               continue;
1144           vv = v > 0 ? v : -v;
1145           l = solv->decisionmap[vv];
1146           if (l < 0)
1147             l = -l;
1148           MAPSET(&seen, vv);
1149         }
1150     }
1151   map_free(&seen);
1152   map_free(&rseen);
1153   queue_push(&solv->problems, 0);       /* mark end of this problem */
1154
1155   if (lastweak)
1156     {
1157       /* disable last weak rule */
1158       solv->problems.count = oldproblemcount;
1159       solv->learnt_pool.count = oldlearntpoolcount;
1160       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
1161         v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
1162       else
1163         v = lastweak;
1164       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
1165       solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
1166       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
1167         solver_disablechoicerules(solv, solv->rules + lastweak);
1168       solver_disableproblem(solv, v);
1169       if (v < 0)
1170         solver_reenablepolicyrules(solv, -v);
1171       solver_reset(solv);
1172       return 1;
1173     }
1174
1175   if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
1176     {
1177       solv->problems.count = oldproblemcount;
1178       solv->learnt_pool.count = oldlearntpoolcount;
1179       solver_reset(solv);
1180       return 1;
1181     }
1182
1183   /* finish proof */
1184   if (record_proof)
1185     {
1186       queue_push(&solv->learnt_pool, 0);
1187       solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1188     }
1189
1190   /* + 2: index + trailing zero */
1191   if (disablerules && oldproblemcount + 2 < solv->problems.count)
1192     {
1193       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1194         solver_disableproblem(solv, solv->problems.elements[i]);
1195       /* XXX: might want to enable all weak rules again */
1196       solver_reset(solv);
1197       return 1;
1198     }
1199   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1200   return 0;
1201 }
1202
1203
1204 /********************************************************************/
1205 /* Decision revert */
1206
1207 /*-------------------------------------------------------------------
1208  * 
1209  * revert
1210  * revert decisionq to a level
1211  */
1212
1213 static void
1214 revert(Solver *solv, int level)
1215 {
1216   Pool *pool = solv->pool;
1217   Id v, vv;
1218   while (solv->decisionq.count)
1219     {
1220       v = solv->decisionq.elements[solv->decisionq.count - 1];
1221       vv = v > 0 ? v : -v;
1222       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1223         break;
1224       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1225       solv->decisionmap[vv] = 0;
1226       solv->decisionq.count--;
1227       solv->decisionq_why.count--;
1228       solv->propagate_index = solv->decisionq.count;
1229     }
1230   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1231     {
1232       solv->branches.count--;
1233       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1234         solv->branches.count--;
1235     }
1236   solv->recommends_index = -1;
1237 }
1238
1239
1240 /*-------------------------------------------------------------------
1241  * 
1242  * watch2onhighest - put watch2 on literal with highest level
1243  */
1244
1245 static inline void
1246 watch2onhighest(Solver *solv, Rule *r)
1247 {
1248   int l, wl = 0;
1249   Id d, v, *dp;
1250
1251   d = r->d < 0 ? -r->d - 1 : r->d;
1252   if (!d)
1253     return;     /* binary rule, both watches are set */
1254   dp = solv->pool->whatprovidesdata + d;
1255   while ((v = *dp++) != 0)
1256     {
1257       l = solv->decisionmap[v < 0 ? -v : v];
1258       if (l < 0)
1259         l = -l;
1260       if (l > wl)
1261         {
1262           r->w2 = dp[-1];
1263           wl = l;
1264         }
1265     }
1266 }
1267
1268
1269 /*-------------------------------------------------------------------
1270  * 
1271  * setpropagatelearn
1272  *
1273  * add free decision (solvable to install) to decisionq
1274  * increase level and propagate decision
1275  * return if no conflict.
1276  *
1277  * in conflict case, analyze conflict rule, add resulting
1278  * rule to learnt rule set, make decision from learnt
1279  * rule (always unit) and re-propagate.
1280  *
1281  * returns the new solver level or 0 if unsolvable
1282  *
1283  */
1284
1285 static int
1286 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
1287 {
1288   Pool *pool = solv->pool;
1289   Rule *r;
1290   Id p = 0, d = 0;
1291   int l, why;
1292
1293   assert(ruleid >= 0);
1294   if (decision)
1295     {
1296       level++;
1297       if (decision > 0)
1298         solv->decisionmap[decision] = level;
1299       else
1300         solv->decisionmap[-decision] = -level;
1301       queue_push(&solv->decisionq, decision);
1302       queue_push(&solv->decisionq_why, -ruleid);        /* <= 0 -> free decision */
1303     }
1304   for (;;)
1305     {
1306       r = propagate(solv, level);
1307       if (!r)
1308         break;
1309       if (level == 1)
1310         return analyze_unsolvable(solv, r, disablerules);
1311       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1312       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1313       assert(l > 0 && l < level);
1314       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1315       level = l;
1316       revert(solv, level);
1317       r = solver_addrule(solv, p, d);
1318       assert(r);
1319       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1320       queue_push(&solv->learnt_why, why);
1321       if (d)
1322         {
1323           /* at least 2 literals, needs watches */
1324           watch2onhighest(solv, r);
1325           addwatches_rule(solv, r);
1326         }
1327       else
1328         {
1329           /* learnt rule is an assertion */
1330           queue_push(&solv->ruleassertions, r - solv->rules);
1331         }
1332       /* the new rule is unit by design */
1333       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1334       queue_push(&solv->decisionq, p);
1335       queue_push(&solv->decisionq_why, r - solv->rules);
1336       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
1337         {
1338           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
1339           solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
1340           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
1341           solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
1342         }
1343     }
1344   return level;
1345 }
1346
1347
1348 /*-------------------------------------------------------------------
1349  * 
1350  * select and install
1351  * 
1352  * install best package from the queue. We add an extra package, inst, if
1353  * provided. See comment in weak install section.
1354  *
1355  * returns the new solver level or 0 if unsolvable
1356  *
1357  */
1358
1359 static int
1360 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
1361 {
1362   Pool *pool = solv->pool;
1363   Id p;
1364   int i;
1365
1366   if (dq->count > 1)
1367     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
1368   if (dq->count > 1)
1369     {
1370       /* XXX: didn't we already do that? */
1371       /* XXX: shouldn't we prefer installed packages? */
1372       /* XXX: move to policy.c? */
1373       /* choose the supplemented one */
1374       for (i = 0; i < dq->count; i++)
1375         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1376           {
1377             dq->elements[0] = dq->elements[i];
1378             dq->count = 1;
1379             break;
1380           }
1381     }
1382   if (dq->count > 1)
1383     {
1384       /* multiple candidates, open a branch */
1385       for (i = 1; i < dq->count; i++)
1386         queue_push(&solv->branches, dq->elements[i]);
1387       queue_push(&solv->branches, -level);
1388     }
1389   p = dq->elements[0];
1390
1391   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
1392
1393   return setpropagatelearn(solv, level, p, disablerules, ruleid);
1394 }
1395
1396
1397 /********************************************************************/
1398 /* Main solver interface */
1399
1400
1401 /*-------------------------------------------------------------------
1402  * 
1403  * solver_create
1404  * create solver structure
1405  *
1406  * pool: all available solvables
1407  * installed: installed Solvables
1408  *
1409  *
1410  * Upon solving, rules are created to flag the Solvables
1411  * of the 'installed' Repo as installed.
1412  */
1413
1414 Solver *
1415 solver_create(Pool *pool)
1416 {
1417   Solver *solv;
1418   solv = (Solver *)solv_calloc(1, sizeof(Solver));
1419   solv->pool = pool;
1420   solv->installed = pool->installed;
1421
1422   solv->allownamechange = 1;
1423
1424   solv->dup_allowdowngrade = 1;
1425   solv->dup_allownamechange = 1;
1426   solv->dup_allowarchchange = 1;
1427   solv->dup_allowvendorchange = 1;
1428
1429   queue_init(&solv->ruletojob);
1430   queue_init(&solv->decisionq);
1431   queue_init(&solv->decisionq_why);
1432   queue_init(&solv->problems);
1433   queue_init(&solv->orphaned);
1434   queue_init(&solv->learnt_why);
1435   queue_init(&solv->learnt_pool);
1436   queue_init(&solv->branches);
1437   queue_init(&solv->weakruleq);
1438   queue_init(&solv->ruleassertions);
1439   queue_init(&solv->addedmap_deduceq);
1440
1441   queue_push(&solv->learnt_pool, 0);    /* so that 0 does not describe a proof */
1442
1443   map_init(&solv->recommendsmap, pool->nsolvables);
1444   map_init(&solv->suggestsmap, pool->nsolvables);
1445   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
1446   solv->recommends_index = 0;
1447
1448   solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
1449   solv->nrules = 1;
1450   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
1451   memset(solv->rules, 0, sizeof(Rule));
1452
1453   return solv;
1454 }
1455
1456
1457 /*-------------------------------------------------------------------
1458  * 
1459  * solver_free
1460  */
1461
1462 void
1463 solver_free(Solver *solv)
1464 {
1465   queue_free(&solv->job);
1466   queue_free(&solv->ruletojob);
1467   queue_free(&solv->decisionq);
1468   queue_free(&solv->decisionq_why);
1469   queue_free(&solv->learnt_why);
1470   queue_free(&solv->learnt_pool);
1471   queue_free(&solv->problems);
1472   queue_free(&solv->solutions);
1473   queue_free(&solv->orphaned);
1474   queue_free(&solv->branches);
1475   queue_free(&solv->weakruleq);
1476   queue_free(&solv->ruleassertions);
1477   queue_free(&solv->addedmap_deduceq);
1478   if (solv->cleandeps_updatepkgs)
1479     {
1480       queue_free(solv->cleandeps_updatepkgs);
1481       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
1482     }
1483   if (solv->cleandeps_mistakes)
1484     {
1485       queue_free(solv->cleandeps_mistakes);
1486       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
1487     }
1488   if (solv->update_targets)
1489     {
1490       queue_free(solv->update_targets);
1491       solv->update_targets = solv_free(solv->update_targets);
1492     }
1493   if (solv->installsuppdepq)
1494     {
1495       queue_free(solv->installsuppdepq);
1496       solv->installsuppdepq = solv_free(solv->installsuppdepq);
1497     }
1498
1499   map_free(&solv->recommendsmap);
1500   map_free(&solv->suggestsmap);
1501   map_free(&solv->noupdate);
1502   map_free(&solv->weakrulemap);
1503   map_free(&solv->noobsoletes);
1504
1505   map_free(&solv->updatemap);
1506   map_free(&solv->bestupdatemap);
1507   map_free(&solv->fixmap);
1508   map_free(&solv->dupmap);
1509   map_free(&solv->dupinvolvedmap);
1510   map_free(&solv->droporphanedmap);
1511   map_free(&solv->cleandepsmap);
1512
1513   solv_free(solv->decisionmap);
1514   solv_free(solv->rules);
1515   solv_free(solv->watches);
1516   solv_free(solv->obsoletes);
1517   solv_free(solv->obsoletes_data);
1518   solv_free(solv->multiversionupdaters);
1519   solv_free(solv->choicerules_ref);
1520   solv_free(solv->bestrules_pkg);
1521   solv_free(solv);
1522 }
1523
1524 int
1525 solver_get_flag(Solver *solv, int flag)
1526 {
1527   switch (flag)
1528   {
1529   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1530     return solv->allowdowngrade;
1531   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1532     return solv->allownamechange;
1533   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1534     return solv->allowarchchange;
1535   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1536     return solv->allowvendorchange;
1537   case SOLVER_FLAG_ALLOW_UNINSTALL:
1538     return solv->allowuninstall;
1539   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1540     return solv->noupdateprovide;
1541   case SOLVER_FLAG_SPLITPROVIDES:
1542     return solv->dosplitprovides;
1543   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1544     return solv->dontinstallrecommended;
1545   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1546     return solv->addalreadyrecommended;
1547   case SOLVER_FLAG_NO_INFARCHCHECK:
1548     return solv->noinfarchcheck;
1549   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1550     return solv->keepexplicitobsoletes;
1551   case SOLVER_FLAG_BEST_OBEY_POLICY:
1552     return solv->bestobeypolicy;
1553   case SOLVER_FLAG_NO_AUTOTARGET:
1554     return solv->noautotarget;
1555   default:
1556     break;
1557   }
1558   return -1;
1559 }
1560
1561 int
1562 solver_set_flag(Solver *solv, int flag, int value)
1563 {
1564   int old = solver_get_flag(solv, flag);
1565   switch (flag)
1566   {
1567   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1568     solv->allowdowngrade = value;
1569     break;
1570   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1571     solv->allownamechange = value;
1572     break;
1573   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1574     solv->allowarchchange = value;
1575     break;
1576   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1577     solv->allowvendorchange = value;
1578     break;
1579   case SOLVER_FLAG_ALLOW_UNINSTALL:
1580     solv->allowuninstall = value;
1581     break;
1582   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1583     solv->noupdateprovide = value;
1584     break;
1585   case SOLVER_FLAG_SPLITPROVIDES:
1586     solv->dosplitprovides = value;
1587     break;
1588   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1589     solv->dontinstallrecommended = value;
1590     break;
1591   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1592     solv->addalreadyrecommended = value;
1593     break;
1594   case SOLVER_FLAG_NO_INFARCHCHECK:
1595     solv->noinfarchcheck = value;
1596     break;
1597   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1598     solv->keepexplicitobsoletes = value;
1599     break;
1600   case SOLVER_FLAG_BEST_OBEY_POLICY:
1601     solv->bestobeypolicy = value;
1602     break;
1603   case SOLVER_FLAG_NO_AUTOTARGET:
1604     solv->noautotarget = value;
1605     break;
1606   default:
1607     break;
1608   }
1609   return old;
1610 }
1611
1612 int
1613 cleandeps_check_mistakes(Solver *solv, int level)
1614 {
1615   Pool *pool = solv->pool;
1616   Rule *r;
1617   Id p, pp;
1618   int i;
1619   int mademistake = 0;
1620
1621   if (!solv->cleandepsmap.size)
1622     return 0;
1623   /* check for mistakes */
1624   for (i = solv->installed->start; i < solv->installed->end; i++)
1625     {
1626       if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1627         continue;
1628       r = solv->rules + solv->featurerules + (i - solv->installed->start);
1629       /* a mistake is when the featurerule is true but the updaterule is false */
1630       if (!r->p)
1631         continue;
1632       FOR_RULELITERALS(p, pp, r)
1633         if (p > 0 && solv->decisionmap[p] > 0)
1634           break;
1635       if (!p)
1636         continue;       /* feature rule is not true */
1637       r = solv->rules + solv->updaterules + (i - solv->installed->start);
1638       if (!r->p)
1639         continue;
1640       FOR_RULELITERALS(p, pp, r)
1641         if (p > 0 && solv->decisionmap[p] > 0)
1642           break;
1643       if (p)
1644         continue;       /* update rule is true */
1645       POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
1646       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
1647       POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
1648       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
1649       if (!solv->cleandeps_mistakes)
1650         {
1651           solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
1652           queue_init(solv->cleandeps_mistakes);
1653         }
1654       queue_push(solv->cleandeps_mistakes, i);
1655       MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
1656       solver_reenablepolicyrules_cleandeps(solv, i);
1657       mademistake = 1;
1658     }
1659   if (mademistake)
1660     solver_reset(solv);
1661   return mademistake;
1662 }
1663
1664 static void
1665 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
1666 {
1667   int i, j;
1668   Id p, *cp2;
1669   for (i = j = 0; i < q->count; i++)
1670     {
1671       p = q->elements[i];
1672       for (cp2 = cp; *cp2; cp2++)
1673         if (*cp2 == p)
1674           {
1675             q->elements[j++] = p;
1676             break;
1677           }
1678     }
1679   queue_truncate(q, j);
1680 }
1681
1682 /*-------------------------------------------------------------------
1683  * 
1684  * solver_run_sat
1685  *
1686  * all rules have been set up, now actually run the solver
1687  *
1688  */
1689
1690 void
1691 solver_run_sat(Solver *solv, int disablerules, int doweak)
1692 {
1693   Queue dq;             /* local decisionqueue */
1694   Queue dqs;            /* local decisionqueue for supplements */
1695   int systemlevel;
1696   int level, olevel;
1697   Rule *r;
1698   int i, j, n;
1699   Solvable *s;
1700   Pool *pool = solv->pool;
1701   Id p, pp, *dp;
1702   int minimizationsteps;
1703   int installedpos = solv->installed ? solv->installed->start : 0;
1704
1705   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
1706     {
1707       POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
1708       for (i = 1; i < solv->nrules; i++)
1709         solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
1710     }
1711
1712   POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
1713
1714   /* start SAT algorithm */
1715   level = 1;
1716   systemlevel = level + 1;
1717   POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
1718
1719   queue_init(&dq);
1720   queue_init(&dqs);
1721
1722   /*
1723    * here's the main loop:
1724    * 1) propagate new decisions (only needed once)
1725    * 2) fulfill jobs
1726    * 3) try to keep installed packages
1727    * 4) fulfill all unresolved rules
1728    * 5) install recommended packages
1729    * 6) minimalize solution if we had choices
1730    * if we encounter a problem, we rewind to a safe level and restart
1731    * with step 1
1732    */
1733    
1734   minimizationsteps = 0;
1735   for (;;)
1736     {
1737       /*
1738        * initial propagation of the assertions
1739        */
1740       if (level == 1)
1741         {
1742           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
1743           if ((r = propagate(solv, level)) != 0)
1744             {
1745               if (analyze_unsolvable(solv, r, disablerules))
1746                 continue;
1747               level = 0;
1748               break;    /* unsolvable */
1749             }
1750         }
1751
1752       /*
1753        * resolve jobs first
1754        */
1755      if (level < systemlevel)
1756         {
1757           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
1758           for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
1759             {
1760               Id l;
1761               if (r->d < 0)             /* ignore disabled rules */
1762                 continue;
1763               queue_empty(&dq);
1764               FOR_RULELITERALS(l, pp, r)
1765                 {
1766                   if (l < 0)
1767                     {
1768                       if (solv->decisionmap[-l] <= 0)
1769                         break;
1770                     }
1771                   else
1772                     {
1773                       if (solv->decisionmap[l] > 0)
1774                         break;
1775                       if (solv->decisionmap[l] == 0)
1776                         queue_push(&dq, l);
1777                     }
1778                 }
1779               if (l || !dq.count)
1780                 continue;
1781               /* prune to installed if not updating */
1782               if (dq.count > 1 && solv->installed && !solv->updatemap_all &&
1783                   !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
1784                 {
1785                   int j, k;
1786                   for (j = k = 0; j < dq.count; j++)
1787                     {
1788                       Solvable *s = pool->solvables + dq.elements[j];
1789                       if (s->repo == solv->installed)
1790                         {
1791                           dq.elements[k++] = dq.elements[j];
1792                           if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
1793                             {
1794                               k = 0;    /* package wants to be updated, do not prune */
1795                               break;
1796                             }
1797                         }
1798                     }
1799                   if (k)
1800                     dq.count = k;
1801                 }
1802               olevel = level;
1803               level = selectandinstall(solv, level, &dq, disablerules, i);
1804               if (level == 0)
1805                 break;
1806               if (level <= olevel)
1807                 break;
1808             }
1809           if (level == 0)
1810             break;      /* unsolvable */
1811           systemlevel = level + 1;
1812           if (i < solv->jobrules_end)
1813             continue;
1814           solv->decisioncnt_update = solv->decisionq.count;
1815           solv->decisioncnt_keep = solv->decisionq.count;
1816         }
1817
1818       /*
1819        * installed packages
1820        */
1821       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
1822         {
1823           Repo *installed = solv->installed;
1824           int pass;
1825
1826           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
1827           /* we use two passes if we need to update packages 
1828            * to create a better user experience */
1829           for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
1830             {
1831               int passlevel = level;
1832               if (pass == 1)
1833                 solv->decisioncnt_keep = solv->decisionq.count;
1834               /* start with installedpos, the position that gave us problems last time */
1835               for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
1836                 {
1837                   Rule *rr;
1838                   Id d;
1839
1840                   if (i == installed->end)
1841                     i = installed->start;
1842                   s = pool->solvables + i;
1843                   if (s->repo != installed)
1844                     continue;
1845
1846                   if (solv->decisionmap[i] > 0)
1847                     continue;
1848                   if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
1849                     continue;           /* updates first */
1850                   r = solv->rules + solv->updaterules + (i - installed->start);
1851                   rr = r;
1852                   if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
1853                     rr -= solv->installed->end - solv->installed->start;
1854                   if (!rr->p)           /* identical to update rule? */
1855                     rr = r;
1856                   if (!rr->p)
1857                     continue;           /* orpaned package */
1858
1859                   /* XXX: noupdate check is probably no longer needed, as all jobs should
1860                    * already be satisfied */
1861                   /* Actually we currently still need it because of erase jobs */
1862                   /* if noupdate is set we do not look at update candidates */
1863                   queue_empty(&dq);
1864                   if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i))
1865                     {
1866                       if (solv->noobsoletes.size && solv->multiversionupdaters
1867                              && (d = solv->multiversionupdaters[i - installed->start]) != 0)
1868                         {
1869                           /* special multiversion handling, make sure best version is chosen */
1870                           queue_push(&dq, i);
1871                           while ((p = pool->whatprovidesdata[d++]) != 0)
1872                             if (solv->decisionmap[p] >= 0)
1873                               queue_push(&dq, p);
1874                           if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1875                             prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1876                           if (dq.count)
1877                             {
1878                               policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
1879                               p = dq.elements[0];
1880                               if (p != i && solv->decisionmap[p] == 0)
1881                                 {
1882                                   rr = solv->rules + solv->featurerules + (i - solv->installed->start);
1883                                   if (!rr->p)           /* update rule == feature rule? */
1884                                     rr = rr - solv->featurerules + solv->updaterules;
1885                                   dq.count = 1;
1886                                 }
1887                               else
1888                                 dq.count = 0;
1889                             }
1890                         }
1891                       else
1892                         {
1893                           /* update to best package */
1894                           FOR_RULELITERALS(p, pp, rr)
1895                             {
1896                               if (solv->decisionmap[p] > 0)
1897                                 {
1898                                   dq.count = 0;         /* already fulfilled */
1899                                   break;
1900                                 }
1901                               if (!solv->decisionmap[p])
1902                                 queue_push(&dq, p);
1903                             }
1904                         }
1905                     }
1906                   if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1907                     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1908                   /* install best version */
1909                   if (dq.count)
1910                     {
1911                       olevel = level;
1912                       level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
1913                       if (level == 0)
1914                         {
1915                           queue_free(&dq);
1916                           queue_free(&dqs);
1917                           return;
1918                         }
1919                       if (level <= olevel)
1920                         {
1921                           if (level == 1 || level < passlevel)
1922                             break;      /* trouble */
1923                           if (level < olevel)
1924                             n = installed->start;       /* redo all */
1925                           i--;
1926                           n--;
1927                           continue;
1928                         }
1929                     }
1930                   /* if still undecided keep package */
1931                   if (solv->decisionmap[i] == 0)
1932                     {
1933                       olevel = level;
1934                       if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
1935                         {
1936 #if 0
1937                           POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
1938                           level = setpropagatelearn(solv, level, -i, disablerules, 0);
1939 #else
1940                           continue;
1941 #endif
1942                         }
1943                       else
1944                         {
1945                           POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
1946                           level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
1947                         }
1948                       if (level == 0)
1949                         break;
1950                       if (level <= olevel)
1951                         {
1952                           if (level == 1 || level < passlevel)
1953                             break;      /* trouble */
1954                           if (level < olevel)
1955                             n = installed->start;       /* redo all */
1956                           i--;
1957                           n--;
1958                           continue;     /* retry with learnt rule */
1959                         }
1960                     }
1961                 }
1962               if (n < installed->end)
1963                 {
1964                   installedpos = i;     /* retry problem solvable next time */
1965                   break;                /* ran into trouble */
1966                 }
1967               installedpos = installed->start;  /* reset installedpos */
1968             }
1969           if (level == 0)
1970             break;              /* unsolvable */
1971           systemlevel = level + 1;
1972           if (pass < 2)
1973             continue;           /* had trouble, retry */
1974         }
1975
1976       if (level < systemlevel)
1977         systemlevel = level;
1978
1979       /*
1980        * decide
1981        */
1982       solv->decisioncnt_resolve = solv->decisionq.count;
1983       POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
1984       for (i = 1, n = 1; n < solv->nrules; i++, n++)
1985         {
1986           if (i == solv->nrules)
1987             i = 1;
1988           r = solv->rules + i;
1989           if (r->d < 0)         /* ignore disabled rules */
1990             continue;
1991           queue_empty(&dq);
1992           if (r->d == 0)
1993             {
1994               /* binary or unary rule */
1995               /* need two positive undecided literals */
1996               if (r->p < 0 || r->w2 <= 0)
1997                 continue;
1998               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
1999                 continue;
2000               queue_push(&dq, r->p);
2001               queue_push(&dq, r->w2);
2002             }
2003           else
2004             {
2005               /* make sure that
2006                * all negative literals are installed
2007                * no positive literal is installed
2008                * i.e. the rule is not fulfilled and we
2009                * just need to decide on the positive literals
2010                */
2011               if (r->p < 0)
2012                 {
2013                   if (solv->decisionmap[-r->p] <= 0)
2014                     continue;
2015                 }
2016               else
2017                 {
2018                   if (solv->decisionmap[r->p] > 0)
2019                     continue;
2020                   if (solv->decisionmap[r->p] == 0)
2021                     queue_push(&dq, r->p);
2022                 }
2023               dp = pool->whatprovidesdata + r->d;
2024               while ((p = *dp++) != 0)
2025                 {
2026                   if (p < 0)
2027                     {
2028                       if (solv->decisionmap[-p] <= 0)
2029                         break;
2030                     }
2031                   else
2032                     {
2033                       if (solv->decisionmap[p] > 0)
2034                         break;
2035                       if (solv->decisionmap[p] == 0)
2036                         queue_push(&dq, p);
2037                     }
2038                 }
2039               if (p)
2040                 continue;
2041             }
2042           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
2043             {
2044               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
2045               solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
2046             }
2047           /* dq.count < 2 cannot happen as this means that
2048            * the rule is unit */
2049           assert(dq.count > 1);
2050
2051           /* prune to cleandeps packages */
2052           if (solv->cleandepsmap.size && solv->installed)
2053             {
2054               Repo *installed = solv->installed;
2055               for (j = 0; j < dq.count; j++)
2056                 if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
2057                   break;
2058               if (j < dq.count)
2059                 {
2060                   dq.elements[0] = dq.elements[j];
2061                   queue_truncate(&dq, 1);
2062                 }
2063             }
2064
2065           olevel = level;
2066           level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2067           if (level == 0)
2068             break;              /* unsolvable */
2069           if (level < systemlevel || level == 1)
2070             break;              /* trouble */
2071           /* something changed, so look at all rules again */
2072           n = 0;
2073         }
2074
2075       if (n != solv->nrules)    /* ran into trouble? */
2076         {
2077           if (level == 0)
2078             break;              /* unsolvable */
2079           continue;             /* start over */
2080         }
2081
2082       /* at this point we have a consistent system. now do the extras... */
2083
2084       /* first decide leftover cleandeps packages */
2085       if (solv->cleandepsmap.size && solv->installed)
2086         {
2087           for (p = solv->installed->start; p < solv->installed->end; p++)
2088             {
2089               s = pool->solvables + p;
2090               if (s->repo != solv->installed)
2091                 continue;
2092               if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2093                 {
2094                   POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
2095                   olevel = level;
2096                   level = setpropagatelearn(solv, level, -p, 0, 0);
2097                   if (level < olevel)
2098                     break;
2099                 }
2100             }
2101           if (p < solv->installed->end)
2102             continue;
2103         }
2104
2105       solv->decisioncnt_weak = solv->decisionq.count;
2106       if (doweak)
2107         {
2108           int qcount;
2109
2110           POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
2111           queue_empty(&dq);     /* recommended packages */
2112           queue_empty(&dqs);    /* supplemented packages */
2113           for (i = 1; i < pool->nsolvables; i++)
2114             {
2115               if (solv->decisionmap[i] < 0)
2116                 continue;
2117               if (solv->decisionmap[i] > 0)
2118                 {
2119                   /* installed, check for recommends */
2120                   Id *recp, rec, pp, p;
2121                   s = pool->solvables + i;
2122                   if (!solv->addalreadyrecommended && s->repo == solv->installed)
2123                     continue;
2124                   /* XXX need to special case AND ? */
2125                   if (s->recommends)
2126                     {
2127                       recp = s->repo->idarraydata + s->recommends;
2128                       while ((rec = *recp++) != 0)
2129                         {
2130                           qcount = dq.count;
2131                           FOR_PROVIDES(p, pp, rec)
2132                             {
2133                               if (solv->decisionmap[p] > 0)
2134                                 {
2135                                   dq.count = qcount;
2136                                   break;
2137                                 }
2138                               else if (solv->decisionmap[p] == 0)
2139                                 {
2140                                   if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
2141                                     continue;
2142                                   queue_pushunique(&dq, p);
2143                                 }
2144                             }
2145                         }
2146                     }
2147                 }
2148               else
2149                 {
2150                   s = pool->solvables + i;
2151                   if (!s->supplements)
2152                     continue;
2153                   if (!pool_installable(pool, s))
2154                     continue;
2155                   if (!solver_is_supplementing(solv, s))
2156                     continue;
2157                   if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
2158                     continue;
2159                   queue_push(&dqs, i);
2160                 }
2161             }
2162
2163           /* filter out all packages obsoleted by installed packages */
2164           /* this is no longer needed if we have reverse obsoletes */
2165           if ((dqs.count || dq.count) && solv->installed)
2166             {
2167               Map obsmap;
2168               Id obs, *obsp, po, ppo;
2169
2170               map_init(&obsmap, pool->nsolvables);
2171               for (p = solv->installed->start; p < solv->installed->end; p++)
2172                 {
2173                   s = pool->solvables + p;
2174                   if (s->repo != solv->installed || !s->obsoletes)
2175                     continue;
2176                   if (solv->decisionmap[p] <= 0)
2177                     continue;
2178                   if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
2179                     continue;
2180                   obsp = s->repo->idarraydata + s->obsoletes;
2181                   /* foreach obsoletes */
2182                   while ((obs = *obsp++) != 0)
2183                     FOR_PROVIDES(po, ppo, obs)
2184                       MAPSET(&obsmap, po);
2185                 }
2186               for (i = j = 0; i < dqs.count; i++)
2187                 if (!MAPTST(&obsmap, dqs.elements[i]))
2188                   dqs.elements[j++] = dqs.elements[i];
2189               dqs.count = j;
2190               for (i = j = 0; i < dq.count; i++)
2191                 if (!MAPTST(&obsmap, dq.elements[i]))
2192                   dq.elements[j++] = dq.elements[i];
2193               dq.count = j;
2194               map_free(&obsmap);
2195             }
2196
2197           /* filter out all already supplemented packages if requested */
2198           if (!solv->addalreadyrecommended && dqs.count)
2199             {
2200               /* turn off all new packages */
2201               for (i = 0; i < solv->decisionq.count; i++)
2202                 {
2203                   p = solv->decisionq.elements[i];
2204                   if (p < 0)
2205                     continue;
2206                   s = pool->solvables + p;
2207                   if (s->repo && s->repo != solv->installed)
2208                     solv->decisionmap[p] = -solv->decisionmap[p];
2209                 }
2210               /* filter out old supplements */
2211               for (i = j = 0; i < dqs.count; i++)
2212                 {
2213                   p = dqs.elements[i];
2214                   s = pool->solvables + p;
2215                   if (!s->supplements)
2216                     continue;
2217                   if (!solver_is_supplementing(solv, s))
2218                     dqs.elements[j++] = p;
2219                   else if (s->supplements && solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
2220                     dqs.elements[j++] = p;
2221                 }
2222               dqs.count = j;
2223               /* undo turning off */
2224               for (i = 0; i < solv->decisionq.count; i++)
2225                 {
2226                   p = solv->decisionq.elements[i];
2227                   if (p < 0)
2228                     continue;
2229                   s = pool->solvables + p;
2230                   if (s->repo && s->repo != solv->installed)
2231                     solv->decisionmap[p] = -solv->decisionmap[p];
2232                 }
2233             }
2234
2235           /* multiversion doesn't mix well with supplements.
2236            * filter supplemented packages where we already decided
2237            * to install a different version (see bnc#501088) */
2238           if (dqs.count && solv->noobsoletes.size)
2239             {
2240               for (i = j = 0; i < dqs.count; i++)
2241                 {
2242                   p = dqs.elements[i];
2243                   if (MAPTST(&solv->noobsoletes, p))
2244                     {
2245                       Id p2, pp2;
2246                       s = pool->solvables + p;
2247                       FOR_PROVIDES(p2, pp2, s->name)
2248                         if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
2249                           break;
2250                       if (p2)
2251                         continue;       /* ignore this package */
2252                     }
2253                   dqs.elements[j++] = p;
2254                 }
2255               dqs.count = j;
2256             }
2257
2258           /* make dq contain both recommended and supplemented pkgs */
2259           if (dqs.count)
2260             {
2261               for (i = 0; i < dqs.count; i++)
2262                 queue_pushunique(&dq, dqs.elements[i]);
2263             }
2264
2265           if (dq.count)
2266             {
2267               Map dqmap;
2268               int decisioncount = solv->decisionq.count;
2269
2270               if (dq.count == 1)
2271                 {
2272                   /* simple case, just one package. no need to choose to best version */
2273                   p = dq.elements[0];
2274                   if (dqs.count)
2275                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2276                   else
2277                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2278                   level = setpropagatelearn(solv, level, p, 0, 0);
2279                   if (level == 0)
2280                     break;
2281                   continue;     /* back to main loop */
2282                 }
2283
2284               /* filter packages, this gives us the best versions */
2285               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2286
2287               /* create map of result */
2288               map_init(&dqmap, pool->nsolvables);
2289               for (i = 0; i < dq.count; i++)
2290                 MAPSET(&dqmap, dq.elements[i]);
2291
2292               /* install all supplemented packages */
2293               for (i = 0; i < dqs.count; i++)
2294                 {
2295                   p = dqs.elements[i];
2296                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2297                     continue;
2298                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2299                   olevel = level;
2300                   level = setpropagatelearn(solv, level, p, 0, 0);
2301                   if (level <= olevel)
2302                     break;
2303                 }
2304               if (i < dqs.count || solv->decisionq.count < decisioncount)
2305                 {
2306                   map_free(&dqmap);
2307                   if (level == 0)
2308                     break;
2309                   continue;
2310                 }
2311
2312               /* install all recommended packages */
2313               /* more work as we want to created branches if multiple
2314                * choices are valid */
2315               for (i = 0; i < decisioncount; i++)
2316                 {
2317                   Id rec, *recp, pp;
2318                   p = solv->decisionq.elements[i];
2319                   if (p < 0)
2320                     continue;
2321                   s = pool->solvables + p;
2322                   if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
2323                     continue;
2324                   if (!s->recommends)
2325                     continue;
2326                   recp = s->repo->idarraydata + s->recommends;
2327                   while ((rec = *recp++) != 0)
2328                     {
2329                       queue_empty(&dq);
2330                       FOR_PROVIDES(p, pp, rec)
2331                         {
2332                           if (solv->decisionmap[p] > 0)
2333                             {
2334                               dq.count = 0;
2335                               break;
2336                             }
2337                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2338                             queue_pushunique(&dq, p);
2339                         }
2340                       if (!dq.count)
2341                         continue;
2342                       if (dq.count > 1)
2343                         {
2344                           /* multiple candidates, open a branch */
2345                           for (i = 1; i < dq.count; i++)
2346                             queue_push(&solv->branches, dq.elements[i]);
2347                           queue_push(&solv->branches, -level);
2348                         }
2349                       p = dq.elements[0];
2350                       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2351                       olevel = level;
2352                       level = setpropagatelearn(solv, level, p, 0, 0);
2353                       if (level <= olevel || solv->decisionq.count < decisioncount)
2354                         break;  /* we had to revert some decisions */
2355                     }
2356                   if (rec)
2357                     break;      /* had a problem above, quit loop */
2358                 }
2359               map_free(&dqmap);
2360               if (level == 0)
2361                 break;
2362               continue;         /* back to main loop so that all deps are checked */
2363             }
2364         }
2365
2366       solv->decisioncnt_orphan = solv->decisionq.count;
2367       if (solv->dupmap_all && solv->installed)
2368         {
2369           int installedone = 0;
2370
2371           /* let's see if we can install some unsupported package */
2372           POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
2373           for (i = 0; i < solv->orphaned.count; i++)
2374             {
2375               p = solv->orphaned.elements[i];
2376               if (solv->decisionmap[p])
2377                 continue;       /* already decided */
2378               if (solv->droporphanedmap_all)
2379                 continue;
2380               if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
2381                 continue;
2382               POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
2383               olevel = level;
2384               level = setpropagatelearn(solv, level, p, 0, 0);
2385               installedone = 1;
2386               if (level < olevel)
2387                 break;
2388             }
2389           if (installedone || i < solv->orphaned.count)
2390             {
2391               if (level == 0)
2392                 break;
2393               continue;         /* back to main loop */
2394             }
2395           for (i = 0; i < solv->orphaned.count; i++)
2396             {
2397               p = solv->orphaned.elements[i];
2398               if (solv->decisionmap[p])
2399                 continue;       /* already decided */
2400               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
2401               olevel = level;
2402               level = setpropagatelearn(solv, level, -p, 0, 0);
2403               if (level < olevel)
2404                 break;
2405             }
2406           if (i < solv->orphaned.count)
2407             {
2408               if (level == 0)
2409                 break;
2410               continue;         /* back to main loop */
2411             }
2412         }
2413
2414      if (solv->installed && solv->cleandepsmap.size)
2415         {
2416           if (cleandeps_check_mistakes(solv, level))
2417             {
2418               level = 1;        /* restart from scratch */
2419               systemlevel = level + 1;
2420               continue;
2421             }
2422         }
2423
2424      if (solv->solution_callback)
2425         {
2426           solv->solution_callback(solv, solv->solution_callback_data);
2427           if (solv->branches.count)
2428             {
2429               int i = solv->branches.count - 1;
2430               int l = -solv->branches.elements[i];
2431               Id why;
2432
2433               for (; i > 0; i--)
2434                 if (solv->branches.elements[i - 1] < 0)
2435                   break;
2436               p = solv->branches.elements[i];
2437               POOL_DEBUG(SOLV_DEBUG_SOLVER, "branching with %s\n", pool_solvid2str(pool, p));
2438               queue_empty(&dq);
2439               for (j = i + 1; j < solv->branches.count; j++)
2440                 queue_push(&dq, solv->branches.elements[j]);
2441               solv->branches.count = i;
2442               level = l;
2443               revert(solv, level);
2444               if (dq.count > 1)
2445                 for (j = 0; j < dq.count; j++)
2446                   queue_push(&solv->branches, dq.elements[j]);
2447               olevel = level;
2448               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2449               assert(why >= 0);
2450               level = setpropagatelearn(solv, level, p, disablerules, why);
2451               if (level == 0)
2452                 break;
2453               continue;
2454             }
2455           /* all branches done, we're finally finished */
2456           break;
2457         }
2458
2459       /* auto-minimization step */
2460      if (solv->branches.count)
2461         {
2462           int l = 0, lasti = -1, lastl = -1;
2463           Id why;
2464
2465           p = 0;
2466           for (i = solv->branches.count - 1; i >= 0; i--)
2467             {
2468               p = solv->branches.elements[i];
2469               if (p < 0)
2470                 l = -p;
2471               else if (p > 0 && solv->decisionmap[p] > l + 1)
2472                 {
2473                   lasti = i;
2474                   lastl = l;
2475                 }
2476             }
2477           if (lasti >= 0)
2478             {
2479               /* kill old solvable so that we do not loop */
2480               p = solv->branches.elements[lasti];
2481               solv->branches.elements[lasti] = 0;
2482               POOL_DEBUG(SOLV_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, pool_solvid2str(pool, p));
2483               minimizationsteps++;
2484
2485               level = lastl;
2486               revert(solv, level);
2487               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2488               assert(why >= 0);
2489               olevel = level;
2490               level = setpropagatelearn(solv, level, p, disablerules, why);
2491               if (level == 0)
2492                 break;
2493               continue;         /* back to main loop */
2494             }
2495         }
2496       /* no minimization found, we're finally finished! */
2497       break;
2498     }
2499
2500   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
2501
2502   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
2503   queue_free(&dq);
2504   queue_free(&dqs);
2505   if (level == 0)
2506     {
2507       /* unsolvable */
2508       solv->decisioncnt_update = solv->decisionq.count;
2509       solv->decisioncnt_keep = solv->decisionq.count;
2510       solv->decisioncnt_resolve = solv->decisionq.count;
2511       solv->decisioncnt_weak = solv->decisionq.count;
2512       solv->decisioncnt_orphan = solv->decisionq.count;
2513     }
2514 #if 0
2515   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
2516 #endif
2517 }
2518
2519
2520 /*-------------------------------------------------------------------
2521  * 
2522  * remove disabled conflicts
2523  *
2524  * purpose: update the decisionmap after some rules were disabled.
2525  * this is used to calculate the suggested/recommended package list.
2526  * Also returns a "removed" list to undo the discisionmap changes.
2527  */
2528
2529 static void
2530 removedisabledconflicts(Solver *solv, Queue *removed)
2531 {
2532   Pool *pool = solv->pool;
2533   int i, n;
2534   Id p, why, *dp;
2535   Id new;
2536   Rule *r;
2537   Id *decisionmap = solv->decisionmap;
2538
2539   queue_empty(removed);
2540   for (i = 0; i < solv->decisionq.count; i++)
2541     {
2542       p = solv->decisionq.elements[i];
2543       if (p > 0)
2544         continue;       /* conflicts only, please */
2545       why = solv->decisionq_why.elements[i];
2546       if (why == 0)
2547         {
2548           /* no rule involved, must be a orphan package drop */
2549           continue;
2550         }
2551       /* we never do conflicts on free decisions, so there
2552        * must have been an unit rule */
2553       assert(why > 0);
2554       r = solv->rules + why;
2555       if (r->d < 0 && decisionmap[-p])
2556         {
2557           /* rule is now disabled, remove from decisionmap */
2558           POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
2559           queue_push(removed, -p);
2560           queue_push(removed, decisionmap[-p]);
2561           decisionmap[-p] = 0;
2562         }
2563     }
2564   if (!removed->count)
2565     return;
2566   /* we removed some confliced packages. some of them might still
2567    * be in conflict, so search for unit rules and re-conflict */
2568   new = 0;
2569   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
2570     {
2571       if (i == solv->nrules)
2572         {
2573           i = 1;
2574           r = solv->rules + i;
2575         }
2576       if (r->d < 0)
2577         continue;
2578       if (!r->w2)
2579         {
2580           if (r->p < 0 && !decisionmap[-r->p])
2581             new = r->p;
2582         }
2583       else if (!r->d)
2584         {
2585           /* binary rule */
2586           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
2587             new = r->p;
2588           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
2589             new = r->w2;
2590         }
2591       else
2592         {
2593           if (r->p < 0 && decisionmap[-r->p] == 0)
2594             new = r->p;
2595           if (new || DECISIONMAP_FALSE(r->p))
2596             {
2597               dp = pool->whatprovidesdata + r->d;
2598               while ((p = *dp++) != 0)
2599                 {
2600                   if (new && p == new)
2601                     continue;
2602                   if (p < 0 && decisionmap[-p] == 0)
2603                     {
2604                       if (new)
2605                         {
2606                           new = 0;
2607                           break;
2608                         }
2609                       new = p;
2610                     }
2611                   else if (!DECISIONMAP_FALSE(p))
2612                     {
2613                       new = 0;
2614                       break;
2615                     }
2616                 }
2617             }
2618         }
2619       if (new)
2620         {
2621           POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
2622           decisionmap[-new] = -1;
2623           new = 0;
2624           n = 0;        /* redo all rules */
2625         }
2626     }
2627 }
2628
2629 static inline void
2630 undo_removedisabledconflicts(Solver *solv, Queue *removed)
2631 {
2632   int i;
2633   for (i = 0; i < removed->count; i += 2)
2634     solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
2635 }
2636
2637
2638 /*-------------------------------------------------------------------
2639  *
2640  * weaken solvable dependencies
2641  */
2642
2643 static void
2644 weaken_solvable_deps(Solver *solv, Id p)
2645 {
2646   int i;
2647   Rule *r;
2648
2649   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
2650     {
2651       if (r->p != -p)
2652         continue;
2653       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2654         continue;       /* conflict */
2655       queue_push(&solv->weakruleq, i);
2656     }
2657 }
2658
2659
2660 /********************************************************************/
2661 /* main() */
2662
2663
2664 void
2665 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *noobsmap)
2666 {
2667   int i;
2668   Id how, what, select;
2669   Id p, pp;
2670   for (i = 0; i < job->count; i += 2)
2671     {
2672       how = job->elements[i];
2673       if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
2674         continue;
2675       what = job->elements[i + 1];
2676       select = how & SOLVER_SELECTMASK;
2677       if (!noobsmap->size)
2678         map_grow(noobsmap, pool->nsolvables);
2679       if (select == SOLVER_SOLVABLE_ALL)
2680         {
2681           FOR_POOL_SOLVABLES(p)
2682             MAPSET(noobsmap, p);
2683         }
2684       else if (select == SOLVER_SOLVABLE_REPO)
2685         {
2686           Solvable *s;
2687           Repo *repo = pool_id2repo(pool, what);
2688           if (repo)
2689             FOR_REPO_SOLVABLES(repo, p, s)
2690               MAPSET(noobsmap, p);
2691         }
2692       FOR_JOB_SELECT(p, pp, select, what)
2693         MAPSET(noobsmap, p);
2694     }
2695 }
2696
2697 /*
2698  * add a rule created by a job, record job number and weak flag
2699  */
2700 static inline void
2701 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
2702 {
2703   solver_addrule(solv, p, d);
2704   queue_push(&solv->ruletojob, job);
2705   if (weak)
2706     queue_push(&solv->weakruleq, solv->nrules - 1);
2707 }
2708
2709 static inline void
2710 add_cleandeps_package(Solver *solv, Id p)
2711 {
2712   if (!solv->cleandeps_updatepkgs)
2713     {
2714       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
2715       queue_init(solv->cleandeps_updatepkgs);
2716     }
2717   queue_pushunique(solv->cleandeps_updatepkgs, p);
2718 }
2719
2720 static void
2721 add_update_target(Solver *solv, Id p, Id how)
2722 {
2723   Pool *pool = solv->pool;
2724   Solvable *s = pool->solvables + p;
2725   Repo *installed = solv->installed;
2726   Id pi, pip;
2727   if (!solv->update_targets)
2728     {
2729       solv->update_targets = solv_calloc(1, sizeof(Queue));
2730       queue_init(solv->update_targets);
2731     }
2732   if (s->repo == installed)
2733     {
2734       queue_push2(solv->update_targets, p, p);
2735       return;
2736     }
2737   FOR_PROVIDES(pi, pip, s->name)
2738     {
2739       Solvable *si = pool->solvables + pi;
2740       if (si->repo != installed || si->name != s->name)
2741         continue;
2742       if (how & SOLVER_FORCEBEST)
2743         {
2744           if (!solv->bestupdatemap.size)
2745             map_grow(&solv->bestupdatemap, installed->end - installed->start);
2746           MAPSET(&solv->bestupdatemap, pi - installed->start);
2747         }
2748       if (how & SOLVER_CLEANDEPS)
2749         add_cleandeps_package(solv, pi);
2750       queue_push2(solv->update_targets, pi, p);
2751       /* check if it's ok to keep the installed package */
2752       if (s->evr == si->evr && solvable_identical(s, si))
2753         queue_push2(solv->update_targets, pi, pi);
2754     }
2755   if (s->obsoletes)
2756     {
2757       Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2758       while ((obs = *obsp++) != 0)
2759         {
2760           FOR_PROVIDES(pi, pip, obs) 
2761             {
2762               Solvable *si = pool->solvables + pi;
2763               if (si->repo != installed)
2764                 continue;
2765               if (si->name == s->name)
2766                 continue;       /* already handled above */
2767               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
2768                 continue;
2769               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
2770                 continue;
2771               if (how & SOLVER_FORCEBEST)
2772                 {
2773                   if (!solv->bestupdatemap.size)
2774                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
2775                   MAPSET(&solv->bestupdatemap, pi - installed->start);
2776                 }
2777               if (how & SOLVER_CLEANDEPS)
2778                 add_cleandeps_package(solv, pi);
2779               queue_push2(solv->update_targets, pi, p);
2780             }
2781         }
2782     }
2783 }
2784
2785 static int
2786 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
2787 {
2788   const Id *a = ap;
2789   const Id *b = bp;
2790   if (a[0] - b[0])
2791     return a[0] - b[0];
2792   return a[1] - b[1];
2793 }
2794
2795 static void
2796 transform_update_targets(Solver *solv)
2797 {
2798   Repo *installed = solv->installed;
2799   Queue *update_targets = solv->update_targets;
2800   int i, j;
2801   Id p, q, lastp, lastq;
2802
2803   if (!update_targets->count)
2804     {
2805       queue_free(update_targets);
2806       solv->update_targets = solv_free(update_targets);
2807       return;
2808     }
2809   if (update_targets->count > 2)
2810     solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
2811   queue_insertn(update_targets, 0, installed->end - installed->start);
2812   lastp = lastq = 0;
2813   for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
2814     {
2815       if ((p = update_targets->elements[i]) != lastp)
2816         {
2817           if (!solv->updatemap.size)
2818             map_grow(&solv->updatemap, installed->end - installed->start);
2819           MAPSET(&solv->updatemap, p - installed->start);
2820           update_targets->elements[j++] = 0;                    /* finish old set */
2821           update_targets->elements[p - installed->start] = j;   /* start new set */
2822           lastp = p;
2823           lastq = 0;
2824         }
2825       if ((q = update_targets->elements[i + 1]) != lastq)
2826         {
2827           update_targets->elements[j++] = q;
2828           lastq = q;
2829         }
2830     }
2831   queue_truncate(update_targets, j);
2832   queue_push(update_targets, 0);        /* finish last set */
2833 }
2834
2835
2836 static void
2837 addedmap2deduceq(Solver *solv, Map *addedmap)
2838 {
2839   Pool *pool = solv->pool;
2840   int i, j;
2841   Id p;
2842   Rule *r;
2843
2844   queue_empty(&solv->addedmap_deduceq);
2845   for (i = 2, j = solv->rpmrules_end - 1; i < pool->nsolvables && j > 0; j--)
2846     {
2847       r = solv->rules + j;
2848       if (r->p >= 0)
2849         continue;
2850       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2851         continue;
2852       p = -r->p;
2853       if (!MAPTST(addedmap, p))
2854         {
2855           /* should never happen, but... */
2856           if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
2857             queue_push(&solv->addedmap_deduceq, -p);
2858           continue;
2859         }
2860       for (; i < p; i++)
2861         if (MAPTST(addedmap, i))
2862           queue_push(&solv->addedmap_deduceq, i);
2863       if (i == p)
2864         i++;
2865     }
2866   for (; i < pool->nsolvables; i++)
2867     if (MAPTST(addedmap, i))
2868       queue_push(&solv->addedmap_deduceq, i);
2869   j = 0;
2870   for (i = 2; i < pool->nsolvables; i++)
2871     if (MAPTST(addedmap, i))
2872       j++;
2873 }
2874
2875 static void 
2876 deduceq2addedmap(Solver *solv, Map *addedmap)
2877 {
2878   int j;
2879   Id p;
2880   Rule *r;
2881   for (j = solv->rpmrules_end - 1; j > 0; j--)
2882     {
2883       r = solv->rules + j;
2884       if (r->d < 0 && r->p)
2885         solver_enablerule(solv, r);
2886       if (r->p >= 0)
2887         continue;
2888       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2889         continue;
2890       p = -r->p;
2891       MAPSET(addedmap, p);
2892     }
2893   for (j = 0; j < solv->addedmap_deduceq.count; j++)
2894     {
2895       p = solv->addedmap_deduceq.elements[j];
2896       if (p > 0)
2897         MAPSET(addedmap, p);
2898       else
2899         MAPCLR(addedmap, p);
2900     }
2901 }
2902
2903
2904 /*
2905  *
2906  * solve job queue
2907  *
2908  */
2909
2910 int
2911 solver_solve(Solver *solv, Queue *job)
2912 {
2913   Pool *pool = solv->pool;
2914   Repo *installed = solv->installed;
2915   int i;
2916   int oldnrules, initialnrules;
2917   Map addedmap;                /* '1' == have rpm-rules for solvable */
2918   Map installcandidatemap;
2919   Id how, what, select, name, weak, p, pp, d;
2920   Queue q;
2921   Solvable *s;
2922   Rule *r;
2923   int now, solve_start;
2924   int hasdupjob = 0;
2925   int hasbestinstalljob = 0;
2926
2927   solve_start = solv_timems(0);
2928
2929   /* log solver options */
2930   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
2931   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
2932   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
2933   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
2934   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors);
2935   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
2936
2937   /* create whatprovides if not already there */
2938   if (!pool->whatprovides)
2939     pool_createwhatprovides(pool);
2940
2941   /* create obsolete index */
2942   policy_create_obsolete_index(solv);
2943
2944   /* remember job */
2945   queue_free(&solv->job);
2946   queue_init_clone(&solv->job, job);
2947   solv->pooljobcnt = pool->pooljobs.count;
2948   if (pool->pooljobs.count)
2949     {
2950       queue_insertn(&solv->job, 0, pool->pooljobs.count);
2951       memcpy(solv->job.elements, pool->pooljobs.elements, pool->pooljobs.count * sizeof(Id));
2952     }
2953   job = &solv->job;
2954
2955   /* free old stuff */
2956   if (solv->update_targets)
2957     {
2958       queue_free(solv->update_targets);
2959       solv->update_targets = solv_free(solv->update_targets);
2960     }
2961   if (solv->cleandeps_updatepkgs)
2962     {
2963       queue_free(solv->cleandeps_updatepkgs);
2964       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
2965     }
2966   queue_empty(&solv->ruleassertions);
2967   solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
2968   solv->choicerules_ref = solv_free(solv->choicerules_ref);
2969   if (solv->noupdate.size)
2970     map_empty(&solv->noupdate);
2971   if (solv->noobsoletes.size)
2972     {
2973       map_free(&solv->noobsoletes);
2974       map_init(&solv->noobsoletes, 0);
2975     }
2976   solv->updatemap_all = 0;
2977   if (solv->updatemap.size)
2978     {
2979       map_free(&solv->updatemap);
2980       map_init(&solv->updatemap, 0);
2981     }
2982   solv->bestupdatemap_all = 0;
2983   if (solv->bestupdatemap.size)
2984     {
2985       map_free(&solv->bestupdatemap);
2986       map_init(&solv->bestupdatemap, 0);
2987     }
2988   solv->fixmap_all = 0;
2989   if (solv->fixmap.size)
2990     {
2991       map_free(&solv->fixmap);
2992       map_init(&solv->fixmap, 0);
2993     }
2994   solv->dupmap_all = 0;
2995   if (solv->dupmap.size)
2996     {
2997       map_free(&solv->dupmap);
2998       map_init(&solv->dupmap, 0);
2999     }
3000   if (solv->dupinvolvedmap.size)
3001     {
3002       map_free(&solv->dupinvolvedmap);
3003       map_init(&solv->dupinvolvedmap, 0);
3004     }
3005   solv->droporphanedmap_all = 0;
3006   if (solv->droporphanedmap.size)
3007     {
3008       map_free(&solv->droporphanedmap);
3009       map_init(&solv->droporphanedmap, 0);
3010     }
3011   if (solv->cleandepsmap.size)
3012     {
3013       map_free(&solv->cleandepsmap);
3014       map_init(&solv->cleandepsmap, 0);
3015     }
3016   
3017   queue_empty(&solv->weakruleq);
3018   solv->watches = solv_free(solv->watches);
3019   queue_empty(&solv->ruletojob);
3020   if (solv->decisionq.count)
3021     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
3022   queue_empty(&solv->decisionq);
3023   queue_empty(&solv->decisionq_why);
3024   solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
3025   queue_empty(&solv->learnt_why);
3026   queue_empty(&solv->learnt_pool);
3027   queue_empty(&solv->branches);
3028   solv->propagate_index = 0;
3029   queue_empty(&solv->problems);
3030   queue_empty(&solv->solutions);
3031   queue_empty(&solv->orphaned);
3032   solv->stats_learned = solv->stats_unsolvable = 0;
3033   if (solv->recommends_index)
3034     {
3035       map_empty(&solv->recommendsmap);
3036       map_empty(&solv->suggestsmap);
3037       solv->recommends_index = 0;
3038     }
3039   solv->multiversionupdaters = solv_free(solv->multiversionupdaters);
3040   
3041
3042   /*
3043    * create basic rule set of all involved packages
3044    * use addedmap bitmap to make sure we don't create rules twice
3045    */
3046
3047   /* create noobsolete map if needed */
3048   solver_calculate_noobsmap(pool, job, &solv->noobsoletes);
3049
3050   map_init(&addedmap, pool->nsolvables);
3051   MAPSET(&addedmap, SYSTEMSOLVABLE);
3052
3053   map_init(&installcandidatemap, pool->nsolvables);
3054   queue_init(&q);
3055
3056   now = solv_timems(0);
3057   /*
3058    * create rules for all package that could be involved with the solving
3059    * so called: rpm rules
3060    *
3061    */
3062   initialnrules = solv->rpmrules_end ? solv->rpmrules_end : 1;
3063   if (initialnrules > 1)
3064     deduceq2addedmap(solv, &addedmap);
3065   if (solv->nrules != initialnrules)
3066     solver_shrinkrules(solv, initialnrules);
3067   solv->nrules = initialnrules;
3068   solv->rpmrules_end = 0;
3069   
3070   if (installed)
3071     {
3072       /* check for update/verify jobs as they need to be known early */
3073       for (i = 0; i < job->count; i += 2)
3074         {
3075           how = job->elements[i];
3076           what = job->elements[i + 1];
3077           select = how & SOLVER_SELECTMASK;
3078           switch (how & SOLVER_JOBMASK)
3079             {
3080             case SOLVER_VERIFY:
3081               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3082                 solv->fixmap_all = 1;
3083               FOR_JOB_SELECT(p, pp, select, what)
3084                 {
3085                   s = pool->solvables + p;
3086                   if (s->repo != installed)
3087                     continue;
3088                   if (!solv->fixmap.size)
3089                     map_grow(&solv->fixmap, installed->end - installed->start);
3090                   MAPSET(&solv->fixmap, p - installed->start);
3091                 }
3092               break;
3093             case SOLVER_UPDATE:
3094               if (select == SOLVER_SOLVABLE_ALL)
3095                 {
3096                   solv->updatemap_all = 1;
3097                   if (how & SOLVER_FORCEBEST)
3098                     solv->bestupdatemap_all = 1;
3099                   if (how & SOLVER_CLEANDEPS)
3100                     {
3101                       FOR_REPO_SOLVABLES(installed, p, s)
3102                         add_cleandeps_package(solv, p);
3103                     }
3104                 }
3105               else if (select == SOLVER_SOLVABLE_REPO)
3106                 {
3107                   Repo *repo = pool_id2repo(pool, what);
3108                   if (!repo)
3109                     break;
3110                   if (repo == installed && !(how & SOLVER_TARGETED))
3111                     {
3112                       solv->updatemap_all = 1;
3113                       if (how & SOLVER_FORCEBEST)
3114                         solv->bestupdatemap_all = 1;
3115                       if (how & SOLVER_CLEANDEPS)
3116                         {
3117                           FOR_REPO_SOLVABLES(installed, p, s)
3118                             add_cleandeps_package(solv, p);
3119                         }
3120                       break;
3121                     }
3122                   if (solv->noautotarget && !(how & SOLVER_TARGETED))
3123                     break;
3124                   /* targeted update */
3125                   FOR_REPO_SOLVABLES(repo, p, s)
3126                     add_update_target(solv, p, how);
3127                 }
3128               else
3129                 {
3130                   if (!(how & SOLVER_TARGETED))
3131                     {
3132                       int targeted = 1;
3133                       FOR_JOB_SELECT(p, pp, select, what)
3134                         {
3135                           s = pool->solvables + p;
3136                           if (s->repo != installed)
3137                             continue;
3138                           if (!solv->updatemap.size)
3139                             map_grow(&solv->updatemap, installed->end - installed->start);
3140                           MAPSET(&solv->updatemap, p - installed->start);
3141                           if (how & SOLVER_FORCEBEST)
3142                             {
3143                               if (!solv->bestupdatemap.size)
3144                                 map_grow(&solv->bestupdatemap, installed->end - installed->start);
3145                               MAPSET(&solv->bestupdatemap, p - installed->start);
3146                             }
3147                           if (how & SOLVER_CLEANDEPS)
3148                             add_cleandeps_package(solv, p);
3149                           targeted = 0;
3150                         }
3151                       if (!targeted || solv->noautotarget)
3152                         break;
3153                     }
3154                   FOR_JOB_SELECT(p, pp, select, what)
3155                     add_update_target(solv, p, how);
3156                 }
3157               break;
3158             default:
3159               break;
3160             }
3161         }
3162
3163       if (solv->update_targets)
3164         transform_update_targets(solv);
3165
3166       oldnrules = solv->nrules;
3167       FOR_REPO_SOLVABLES(installed, p, s)
3168         solver_addrpmrulesforsolvable(solv, s, &addedmap);
3169       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3170       oldnrules = solv->nrules;
3171       FOR_REPO_SOLVABLES(installed, p, s)
3172         solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
3173       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3174     }
3175
3176   /*
3177    * create rules for all packages involved in the job
3178    * (to be installed or removed)
3179    */
3180     
3181   oldnrules = solv->nrules;
3182   for (i = 0; i < job->count; i += 2)
3183     {
3184       how = job->elements[i];
3185       what = job->elements[i + 1];
3186       select = how & SOLVER_SELECTMASK;
3187
3188       switch (how & SOLVER_JOBMASK)
3189         {
3190         case SOLVER_INSTALL:
3191           FOR_JOB_SELECT(p, pp, select, what)
3192             {
3193               MAPSET(&installcandidatemap, p);
3194               solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3195             }
3196           break;
3197         case SOLVER_DISTUPGRADE:
3198           if (select == SOLVER_SOLVABLE_ALL)
3199             {
3200               solv->dupmap_all = 1;
3201               solv->updatemap_all = 1;
3202               if (how & SOLVER_FORCEBEST)
3203                 solv->bestupdatemap_all = 1;
3204             }
3205           if (!solv->dupmap_all)
3206             hasdupjob = 1;
3207           break;
3208         default:
3209           break;
3210         }
3211     }
3212   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3213
3214     
3215   /*
3216    * add rules for suggests, enhances
3217    */
3218   oldnrules = solv->nrules;
3219   solver_addrpmrulesforweak(solv, &addedmap);
3220   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3221
3222   /*
3223    * first pass done, we now have all the rpm rules we need.
3224    * unify existing rules before going over all job rules and
3225    * policy rules.
3226    * at this point the system is always solvable,
3227    * as an empty system (remove all packages) is a valid solution
3228    */
3229
3230   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3231     {
3232       int possible = 0, installable = 0;
3233       for (i = 1; i < pool->nsolvables; i++)
3234         {
3235           if (pool_installable(pool, pool->solvables + i))
3236             installable++;
3237           if (MAPTST(&addedmap, i))
3238             possible++;
3239         }
3240       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3241     }
3242
3243   if (solv->nrules > initialnrules)
3244     solver_unifyrules(solv);                    /* remove duplicate rpm rules */
3245   solv->rpmrules_end = solv->nrules;            /* mark end of rpm rules */
3246
3247   if (solv->nrules > initialnrules)
3248     addedmap2deduceq(solv, &addedmap);          /* so that we can recreate the addedmap */
3249
3250   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3251   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now));
3252
3253   /* create dup maps if needed. We need the maps early to create our
3254    * update rules */
3255   if (hasdupjob)
3256     solver_createdupmaps(solv);
3257
3258   /*
3259    * create feature rules
3260    * 
3261    * foreach installed:
3262    *   create assertion (keep installed, if no update available)
3263    *   or
3264    *   create update rule (A|update1(A)|update2(A)|...)
3265    * 
3266    * those are used later on to keep a version of the installed packages in
3267    * best effort mode
3268    */
3269     
3270   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3271   if (installed)
3272     {
3273       /* foreach possibly installed solvable */
3274       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3275         {
3276           if (s->repo != installed)
3277             {
3278               solver_addrule(solv, 0, 0);       /* create dummy rule */
3279               continue;
3280             }
3281           solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3282         }
3283       /* make sure we accounted for all rules */
3284       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3285     }
3286   solv->featurerules_end = solv->nrules;
3287
3288     /*
3289      * Add update rules for installed solvables
3290      * 
3291      * almost identical to feature rules
3292      * except that downgrades/archchanges/vendorchanges are not allowed
3293      */
3294     
3295   solv->updaterules = solv->nrules;
3296
3297   if (installed)
3298     { /* foreach installed solvables */
3299       /* we create all update rules, but disable some later on depending on the job */
3300       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3301         {
3302           Rule *sr;
3303
3304           if (s->repo != installed)
3305             {
3306               solver_addrule(solv, 0, 0);       /* create dummy rule */
3307               continue;
3308             }
3309           solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
3310           /*
3311            * check for and remove duplicate
3312            */
3313           r = solv->rules + solv->nrules - 1;           /* r: update rule */
3314           sr = r - (installed->end - installed->start); /* sr: feature rule */
3315           /* it's orphaned if there is no feature rule or the feature rule
3316            * consists just of the installed package */
3317           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
3318             queue_push(&solv->orphaned, i);
3319           if (!r->p)
3320             {
3321               assert(solv->dupmap_all && !sr->p);
3322               continue;
3323             }
3324           if (!solver_rulecmp(solv, r, sr))
3325             memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
3326           else
3327             solver_disablerule(solv, sr);       /* disable feature rule */
3328         }
3329       /* consistency check: we added a rule for _every_ installed solvable */
3330       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3331     }
3332   solv->updaterules_end = solv->nrules;
3333
3334
3335   /*
3336    * now add all job rules
3337    */
3338
3339   solv->jobrules = solv->nrules;
3340   for (i = 0; i < job->count; i += 2)
3341     {
3342       oldnrules = solv->nrules;
3343
3344       if (i && i == solv->pooljobcnt)
3345         POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
3346       how = job->elements[i];
3347       what = job->elements[i + 1];
3348       weak = how & SOLVER_WEAK;
3349       select = how & SOLVER_SELECTMASK;
3350       switch (how & SOLVER_JOBMASK)
3351         {
3352         case SOLVER_INSTALL:
3353           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3354           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3355             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3356           if (select == SOLVER_SOLVABLE)
3357             {
3358               p = what;
3359               d = 0;
3360             }
3361           else
3362             {
3363               queue_empty(&q);
3364               FOR_JOB_SELECT(p, pp, select, what)
3365                 queue_push(&q, p);
3366               if (!q.count)
3367                 {
3368                   /* no candidate found, make this an impossible rule */
3369                   queue_push(&q, -SYSTEMSOLVABLE);
3370                 }
3371               p = queue_shift(&q);      /* get first candidate */
3372               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
3373             }
3374           /* force install of namespace supplements hack */
3375           if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3376             {
3377               Reldep *rd = GETRELDEP(pool, what);
3378               if (rd->flags == REL_NAMESPACE)
3379                 {
3380                   p = SYSTEMSOLVABLE;
3381                   if (!solv->installsuppdepq)
3382                     {
3383                       solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3384                       queue_init(solv->installsuppdepq);
3385                     }
3386                   queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3387                 }
3388             }
3389           solver_addjobrule(solv, p, d, i, weak);
3390           if (how & SOLVER_FORCEBEST)
3391             hasbestinstalljob = 1;
3392           break;
3393         case SOLVER_ERASE:
3394           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3395           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3396             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3397           /* specific solvable: by id or by nevra */
3398           name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3399           if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
3400             {
3401               FOR_POOL_SOLVABLES(p)
3402                 solver_addjobrule(solv, -p, 0, i, weak);
3403             }
3404           else if (select == SOLVER_SOLVABLE_REPO)
3405             {
3406               Repo *repo = pool_id2repo(pool, what);
3407               if (repo)
3408                 FOR_REPO_SOLVABLES(repo, p, s)
3409                   solver_addjobrule(solv, -p, 0, i, weak);
3410             }
3411           FOR_JOB_SELECT(p, pp, select, what)
3412             {
3413               s = pool->solvables + p;
3414               if (installed && s->repo == installed)
3415                 name = !name ? s->name : -1;
3416               solver_addjobrule(solv, -p, 0, i, weak);
3417             }
3418           /* special case for "erase a specific solvable": we also
3419            * erase all other solvables with that name, so that they
3420            * don't get picked up as replacement.
3421            * name is > 0 if exactly one installed solvable matched.
3422            */
3423           /* XXX: look also at packages that obsolete this package? */
3424           if (name > 0)
3425             {
3426               int j, k;
3427               k = solv->nrules;
3428               FOR_PROVIDES(p, pp, name)
3429                 {
3430                   s = pool->solvables + p;
3431                   if (s->name != name)
3432                     continue;
3433                   /* keep other versions installed */
3434                   if (s->repo == installed)
3435                     continue;
3436                   /* keep installcandidates of other jobs */
3437                   if (MAPTST(&installcandidatemap, p))
3438                     continue;
3439                   /* don't add the same rule twice */
3440                   for (j = oldnrules; j < k; j++)
3441                     if (solv->rules[j].p == -p)
3442                       break;
3443                   if (j == k)
3444                     solver_addjobrule(solv, -p, 0, i, weak);    /* remove by id */
3445                 }
3446             }
3447           break;
3448
3449         case SOLVER_UPDATE:
3450           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3451           break;
3452         case SOLVER_VERIFY:
3453           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3454           break;
3455         case SOLVER_WEAKENDEPS:
3456           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3457           if (select != SOLVER_SOLVABLE)
3458             break;
3459           s = pool->solvables + what;
3460           weaken_solvable_deps(solv, what);
3461           break;
3462         case SOLVER_NOOBSOLETES:
3463           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3464           break;
3465         case SOLVER_LOCK:
3466           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3467           if (select == SOLVER_SOLVABLE_ALL)
3468             {
3469               FOR_POOL_SOLVABLES(p)
3470                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3471             }
3472           else if (select == SOLVER_SOLVABLE_REPO)
3473             {
3474               Repo *repo = pool_id2repo(pool, what);
3475               if (repo)
3476                 FOR_REPO_SOLVABLES(repo, p, s)
3477                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3478             }
3479           FOR_JOB_SELECT(p, pp, select, what)
3480             solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3481           break;
3482         case SOLVER_DISTUPGRADE:
3483           POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3484           break;
3485         case SOLVER_DROP_ORPHANED:
3486           POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3487           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3488             solv->droporphanedmap_all = 1;
3489           FOR_JOB_SELECT(p, pp, select, what)
3490             {
3491               s = pool->solvables + p;
3492               if (!installed || s->repo != installed)
3493                 continue;
3494               if (!solv->droporphanedmap.size)
3495                 map_grow(&solv->droporphanedmap, installed->end - installed->start);
3496               MAPSET(&solv->droporphanedmap, p - installed->start);
3497             }
3498           break;
3499         case SOLVER_USERINSTALLED:
3500           POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3501           break;
3502         default:
3503           POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3504           break;
3505         }
3506         
3507         /*
3508          * debug
3509          */
3510         
3511       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3512         {
3513           int j;
3514           if (solv->nrules == oldnrules)
3515             POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
3516           for (j = oldnrules; j < solv->nrules; j++)
3517             {
3518               POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
3519               solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3520             }
3521         }
3522     }
3523   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3524   solv->jobrules_end = solv->nrules;
3525
3526   /* now create infarch and dup rules */
3527   if (!solv->noinfarchcheck)
3528     {
3529       solver_addinfarchrules(solv, &addedmap);
3530       if (pool->obsoleteusescolors)
3531         {
3532           /* currently doesn't work well with infarch rules, so make
3533            * them weak */
3534           for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3535             queue_push(&solv->weakruleq, i);
3536         }
3537     }
3538   else
3539     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3540
3541   if (hasdupjob)
3542     solver_addduprules(solv, &addedmap);
3543   else
3544     solv->duprules = solv->duprules_end = solv->nrules;
3545
3546   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3547     solver_addbestrules(solv, hasbestinstalljob);
3548   else
3549     solv->bestrules = solv->bestrules_end = solv->nrules;
3550
3551   if (hasdupjob)
3552     solver_freedupmaps(solv);   /* no longer needed */
3553
3554   if (1)
3555     solver_addchoicerules(solv);
3556   else
3557     solv->choicerules = solv->choicerules_end = solv->nrules;
3558
3559   if (0)
3560     {
3561       for (i = solv->featurerules; i < solv->nrules; i++)
3562         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3563     }
3564   /* all rules created
3565    * --------------------------------------------------------------
3566    * prepare for solving
3567    */
3568     
3569   /* free unneeded memory */
3570   map_free(&addedmap);
3571   map_free(&installcandidatemap);
3572   queue_free(&q);
3573
3574   POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
3575   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3576
3577   /* create weak map */
3578   map_init(&solv->weakrulemap, solv->nrules);
3579   for (i = 0; i < solv->weakruleq.count; i++)
3580     {
3581       p = solv->weakruleq.elements[i];
3582       MAPSET(&solv->weakrulemap, p);
3583     }
3584
3585   /* enable cleandepsmap creation if we have updatepkgs */
3586   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
3587     map_grow(&solv->cleandepsmap, installed->end - installed->start);
3588   /* no mistakes */
3589   if (solv->cleandeps_mistakes)
3590     {    
3591       queue_free(solv->cleandeps_mistakes);
3592       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
3593     }    
3594
3595   /* all new rules are learnt after this point */
3596   solv->learntrules = solv->nrules;
3597
3598   /* create watches chains */
3599   makewatches(solv);
3600
3601   /* create assertion index. it is only used to speed up
3602    * makeruledecsions() a bit */
3603   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
3604     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
3605       queue_push(&solv->ruleassertions, i);
3606
3607   /* disable update rules that conflict with our job */
3608   solver_disablepolicyrules(solv);
3609
3610   /* make initial decisions based on assertion rules */
3611   makeruledecisions(solv);
3612   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
3613
3614   /*
3615    * ********************************************
3616    * solve!
3617    * ********************************************
3618    */
3619     
3620   now = solv_timems(0);
3621   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
3622   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
3623
3624   /*
3625    * prepare solution queue if there were problems
3626    */
3627   solver_prepare_solutions(solv);
3628
3629   POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
3630   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
3631
3632   /* return number of problems */
3633   return solv->problems.count ? solv->problems.count / 2 : 0;
3634 }
3635
3636 Transaction *
3637 solver_create_transaction(Solver *solv)
3638 {
3639   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->noobsoletes);
3640 }
3641
3642 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
3643 {
3644   queue_free(orphanedq);
3645   queue_init_clone(orphanedq, &solv->orphaned);
3646 }
3647
3648 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
3649 {
3650   Pool *pool = solv->pool;
3651   Queue redoq, disabledq;
3652   int goterase, i;
3653   Solvable *s;
3654   Rule *r;
3655   Map obsmap;
3656
3657   if (!recommendationsq && !suggestionsq)
3658     return;
3659
3660   map_init(&obsmap, pool->nsolvables);
3661   if (solv->installed)
3662     {
3663       Id obs, *obsp, p, po, ppo;
3664       for (p = solv->installed->start; p < solv->installed->end; p++)
3665         {
3666           s = pool->solvables + p;
3667           if (s->repo != solv->installed || !s->obsoletes)
3668             continue;
3669           if (solv->decisionmap[p] <= 0)
3670             continue;
3671           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
3672             continue;
3673           obsp = s->repo->idarraydata + s->obsoletes;
3674           /* foreach obsoletes */
3675           while ((obs = *obsp++) != 0)
3676             FOR_PROVIDES(po, ppo, obs)
3677               MAPSET(&obsmap, po);
3678         }
3679     }
3680
3681   queue_init(&redoq);
3682   queue_init(&disabledq);
3683   goterase = 0;
3684   /* disable all erase jobs (including weak "keep uninstalled" rules) */
3685   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
3686     {
3687       if (r->d < 0)     /* disabled ? */
3688         continue;
3689       if (r->p >= 0)    /* install job? */
3690         continue;
3691       queue_push(&disabledq, i);
3692       solver_disablerule(solv, r);
3693       goterase++;
3694     }
3695   
3696   if (goterase)
3697     {
3698       enabledisablelearntrules(solv);
3699       removedisabledconflicts(solv, &redoq);
3700     }
3701
3702   /*
3703    * find recommended packages
3704    */
3705   if (recommendationsq)
3706     {
3707       Id rec, *recp, p, pp;
3708
3709       queue_empty(recommendationsq);
3710       /* create map of all recommened packages */
3711       solv->recommends_index = -1;
3712       MAPZERO(&solv->recommendsmap);
3713
3714       /* put all packages the solver already chose in the map */
3715       if (solv->decisioncnt_weak)
3716         {
3717           for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
3718             {
3719               Id why;
3720               why = solv->decisionq_why.elements[i];
3721               if (why)
3722                 continue;       /* forced by unit rule */
3723               p = solv->decisionq.elements[i];
3724               if (p < 0)
3725                 continue;
3726               MAPSET(&solv->recommendsmap, p);
3727             }
3728         }
3729
3730       for (i = 0; i < solv->decisionq.count; i++)
3731         {
3732           p = solv->decisionq.elements[i];
3733           if (p < 0)
3734             continue;
3735           s = pool->solvables + p;
3736           if (s->recommends)
3737             {
3738               recp = s->repo->idarraydata + s->recommends;
3739               while ((rec = *recp++) != 0)
3740                 {
3741                   FOR_PROVIDES(p, pp, rec)
3742                     if (solv->decisionmap[p] > 0)
3743                       break;
3744                   if (p)
3745                     {
3746                       if (!noselected)
3747                         {
3748                           FOR_PROVIDES(p, pp, rec)
3749                             if (solv->decisionmap[p] > 0)
3750                               MAPSET(&solv->recommendsmap, p);
3751                         }
3752                       continue; /* p != 0: already fulfilled */
3753                     }
3754                   FOR_PROVIDES(p, pp, rec)
3755                     MAPSET(&solv->recommendsmap, p);
3756                 }
3757             }
3758         }
3759       for (i = 1; i < pool->nsolvables; i++)
3760         {
3761           if (solv->decisionmap[i] < 0)
3762             continue;
3763           if (solv->decisionmap[i] > 0 && noselected)
3764             continue;
3765           if (MAPTST(&obsmap, i))
3766             continue;
3767           s = pool->solvables + i;
3768           if (!MAPTST(&solv->recommendsmap, i))
3769             {
3770               if (!s->supplements)
3771                 continue;
3772               if (!pool_installable(pool, s))
3773                 continue;
3774               if (!solver_is_supplementing(solv, s))
3775                 continue;
3776             }
3777           queue_push(recommendationsq, i);
3778         }
3779       /* we use MODE_SUGGEST here so that repo prio is ignored */
3780       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
3781     }
3782
3783   /*
3784    * find suggested packages
3785    */
3786     
3787   if (suggestionsq)
3788     {
3789       Id sug, *sugp, p, pp;
3790
3791       queue_empty(suggestionsq);
3792       /* create map of all suggests that are still open */
3793       solv->recommends_index = -1;
3794       MAPZERO(&solv->suggestsmap);
3795       for (i = 0; i < solv->decisionq.count; i++)
3796         {
3797           p = solv->decisionq.elements[i];
3798           if (p < 0)
3799             continue;
3800           s = pool->solvables + p;
3801           if (s->suggests)
3802             {
3803               sugp = s->repo->idarraydata + s->suggests;
3804               while ((sug = *sugp++) != 0)
3805                 {
3806                   FOR_PROVIDES(p, pp, sug)
3807                     if (solv->decisionmap[p] > 0)
3808                       break;
3809                   if (p)
3810                     {
3811                       if (!noselected)
3812                         {
3813                           FOR_PROVIDES(p, pp, sug)
3814                             if (solv->decisionmap[p] > 0)
3815                               MAPSET(&solv->suggestsmap, p);
3816                         }
3817                       continue; /* already fulfilled */
3818                     }
3819                   FOR_PROVIDES(p, pp, sug)
3820                     MAPSET(&solv->suggestsmap, p);
3821                 }
3822             }
3823         }
3824       for (i = 1; i < pool->nsolvables; i++)
3825         {
3826           if (solv->decisionmap[i] < 0)
3827             continue;
3828           if (solv->decisionmap[i] > 0 && noselected)
3829             continue;
3830           if (MAPTST(&obsmap, i))
3831             continue;
3832           s = pool->solvables + i;
3833           if (!MAPTST(&solv->suggestsmap, i))
3834             {
3835               if (!s->enhances)
3836                 continue;
3837               if (!pool_installable(pool, s))
3838                 continue;
3839               if (!solver_is_enhancing(solv, s))
3840                 continue;
3841             }
3842           queue_push(suggestionsq, i);
3843         }
3844       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
3845     }
3846
3847   /* undo removedisabledconflicts */
3848   if (redoq.count)
3849     undo_removedisabledconflicts(solv, &redoq);
3850   queue_free(&redoq);
3851   
3852   /* undo job rule disabling */
3853   for (i = 0; i < disabledq.count; i++)
3854     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
3855   queue_free(&disabledq);
3856   map_free(&obsmap);
3857 }
3858
3859
3860 /***********************************************************************/
3861 /* disk usage computations */
3862
3863 /*-------------------------------------------------------------------
3864  * 
3865  * calculate DU changes
3866  */
3867
3868 void
3869 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
3870 {
3871   Map installedmap;
3872
3873   solver_create_state_maps(solv, &installedmap, 0);
3874   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
3875   map_free(&installedmap);
3876 }
3877
3878
3879 /*-------------------------------------------------------------------
3880  * 
3881  * calculate changes in install size
3882  */
3883
3884 int
3885 solver_calc_installsizechange(Solver *solv)
3886 {
3887   Map installedmap;
3888   int change;
3889
3890   solver_create_state_maps(solv, &installedmap, 0);
3891   change = pool_calc_installsizechange(solv->pool, &installedmap);
3892   map_free(&installedmap);
3893   return change;
3894 }
3895
3896 void
3897 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
3898 {
3899   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
3900 }
3901
3902 void
3903 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
3904 {
3905   Pool *pool = solv->pool;
3906   Map installedmap;
3907   int i;
3908   pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
3909   pool_trivial_installable_noobsoletesmap(pool, &installedmap, pkgs, res, solv->noobsoletes.size ? &solv->noobsoletes : 0);
3910   for (i = 0; i < res->count; i++)
3911     if (res->elements[i] != -1)
3912       {
3913         Solvable *s = pool->solvables + pkgs->elements[i];
3914         if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap, solv))
3915           res->elements[i] = -1;
3916       }
3917   map_free(&installedmap);
3918 }
3919
3920 /*-------------------------------------------------------------------
3921  * 
3922  * decision introspection
3923  */
3924
3925 int
3926 solver_get_decisionlevel(Solver *solv, Id p)
3927 {
3928   return solv->decisionmap[p];
3929 }
3930
3931 void
3932 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
3933 {
3934   queue_free(decisionq);
3935   queue_init_clone(decisionq, &solv->decisionq);
3936 }
3937
3938 int
3939 solver_get_lastdecisionblocklevel(Solver *solv)
3940 {
3941   Id p;
3942   if (solv->decisionq.count == 0)
3943     return 0;
3944   p = solv->decisionq.elements[solv->decisionq.count - 1];
3945   if (p < 0)
3946     p = -p;
3947   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
3948 }
3949
3950 void
3951 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
3952 {
3953   Id p;
3954   int i;
3955
3956   queue_empty(decisionq);
3957   for (i = 0; i < solv->decisionq.count; i++)
3958     {
3959       p = solv->decisionq.elements[i];
3960       if (p < 0)
3961         p = -p;
3962       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3963         break;
3964     }
3965   if (i == solv->decisionq.count)
3966     return;
3967   for (i = 0; i < solv->decisionq.count; i++)
3968     {
3969       p = solv->decisionq.elements[i];
3970       if (p < 0)
3971         p = -p;
3972       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3973         queue_push(decisionq, p);
3974       else
3975         break;
3976     }
3977 }
3978
3979 int
3980 solver_describe_decision(Solver *solv, Id p, Id *infop)
3981 {
3982   int i;
3983   Id pp, why;
3984   
3985   if (infop)
3986     *infop = 0;
3987   if (!solv->decisionmap[p])
3988     return SOLVER_REASON_UNRELATED;
3989   pp = solv->decisionmap[p] < 0 ? -p : p;
3990   for (i = 0; i < solv->decisionq.count; i++)
3991     if (solv->decisionq.elements[i] == pp)
3992       break;
3993   if (i == solv->decisionq.count)       /* just in case... */
3994     return SOLVER_REASON_UNRELATED;
3995   why = solv->decisionq_why.elements[i];
3996   if (why > 0)
3997     {
3998       if (infop)
3999         *infop = why;
4000       return SOLVER_REASON_UNIT_RULE;
4001     }
4002   why = -why;
4003   if (i < solv->decisioncnt_update)
4004     {
4005       if (i == 0)
4006         {
4007           if (infop)
4008             *infop = SYSTEMSOLVABLE;
4009           return SOLVER_REASON_KEEP_INSTALLED;
4010         }
4011       if (infop)
4012         *infop = why;
4013       return SOLVER_REASON_RESOLVE_JOB;
4014     }
4015   if (i < solv->decisioncnt_keep)
4016     {
4017       if (why == 0 && pp < 0)
4018         return SOLVER_REASON_CLEANDEPS_ERASE;
4019       if (infop)
4020         {
4021           if (why >= solv->updaterules && why < solv->updaterules_end)
4022             *infop = why - solv->updaterules;
4023           else if (why >= solv->featurerules && why < solv->featurerules_end)
4024             *infop = why - solv->featurerules;
4025         }
4026       return SOLVER_REASON_UPDATE_INSTALLED;
4027     }
4028   if (i < solv->decisioncnt_resolve)
4029     {
4030       if (why == 0 && pp < 0)
4031         return SOLVER_REASON_CLEANDEPS_ERASE;
4032       if (infop)
4033         {
4034           if (why >= solv->updaterules && why < solv->updaterules_end)
4035             *infop = why - solv->updaterules;
4036           else if (why >= solv->featurerules && why < solv->featurerules_end)
4037             *infop = why - solv->featurerules;
4038         }
4039       return SOLVER_REASON_KEEP_INSTALLED;
4040     }
4041   if (i < solv->decisioncnt_weak)
4042     {
4043       if (infop)
4044         *infop = why;
4045       return SOLVER_REASON_RESOLVE;
4046     }
4047   if (solv->decisionq.count < solv->decisioncnt_orphan)
4048     return SOLVER_REASON_WEAKDEP;
4049   return SOLVER_REASON_RESOLVE_ORPHAN;
4050 }
4051
4052
4053 void
4054 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
4055 {
4056   Pool *pool = solv->pool;
4057   int i;
4058   int level = solv->decisionmap[p];
4059   int decisionno;
4060   Solvable *s;
4061
4062   queue_empty(whyq);
4063   if (level < 0)
4064     return;     /* huh? */
4065   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
4066     if (solv->decisionq.elements[decisionno] == p)
4067       break;
4068   if (decisionno == solv->decisionq.count)
4069     return;     /* huh? */
4070   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
4071     return;     /* huh? */
4072
4073   /* 1) list all packages that recommend us */
4074   for (i = 1; i < pool->nsolvables; i++)
4075     {
4076       Id *recp, rec, pp2, p2;
4077       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
4078         continue;
4079       s = pool->solvables + i;
4080       if (!s->recommends)
4081         continue;
4082       if (!solv->addalreadyrecommended && s->repo == solv->installed)
4083         continue;
4084       recp = s->repo->idarraydata + s->recommends;
4085       while ((rec = *recp++) != 0)
4086         {
4087           int found = 0;
4088           FOR_PROVIDES(p2, pp2, rec)
4089             {
4090               if (p2 == p)
4091                 found = 1;
4092               else
4093                 {
4094                   /* if p2 is already installed, this recommends is ignored */
4095                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4096                     break;
4097                 }
4098             }
4099           if (!p2 && found)
4100             {
4101               queue_push(whyq, SOLVER_REASON_RECOMMENDED);
4102               queue_push2(whyq, p2, rec);
4103             }
4104         }
4105     }
4106   /* 2) list all supplements */
4107   s = pool->solvables + p;
4108   if (s->supplements && level > 0)
4109     {
4110       Id *supp, sup, pp2, p2;
4111       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
4112        * everything above our level in the decisionmap */
4113       for (i = decisionno; i < solv->decisionq.count; i++ )
4114         {
4115           p2 = solv->decisionq.elements[i];
4116           if (p2 > 0)
4117             solv->decisionmap[p2] = -solv->decisionmap[p2];
4118         }
4119       supp = s->repo->idarraydata + s->supplements;
4120       while ((sup = *supp++) != 0)
4121         if (solver_dep_fulfilled(solv, sup))
4122           {
4123             int found = 0;
4124             /* let's see if this is an easy supp */
4125             FOR_PROVIDES(p2, pp2, sup)
4126               {
4127                 if (!solv->addalreadyrecommended && solv->installed)
4128                   {
4129                     if (pool->solvables[p2].repo == solv->installed)
4130                       continue;
4131                   }
4132                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4133                   {
4134                     queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4135                     queue_push2(whyq, p2, sup);
4136                     found = 1;
4137                   }
4138               }
4139             if (!found)
4140               {
4141                 /* hard case, just note dependency with no package */
4142                 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4143                 queue_push2(whyq, 0, sup);
4144               }
4145           }
4146       for (i = decisionno; i < solv->decisionq.count; i++)
4147         {
4148           p2 = solv->decisionq.elements[i];
4149           if (p2 > 0)
4150             solv->decisionmap[p2] = -solv->decisionmap[p2];
4151         }
4152     }
4153 }
4154
4155 void
4156 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
4157 {
4158   Id p, pp;
4159   how &= SOLVER_SELECTMASK;
4160   queue_empty(pkgs);
4161   if (how == SOLVER_SOLVABLE_ALL)
4162     {
4163       FOR_POOL_SOLVABLES(p)
4164         queue_push(pkgs, p);
4165     }
4166   else if (how == SOLVER_SOLVABLE_REPO)
4167     {
4168       Repo *repo = pool_id2repo(pool, what);
4169       Solvable *s;
4170       if (repo)
4171         FOR_REPO_SOLVABLES(repo, p, s)
4172           queue_push(pkgs, p);
4173     }
4174   else
4175     {
4176       FOR_JOB_SELECT(p, pp, how, what)
4177         queue_push(pkgs, p);
4178     }
4179 }
4180
4181 int
4182 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4183 {
4184   Id p, pp, pi, pip;
4185   Id select = how & SOLVER_SELECTMASK;
4186   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4187     return 0;
4188   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4189     return 0;
4190   if (!pool->installed)
4191     return 1;
4192   FOR_JOB_SELECT(p, pp, select, what)
4193     if (pool->solvables[p].repo == pool->installed)
4194       return 0;
4195   /* hard work */
4196   FOR_JOB_SELECT(p, pp, select, what)
4197     {
4198       Solvable *s = pool->solvables + p;
4199       FOR_PROVIDES(pi, pip, s->name)
4200         {
4201           Solvable *si = pool->solvables + pi;
4202           if (si->repo != pool->installed || si->name != s->name)
4203             continue;
4204           return 0;
4205         }
4206       if (s->obsoletes)
4207         {
4208           Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4209           while ((obs = *obsp++) != 0)
4210             {
4211               FOR_PROVIDES(pi, pip, obs) 
4212                 {
4213                   Solvable *si = pool->solvables + pi;
4214                   if (si->repo != pool->installed)
4215                     continue;
4216                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4217                     continue;
4218                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4219                     continue;
4220                   return 0;
4221                 }
4222             }
4223         }
4224     }
4225   return 1;
4226 }