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