- filter packages from recommended package list that are
[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 "bitmap.h"
22 #include "pool.h"
23 #include "util.h"
24 #include "evr.h"
25 #include "policy.h"
26 #include "solverdebug.h"
27
28 #define RULES_BLOCK 63
29
30 static void disableupdaterules(Solver *solv, Queue *job, int jobidx);
31
32 /********************************************************************
33  *
34  * dependency check helpers
35  *
36  */
37
38 /*-------------------------------------------------------------------
39  * handle split provides
40  */
41
42 int
43 solver_splitprovides(Solver *solv, Id dep)
44 {
45   Pool *pool = solv->pool;
46   Id p, pp;
47   Reldep *rd;
48   Solvable *s;
49
50   if (!solv->dosplitprovides || !solv->installed)
51     return 0;
52   if (!ISRELDEP(dep))
53     return 0;
54   rd = GETRELDEP(pool, dep);
55   if (rd->flags != REL_WITH)
56     return 0;
57   FOR_PROVIDES(p, pp, dep)
58     {
59       s = pool->solvables + p;
60       if (s->repo == solv->installed && s->name == rd->name)
61         return 1;
62     }
63   return 0;
64 }
65
66
67 /*-------------------------------------------------------------------
68  * solver_dep_installed
69  */
70
71 int
72 solver_dep_installed(Solver *solv, Id dep)
73 {
74 #if 0
75   Pool *pool = solv->pool;
76   Id p, pp;
77
78   if (ISRELDEP(dep))
79     {
80       Reldep *rd = GETRELDEP(pool, dep);
81       if (rd->flags == REL_AND)
82         {
83           if (!solver_dep_installed(solv, rd->name))
84             return 0;
85           return solver_dep_installed(solv, rd->evr);
86         }
87       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
88         return solver_dep_installed(solv, rd->evr);
89     }
90   FOR_PROVIDES(p, pp, dep)
91     {
92       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
93         return 1;
94     }
95 #endif
96   return 0;
97 }
98
99
100 /*-------------------------------------------------------------------
101  * Check if dependenc is possible
102  * 
103  * this mirrors solver_dep_fulfilled
104  * but uses map m instead of the decisionmap
105  */
106
107 static inline int
108 dep_possible(Solver *solv, Id dep, Map *m)
109 {
110   Pool *pool = solv->pool;
111   Id p, pp;
112
113   if (ISRELDEP(dep))
114     {
115       Reldep *rd = GETRELDEP(pool, dep);
116       if (rd->flags == REL_AND)
117         {
118           if (!dep_possible(solv, rd->name, m))
119             return 0;
120           return dep_possible(solv, rd->evr, m);
121         }
122       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
123         return solver_splitprovides(solv, rd->evr);
124       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
125         return solver_dep_installed(solv, rd->evr);
126     }
127   FOR_PROVIDES(p, pp, dep)
128     {
129       if (MAPTST(m, p))
130         return 1;
131     }
132   return 0;
133 }
134
135 /********************************************************************
136  *
137  * Rule handling
138  *
139  * - unify rules, remove duplicates
140  */
141
142 static Pool *unifyrules_sortcmp_data;
143
144 /*-------------------------------------------------------------------
145  *
146  * compare rules for unification sort
147  *
148  */
149
150 static int
151 unifyrules_sortcmp(const void *ap, const void *bp)
152 {
153   Pool *pool = unifyrules_sortcmp_data;
154   Rule *a = (Rule *)ap;
155   Rule *b = (Rule *)bp;
156   Id *ad, *bd;
157   int x;
158
159   x = a->p - b->p;
160   if (x)
161     return x;                          /* p differs */
162
163   /* identical p */
164   if (a->d == 0 && b->d == 0)
165     return a->w2 - b->w2;              /* assertion: return w2 diff */
166
167   if (a->d == 0)                       /* a is assertion, b not */
168     {
169       x = a->w2 - pool->whatprovidesdata[b->d];
170       return x ? x : -1;
171     }
172
173   if (b->d == 0)                       /* b is assertion, a not */
174     {
175       x = pool->whatprovidesdata[a->d] - b->w2;
176       return x ? x : 1;
177     }
178
179   /* compare whatprovidesdata */
180   ad = pool->whatprovidesdata + a->d;
181   bd = pool->whatprovidesdata + b->d;
182   while (*bd)
183     if ((x = *ad++ - *bd++) != 0)
184       return x;
185   return *ad;
186 }
187
188
189 /*-------------------------------------------------------------------
190  *
191  * unify rules
192  * go over all rules and remove duplicates
193  */
194
195 static void
196 unifyrules(Solver *solv)
197 {
198   Pool *pool = solv->pool;
199   int i, j;
200   Rule *ir, *jr;
201
202   if (solv->nrules <= 1)               /* nothing to unify */
203     return;
204
205   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
206
207   /* sort rules first */
208   unifyrules_sortcmp_data = solv->pool;
209   qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
210
211   /* prune rules
212    * i = unpruned
213    * j = pruned
214    */
215   jr = 0;
216   for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
217     {
218       if (jr && !unifyrules_sortcmp(ir, jr))
219         continue;                      /* prune! */
220       jr = solv->rules + j++;          /* keep! */
221       if (ir != jr)
222         *jr = *ir;
223     }
224
225   /* reduced count from nrules to j rules */
226   POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
227
228   /* adapt rule buffer */
229   solv->nrules = j;
230   solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
231     /*
232      * debug: statistics
233      */
234   IF_POOLDEBUG (SAT_DEBUG_STATS)
235     {
236       int binr = 0;
237       int lits = 0;
238       Id *dp;
239       Rule *r;
240
241       for (i = 1; i < solv->nrules; i++)
242         {
243           r = solv->rules + i;
244           if (r->d == 0)
245             binr++;
246           else
247             {
248               dp = solv->pool->whatprovidesdata + r->d;
249               while (*dp++)
250                 lits++;
251             }
252         }
253       POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
254       POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
255     }
256   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
257 }
258
259 #if 0
260
261 /*
262  * hash rule
263  */
264
265 static Hashval
266 hashrule(Solver *solv, Id p, Id d, int n)
267 {
268   unsigned int x = (unsigned int)p;
269   int *dp;
270
271   if (n <= 1)
272     return (x * 37) ^ (unsigned int)d;
273   dp = solv->pool->whatprovidesdata + d;
274   while (*dp)
275     x = (x * 37) ^ (unsigned int)*dp++;
276   return x;
277 }
278 #endif
279
280
281 /*-------------------------------------------------------------------
282  * 
283  */
284
285 /*
286  * add rule
287  *  p = direct literal; always < 0 for installed rpm rules
288  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
289  *
290  *
291  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
292  *
293  * p < 0 : pkg id of A
294  * d > 0 : Offset in whatprovidesdata (list of providers of b)
295  *
296  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
297  * p < 0 : pkg id of A
298  * d < 0 : Id of solvable (e.g. B1)
299  *
300  * d == 0: unary rule, assertion => (A) or (-A)
301  *
302  *   Install:    p > 0, d = 0   (A)             user requested install
303  *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
304  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
305  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
306  *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
307  *                                              also used for obsoletes
308  *   ?:          p > 0, d < 0   (A|-B)          
309  *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
310  *
311  *   resulting watches:
312  *   ------------------
313  *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
314  *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
315  *   every other : w1 = p, w2 = whatprovidesdata[d];
316  *   Disabled rule: w1 = 0
317  *
318  *   always returns a rule for non-rpm rules
319  */
320
321 static Rule *
322 addrule(Solver *solv, Id p, Id d)
323 {
324   Pool *pool = solv->pool;
325   Rule *r = 0;
326   Id *dp = 0;
327
328   int n = 0;                           /* number of literals in rule - 1
329                                           0 = direct assertion (single literal)
330                                           1 = binary rule
331                                           >1 = 
332                                         */
333
334   /* it often happenes that requires lead to adding the same rpm rule
335    * multiple times, so we prune those duplicates right away to make
336    * the work for unifyrules a bit easier */
337
338   if (solv->nrules                      /* we already have rules */
339       && !solv->rpmrules_end)           /* but are not done with rpm rules */
340     {
341       r = solv->rules + solv->nrules - 1;   /* get the last added rule */
342       if (r->p == p && r->d == d && d != 0)   /* identical and not user requested */
343         return r;
344     }
345
346     /*
347      * compute number of literals (n) in rule
348      */
349     
350   if (d < 0)
351     {
352       /* always a binary rule */
353       if (p == d)
354         return 0;                      /* ignore self conflict */
355       n = 1;
356     }
357   else if (d > 0)
358     {
359       for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
360         if (*dp == -p)
361           return 0;                     /* rule is self-fulfilling */
362         
363       if (n == 1)   /* have single provider */
364         d = dp[-1];                     /* take single literal */
365     }
366
367   if (n == 1 && p > d && !solv->rpmrules_end)
368     {
369       /* smallest literal first so we can find dups */
370       n = p; p = d; d = n;             /* p <-> d */
371       n = 1;                           /* re-set n, was used as temp var */
372     }
373
374     /*
375      * check for duplicate
376      */
377     
378   /* check if the last added rule (r) is exactly the same as what we're looking for. */
379   if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
380     return r;  /* binary rule */
381
382     /* have n-ary rule with same first literal, check other literals */
383   if (r && n > 1 && r->d && r->p == p)
384     {
385       /* Rule where d is an offset in whatprovidesdata */
386       Id *dp2;
387       if (d == r->d)
388         return r;
389       dp2 = pool->whatprovidesdata + r->d;
390       for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
391         if (*dp != *dp2)
392           break;
393       if (*dp == *dp2)
394         return r;
395    }
396
397     /*
398      * allocate new rule
399      */
400
401   /* extend rule buffer */
402   solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
403   r = solv->rules + solv->nrules++;    /* point to rule space */
404
405     /*
406      * r = new rule
407      */
408     
409   r->p = p;
410   if (n == 0)
411     {
412       /* direct assertion, no watch needed */
413       r->d = 0;
414       r->w1 = p;
415       r->w2 = 0;
416     }
417   else if (n == 1)
418     {
419       /* binary rule */
420       r->d = 0;
421       r->w1 = p;
422       r->w2 = d;
423     }
424   else
425     {
426       r->d = d;
427       r->w1 = p;
428       r->w2 = pool->whatprovidesdata[d];
429     }
430   r->n1 = 0;
431   r->n2 = 0;
432
433   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
434     {
435       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
436       solver_printrule(solv, SAT_DEBUG_RULE_CREATION, r);
437     }
438
439   return r;
440 }
441
442 /*-------------------------------------------------------------------
443  * disable rule
444  */
445
446 static inline void
447 disablerule(Solver *solv, Rule *r)
448 {
449   if (r->d >= 0)
450     r->d = -r->d - 1;
451 }
452
453 /*-------------------------------------------------------------------
454  * enable rule
455  */
456
457 static inline void
458 enablerule(Solver *solv, Rule *r)
459 {
460   if (r->d < 0)
461     r->d = -r->d - 1;
462 }
463
464
465 /**********************************************************************************/
466
467 /* a problem is an item on the solver's problem list. It can either be >0, in that
468  * case it is a update rule, or it can be <0, which makes it refer to a job
469  * consisting of multiple job rules.
470  */
471
472 static void
473 disableproblem(Solver *solv, Id v)
474 {
475   Rule *r;
476   int i;
477   Id *jp;
478
479   if (v > 0)
480     {
481       disablerule(solv, solv->rules + v);
482       return;
483     }
484   v = -(v + 1);
485   jp = solv->ruletojob.elements;
486   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
487     if (*jp == v)
488       disablerule(solv, r);
489 }
490
491 /*-------------------------------------------------------------------
492  * enableproblem
493  */
494
495 static void
496 enableproblem(Solver *solv, Id v)
497 {
498   Rule *r;
499   int i;
500   Id *jp;
501
502   if (v > 0)
503     {
504       if (v >= solv->featurerules && v < solv->featurerules_end)
505         {
506           /* do not enable feature rule if update rule is enabled */
507           r = solv->rules + (v - solv->featurerules + solv->updaterules);
508           if (r->d >= 0)
509             return;
510         }
511       enablerule(solv, solv->rules + v);
512       if (v >= solv->updaterules && v < solv->updaterules_end)
513         {
514           /* disable feature rule when enabling update rule */
515           r = solv->rules + (v - solv->updaterules + solv->featurerules);
516           if (r->p)
517             disablerule(solv, r);
518         }
519       return;
520     }
521   v = -(v + 1);
522   jp = solv->ruletojob.elements;
523   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
524     if (*jp == v)
525       enablerule(solv, r);
526 }
527
528
529 /************************************************************************/
530
531 /*
532  * make assertion rules into decisions
533  * 
534  * go through update and job rules and add direct assertions
535  * to the decisionqueue. If we find a conflict, disable rules and
536  * add them to problem queue.
537  */
538
539 static void
540 makeruledecisions(Solver *solv)
541 {
542   Pool *pool = solv->pool;
543   int i, ri, ii;
544   Rule *r, *rr;
545   Id v, vv;
546   int decisionstart;
547
548   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions ; size decisionq: %d -----\n",solv->decisionq.count);
549
550   decisionstart = solv->decisionq.count;
551   for (ii = 0; ii < solv->ruleassertions.count; ii++)
552     {
553       ri = solv->ruleassertions.elements[ii];
554       r = solv->rules + ri;
555         
556       if (r->d < 0 || !r->p || r->w2)   /* disabled, dummy or no assertion */
557         continue;
558       /* do weak rules in phase 2 */
559       if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
560         continue;
561         
562       v = r->p;
563       vv = v > 0 ? v : -v;
564         
565       if (!solv->decisionmap[vv])          /* if not yet decided */
566         {
567             /*
568              * decide !
569              */
570           queue_push(&solv->decisionq, v);
571           queue_push(&solv->decisionq_why, r - solv->rules);
572           solv->decisionmap[vv] = v > 0 ? 1 : -1;
573           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
574             {
575               Solvable *s = solv->pool->solvables + vv;
576               if (v < 0)
577                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", solvable2str(solv->pool, s));
578               else
579                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "installing  %s (assertion)\n", solvable2str(solv->pool, s));
580             }
581           continue;
582         }
583         /*
584          * check previous decision: is it sane ?
585          */
586         
587       if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
588         continue;
589       if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
590         continue;
591         
592         /*
593          * found a conflict!
594          * 
595          * The rule (r) we're currently processing says something
596          * different (v = r->p) than a previous decision (decisionmap[abs(v)])
597          * on this literal
598          */
599         
600       if (ri >= solv->learntrules)
601         {
602           /* conflict with a learnt rule */
603           /* can happen when packages cannot be installed for
604            * multiple reasons. */
605           /* we disable the learnt rule in this case */
606           disablerule(solv, r);
607           continue;
608         }
609         
610         /*
611          * find the decision which is the "opposite" of the rule
612          */
613         
614       for (i = 0; i < solv->decisionq.count; i++)
615         if (solv->decisionq.elements[i] == -v)
616           break;
617       assert(i < solv->decisionq.count);         /* assert that we found it */
618         
619         /*
620          * conflict with system solvable ?
621          */
622         
623       if (v == -SYSTEMSOLVABLE) {
624         /* conflict with system solvable */
625         queue_push(&solv->problems, solv->learnt_pool.count);
626         queue_push(&solv->learnt_pool, ri);
627         queue_push(&solv->learnt_pool, 0);
628         POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
629         if  (ri >= solv->jobrules && ri < solv->jobrules_end)
630           v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
631         else
632           v = ri;
633         queue_push(&solv->problems, v);
634         queue_push(&solv->problems, 0);
635         disableproblem(solv, v);
636         continue;
637       }
638
639       assert(solv->decisionq_why.elements[i] > 0);
640         
641         /*
642          * conflict with an rpm rule ?
643          */
644         
645       if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
646         {
647           /* conflict with rpm rule assertion */
648           queue_push(&solv->problems, solv->learnt_pool.count);
649           queue_push(&solv->learnt_pool, ri);
650           queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
651           queue_push(&solv->learnt_pool, 0);
652           assert(v > 0 || v == -SYSTEMSOLVABLE);
653           POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
654           if (ri >= solv->jobrules && ri < solv->jobrules_end)
655             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
656           else
657             v = ri;
658           queue_push(&solv->problems, v);
659           queue_push(&solv->problems, 0);
660           disableproblem(solv, v);
661           continue;
662         }
663
664         /*
665          * conflict with another job or update/feature rule
666          */
667         
668       /* record proof */
669       queue_push(&solv->problems, solv->learnt_pool.count);
670       queue_push(&solv->learnt_pool, ri);
671       queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
672       queue_push(&solv->learnt_pool, 0);
673
674       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
675
676         /*
677          * push all of our rules (can only be feature or job rules)
678          * asserting this literal on the problem stack
679          */
680         
681       for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
682         {
683           if (rr->d < 0                          /* disabled */
684               || rr->w2)                         /*  or no assertion */
685             continue;
686           if (rr->p != vv                        /* not affecting the literal */
687               && rr->p != -vv)
688             continue;
689           if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
690             continue;
691             
692           POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
693             
694           solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, solv->rules + i);
695             
696           v = i;
697             /* is is a job rule ? */
698           if (i >= solv->jobrules && i < solv->jobrules_end)
699             v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
700             
701           queue_push(&solv->problems, v);
702           disableproblem(solv, v);
703         }
704       queue_push(&solv->problems, 0);
705
706        /*
707         * start over
708         * (back up from decisions)
709         */
710       while (solv->decisionq.count > decisionstart)
711         {
712           v = solv->decisionq.elements[--solv->decisionq.count];
713           --solv->decisionq_why.count;
714           vv = v > 0 ? v : -v;
715           solv->decisionmap[vv] = 0;
716         }
717       ii = -1; /* restarts loop at 0 */
718     }
719
720     /*
721      * phase 2: now do the weak assertions
722      */
723   for (ii = 0; ii < solv->ruleassertions.count; ii++)
724     {
725       ri = solv->ruleassertions.elements[ii];
726       r = solv->rules + ri;
727       if (r->d < 0 || r->w2)                     /* disabled or no assertion */
728         continue;
729       if (!MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
730         continue;
731       v = r->p;
732       vv = v > 0 ? v : -v;
733         /*
734          * decide !
735          * (if not yet decided)
736          */
737       if (!solv->decisionmap[vv])
738         {
739           queue_push(&solv->decisionq, v);
740           queue_push(&solv->decisionq_why, r - solv->rules);
741           solv->decisionmap[vv] = v > 0 ? 1 : -1;
742           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
743             {
744               Solvable *s = solv->pool->solvables + vv;
745               if (v < 0)
746                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", solvable2str(solv->pool, s));
747               else
748                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", solvable2str(solv->pool, s));
749             }
750           continue;
751         }
752         /*
753          * previously decided, sane ?
754          */
755       if (v > 0 && solv->decisionmap[vv] > 0)
756         continue;
757       if (v < 0 && solv->decisionmap[vv] < 0)
758         continue;
759         
760       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
761       solver_printrule(solv, SAT_DEBUG_UNSOLVABLE, r);
762
763       if (ri >= solv->jobrules && ri < solv->jobrules_end)
764         v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
765       else
766         v = ri;
767       disableproblem(solv, v);
768       if (v < 0)
769         disableupdaterules(solv, solv->job, -(v + 1));
770     }
771   
772   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions end; size decisionq: %d -----\n",solv->decisionq.count);
773 }
774
775
776 /*-------------------------------------------------------------------
777  * enable/disable learnt rules 
778  *
779  * we have enabled or disabled some of our rules. We now reenable all
780  * of our learnt rules but the ones that were learnt from rules that
781  * are now disabled.
782  */
783 static void
784 enabledisablelearntrules(Solver *solv)
785 {
786   Pool *pool = solv->pool;
787   Rule *r;
788   Id why, *whyp;
789   int i;
790
791   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
792   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
793     {
794       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
795       while ((why = *whyp++) != 0)
796         {
797           assert(why > 0 && why < i);
798           if (solv->rules[why].d < 0)
799             break;
800         }
801       /* why != 0: we found a disabled rule, disable the learnt rule */
802       if (why && r->d >= 0)
803         {
804           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
805             {
806               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "disabling ");
807               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
808             }
809           disablerule(solv, r);
810         }
811       else if (!why && r->d < 0)
812         {
813           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
814             {
815               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "re-enabling ");
816               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
817             }
818           enablerule(solv, r);
819         }
820     }
821 }
822
823
824 /*-------------------------------------------------------------------
825  * enable weak rules
826  * 
827  * Enable all rules, except learnt rules, which are
828  * - disabled and weak (set in weakrulemap)
829  * 
830  */
831
832 static void
833 enableweakrules(Solver *solv)
834 {
835   int i;
836   Rule *r;
837
838   for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
839     {
840       if (r->d >= 0) /* skip non-direct literals */
841         continue;
842       if (!MAPTST(&solv->weakrulemap, i))
843         continue;
844       enablerule(solv, r);
845     }
846 }
847
848
849 /* FIXME: bad code ahead, replace as soon as possible */
850 /* FIXME: should probably look at SOLVER_INSTALL|SOLVABLE_ONE_OF */
851
852 /*-------------------------------------------------------------------
853  * disable update rules
854  */
855
856 static void
857 disableupdaterules(Solver *solv, Queue *job, int jobidx)
858 {
859   Pool *pool = solv->pool;
860   int i, j;
861   Id how, select, what, p, pp;
862   Solvable *s;
863   Repo *installed;
864   Rule *r;
865   Id lastjob = -1;
866
867   installed = solv->installed;
868   if (!installed)
869     return;
870
871   if (jobidx != -1)
872     {
873       how = job->elements[jobidx];
874       select = how & SOLVER_SELECTMASK;
875       switch (how & SOLVER_JOBMASK)
876         {
877         case SOLVER_ERASE:
878           break;
879         case SOLVER_INSTALL:
880           if (select != SOLVER_SOLVABLE)
881             return;
882           break;
883         default:
884           return;
885         }
886     }
887   /* go through all enabled job rules */
888   MAPZERO(&solv->noupdate);
889   for (i = solv->jobrules; i < solv->jobrules_end; i++)
890     {
891       r = solv->rules + i;
892       if (r->d < 0)     /* disabled? */
893         continue;
894       j = solv->ruletojob.elements[i - solv->jobrules];
895       if (j == lastjob)
896         continue;
897       lastjob = j;
898       how = job->elements[j];
899       what = job->elements[j + 1];
900       select = how & SOLVER_SELECTMASK;
901       switch (how & SOLVER_JOBMASK)
902         {
903         case SOLVER_INSTALL:
904           if (select != SOLVER_SOLVABLE)
905             break;
906           s = pool->solvables + what;
907           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
908             break;
909           if (s->repo == installed)
910             {
911               MAPSET(&solv->noupdate, what - installed->start);
912               break;
913             }
914           if (s->obsoletes)
915             {
916               Id obs, *obsp;
917               obsp = s->repo->idarraydata + s->obsoletes;
918               while ((obs = *obsp++) != 0)
919                 FOR_PROVIDES(p, pp, obs)
920                   {
921                     if (pool->solvables[p].repo != installed)
922                       continue;
923                     if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
924                       continue;
925                     MAPSET(&solv->noupdate, p - installed->start);
926                   }
927             }
928           FOR_PROVIDES(p, pp, s->name)
929             {
930               if (!solv->implicitobsoleteusesprovides && pool->solvables[p].name != s->name)
931                 continue;
932               if (pool->solvables[p].repo == installed)
933                 MAPSET(&solv->noupdate, p - installed->start);
934             }
935           break;
936         case SOLVER_ERASE:
937           FOR_JOB_SELECT(p, pp, select, what)
938             if (pool->solvables[p].repo == installed)
939               MAPSET(&solv->noupdate, p - installed->start);
940           break;
941         default:
942           break;
943         }
944     }
945
946   /* fixup update rule status */
947   if (jobidx != -1)
948     {
949       /* we just disabled job #jobidx. enable all update rules
950        * that aren't disabled by the remaining job rules */
951       how = job->elements[jobidx];
952       what = job->elements[jobidx + 1];
953       select = how & SOLVER_SELECTMASK;
954       switch (how & SOLVER_JOBMASK)
955         {
956         case SOLVER_INSTALL:
957           if (select != SOLVER_SOLVABLE)
958             break;
959           s = pool->solvables + what;
960           if (s->repo == installed)
961             {
962               if (MAPTST(&solv->noupdate, what - installed->start))
963                 break;
964               r = solv->rules + solv->updaterules + (what - installed->start);
965               if (r->d >= 0)
966                 break;
967               enablerule(solv, r);
968               IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
969                 {
970                   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
971                   solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
972                 }
973               break;
974             }
975           if (s->obsoletes)
976             {
977               Id obs, *obsp;
978               obsp = s->repo->idarraydata + s->obsoletes;
979               while ((obs = *obsp++) != 0)
980                 FOR_PROVIDES(p, pp, obs)
981                   {
982                     if (pool->solvables[p].repo != installed)
983                       continue;
984                     if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
985                       continue;
986                     if (MAPTST(&solv->noupdate, p - installed->start))
987                       continue;
988                     r = solv->rules + solv->updaterules + (p - installed->start);
989                     if (r->d >= 0)
990                       continue;
991                     enablerule(solv, r);
992                     IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
993                       {
994                         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
995                         solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
996                       }
997                   }
998             }
999           FOR_PROVIDES(p, pp, s->name)
1000             {
1001               if (!solv->implicitobsoleteusesprovides && pool->solvables[p].name != s->name)
1002                 continue;
1003               if (pool->solvables[p].repo != installed)
1004                 continue;
1005               if (MAPTST(&solv->noupdate, p - installed->start))
1006                 continue;
1007               r = solv->rules + solv->updaterules + (p - installed->start);
1008               if (r->d >= 0)
1009                 continue;
1010               enablerule(solv, r);
1011               IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1012                 {
1013                   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1014                   solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
1015                 }
1016             }
1017           break;
1018         case SOLVER_ERASE:
1019           FOR_JOB_SELECT(p, pp, select, what)
1020             {
1021               if (pool->solvables[p].repo != installed)
1022                 continue;
1023               if (MAPTST(&solv->noupdate, p - installed->start))
1024                 continue;
1025               r = solv->rules + solv->updaterules + (p - installed->start);
1026               if (r->d >= 0)
1027                 continue;
1028               enablerule(solv, r);
1029               IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1030                 {
1031                   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1032                   solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
1033                 }
1034             }
1035           break;
1036         default:
1037           break;
1038         }
1039       return;
1040     }
1041
1042   for (i = 0; i < installed->nsolvables; i++)
1043     {
1044       r = solv->rules + solv->updaterules + i;
1045       if (r->d >= 0 && MAPTST(&solv->noupdate, i))
1046         disablerule(solv, r);   /* was enabled, need to disable */
1047       r = solv->rules + solv->featurerules + i;
1048       if (r->d >= 0 && MAPTST(&solv->noupdate, i))
1049         disablerule(solv, r);   /* was enabled, need to disable */
1050     }
1051 }
1052
1053
1054 /*
1055  *  special multiversion patch conflict handling:
1056  *  a patch conflict is also satisfied, if some other
1057  *  version with the same name/arch that doesn't conflict
1058  *  get's installed. The generated rule is thus:
1059  *  -patch|-cpack|opack1|opack2|...
1060  */
1061 Id
1062 makemultiversionconflict(Solver *solv, Id n, Id con)
1063 {
1064   Pool *pool = solv->pool;
1065   Solvable *s, *sn;
1066   Queue q;
1067   Id p, pp, qbuf[64];
1068
1069   sn = pool->solvables + n;
1070   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
1071   queue_push(&q, -n);
1072   FOR_PROVIDES(p, pp, sn->name)
1073     {
1074       s = pool->solvables + p;
1075       if (s->name != sn->name || s->arch != sn->arch)
1076         continue;
1077       if (!MAPTST(&solv->noobsoletes, p))
1078         continue;
1079       if (pool_match_nevr(pool, pool->solvables + p, con))
1080         continue;
1081       /* here we have a multiversion solvable that doesn't conflict */
1082       /* thus we're not in conflict if it is installed */
1083       queue_push(&q, p);
1084     }
1085   if (q.count == 1)
1086     return -n;  /* no other package found, generate normal conflict */
1087   return pool_queuetowhatprovides(pool, &q);
1088 }
1089
1090
1091 /*-------------------------------------------------------------------
1092  * 
1093  * add (install) rules for solvable
1094  * 
1095  * s: Solvable for which to add rules
1096  * m: m[s] = 1 for solvables which have rules, prevent rule duplication
1097  * 
1098  * Algorithm: 'visit all nodes of a graph'. The graph nodes are
1099  *  solvables, the edges their dependencies.
1100  *  Starting from an installed solvable, this will create all rules
1101  *  representing the graph created by the solvables dependencies.
1102  * 
1103  * for unfulfilled requirements, conflicts, obsoletes,....
1104  * add a negative assertion for solvables that are not installable
1105  * 
1106  * It will also create rules for all solvables referenced by 's'
1107  *  i.e. descend to all providers of requirements of 's'
1108  *
1109  */
1110
1111 static void
1112 addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
1113 {
1114   Pool *pool = solv->pool;
1115   Repo *installed = solv->installed;
1116
1117   /* 'work' queue. keeps Ids of solvables we still have to work on.
1118      And buffer for it. */
1119   Queue workq;
1120   Id workqbuf[64];
1121     
1122   int i;
1123     /* if to add rules for broken deps ('rpm -V' functionality)
1124      * 0 = yes, 1 = no
1125      */
1126   int dontfix;
1127     /* Id var and pointer for each dependency
1128      * (not used in parallel)
1129      */
1130   Id req, *reqp;
1131   Id con, *conp;
1132   Id obs, *obsp;
1133   Id rec, *recp;
1134   Id sug, *sugp;
1135     /* var and ptr for loops */
1136   Id p, pp;
1137     /* ptr to 'whatprovides' */
1138   Id *dp;
1139     /* Id for current solvable 's' */
1140   Id n;
1141
1142   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
1143
1144   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
1145   queue_push(&workq, s - pool->solvables);      /* push solvable Id to work queue */
1146
1147   /* loop until there's no more work left */
1148   while (workq.count)
1149     {
1150       /*
1151        * n: Id of solvable
1152        * s: Pointer to solvable
1153        */
1154
1155       n = queue_shift(&workq);             /* 'pop' next solvable to work on from queue */
1156       if (MAPTST(m, n))                    /* continue if already visited */
1157         continue;
1158
1159       MAPSET(m, n);                        /* mark as visited */
1160       s = pool->solvables + n;             /* s = Solvable in question */
1161
1162       dontfix = 0;
1163       if (installed                        /* Installed system available */
1164           && !solv->fixsystem              /* NOT repair errors in rpm dependency graph */
1165           && s->repo == installed)         /* solvable is installed? */
1166       {
1167         dontfix = 1;                       /* dont care about broken rpm deps */
1168       }
1169
1170       if (!dontfix
1171           && s->arch != ARCH_SRC
1172           && s->arch != ARCH_NOSRC
1173           && !pool_installable(pool, s))
1174         {
1175           POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
1176           addrule(solv, -n, 0);            /* uninstallable */
1177         }
1178
1179       /*-----------------------------------------
1180        * check requires of s
1181        */
1182
1183       if (s->requires)
1184         {
1185           reqp = s->repo->idarraydata + s->requires;
1186           while ((req = *reqp++) != 0)            /* go through all requires */
1187             {
1188               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
1189                 continue;
1190
1191               /* find list of solvables providing 'req' */
1192               dp = pool->whatprovidesdata + pool_whatprovides(pool, req);
1193
1194               if (*dp == SYSTEMSOLVABLE)          /* always installed */
1195                 continue;
1196
1197               if (dontfix)
1198                 {
1199                   /* the strategy here is to not insist on dependencies
1200                    * that are already broken. so if we find one provider
1201                    * that was already installed, we know that the
1202                    * dependency was not broken before so we enforce it */
1203                  
1204                   /* check if any of the providers for 'req' is installed */
1205                   for (i = 0; (p = dp[i]) != 0; i++)
1206                     {
1207                       if (pool->solvables[p].repo == installed)
1208                         break;          /* provider was installed */
1209                     }
1210                   /* didn't find an installed provider: previously broken dependency */
1211                   if (!p)
1212                     {
1213                       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
1214                       continue;
1215                     }
1216                 }
1217
1218               if (!*dp)
1219                 {
1220                   /* nothing provides req! */
1221                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
1222                   addrule(solv, -n, 0); /* mark requestor as uninstallable */
1223                   continue;
1224                 }
1225
1226               IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
1227                 {
1228                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
1229                   for (i = 0; dp[i]; i++)
1230                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvable2str(pool, pool->solvables + dp[i]));
1231                 }
1232
1233               /* add 'requires' dependency */
1234               /* rule: (-requestor|provider1|provider2|...|providerN) */
1235               addrule(solv, -n, dp - pool->whatprovidesdata);
1236
1237               /* descend the dependency tree
1238                  push all non-visited providers on the work queue */
1239               for (; *dp; dp++)
1240                 {
1241                   if (!MAPTST(m, *dp))
1242                     queue_push(&workq, *dp);
1243                 }
1244
1245             } /* while, requirements of n */
1246
1247         } /* if, requirements */
1248
1249       /* that's all we check for src packages */
1250       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
1251         continue;
1252
1253       /*-----------------------------------------
1254        * check conflicts of s
1255        */
1256
1257       if (s->conflicts)
1258         {
1259           int ispatch = 0;
1260
1261           /* we treat conflicts in patches a bit differen:
1262            * - nevr matching
1263            * - multiversion handling
1264            * XXX: we should really handle this different, looking
1265            * at the name is a bad hack
1266            */
1267           if (!strncmp("patch:", id2str(pool, s->name), 6))
1268             ispatch = 1;
1269           conp = s->repo->idarraydata + s->conflicts;
1270           /* foreach conflicts of 's' */
1271           while ((con = *conp++) != 0)
1272             {
1273               /* foreach providers of a conflict of 's' */
1274               FOR_PROVIDES(p, pp, con)
1275                 {
1276                   if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
1277                     continue;
1278                   /* dontfix: dont care about conflicts with already installed packs */
1279                   if (dontfix && pool->solvables[p].repo == installed)
1280                     continue;
1281                   /* p == n: self conflict */
1282                   if (p == n && !solv->allowselfconflicts)
1283                     {
1284                       if (ISRELDEP(con))
1285                         {
1286                           Reldep *rd = GETRELDEP(pool, con);
1287                           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
1288                             continue;
1289                         }
1290                       p = 0;    /* make it a negative assertion, aka 'uninstallable' */
1291                     }
1292                   if (p && ispatch && solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p) && ISRELDEP(con))
1293                     {
1294                       /* our patch conflicts with a noobsoletes (aka multiversion) package */
1295                       p = -makemultiversionconflict(solv, p, con);
1296                     }
1297                  /* rule: -n|-p: either solvable _or_ provider of conflict */
1298                   addrule(solv, -n, -p);
1299                 }
1300             }
1301         }
1302
1303       /*-----------------------------------------
1304        * check obsoletes if not installed
1305        * (only installation will trigger the obsoletes in rpm)
1306        */
1307       if (!installed || pool->solvables[n].repo != installed)
1308         {                              /* not installed */
1309           int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
1310           if (s->obsoletes && !noobs)
1311             {
1312               obsp = s->repo->idarraydata + s->obsoletes;
1313               /* foreach obsoletes */
1314               while ((obs = *obsp++) != 0)
1315                 {
1316                   /* foreach provider of an obsoletes of 's' */ 
1317                   FOR_PROVIDES(p, pp, obs)
1318                     {
1319                       if (!solv->obsoleteusesprovides /* obsoletes are matched names, not provides */
1320                           && !pool_match_nevr(pool, pool->solvables + p, obs))
1321                         continue;
1322                       addrule(solv, -n, -p);
1323                     }
1324                 }
1325             }
1326           FOR_PROVIDES(p, pp, s->name)
1327             {
1328               Solvable *ps = pool->solvables + p;
1329               /* we still obsolete packages with same nevra, like rpm does */
1330               /* (actually, rpm mixes those packages. yuck...) */
1331               if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
1332                 continue;
1333               if (!solv->implicitobsoleteusesprovides && s->name != ps->name)
1334                 continue;
1335               addrule(solv, -n, -p);
1336             }
1337         }
1338
1339       /*-----------------------------------------
1340        * add recommends to the work queue
1341        */
1342       if (s->recommends)
1343         {
1344           recp = s->repo->idarraydata + s->recommends;
1345           while ((rec = *recp++) != 0)
1346             {
1347               FOR_PROVIDES(p, pp, rec)
1348                 if (!MAPTST(m, p))
1349                   queue_push(&workq, p);
1350             }
1351         }
1352       if (s->suggests)
1353         {
1354           sugp = s->repo->idarraydata + s->suggests;
1355           while ((sug = *sugp++) != 0)
1356             {
1357               FOR_PROVIDES(p, pp, sug)
1358                 if (!MAPTST(m, p))
1359                   queue_push(&workq, p);
1360             }
1361         }
1362     }
1363   queue_free(&workq);
1364   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
1365 }
1366
1367
1368 /*-------------------------------------------------------------------
1369  * 
1370  * Add package rules for weak rules
1371  *
1372  * m: visited solvables
1373  */
1374
1375 static void
1376 addrpmrulesforweak(Solver *solv, Map *m)
1377 {
1378   Pool *pool = solv->pool;
1379   Solvable *s;
1380   Id sup, *supp;
1381   int i, n;
1382
1383   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
1384     /* foreach solvable in pool */
1385   for (i = n = 1; n < pool->nsolvables; i++, n++)
1386     {
1387       if (i == pool->nsolvables)                 /* wrap i */
1388         i = 1;
1389       if (MAPTST(m, i))                          /* been there */
1390         continue;
1391
1392       s = pool->solvables + i;
1393       if (!pool_installable(pool, s))            /* only look at installable ones */
1394         continue;
1395
1396       sup = 0;
1397       if (s->supplements)
1398         {
1399           /* find possible supplements */
1400           supp = s->repo->idarraydata + s->supplements;
1401           while ((sup = *supp++) != ID_NULL)
1402             if (dep_possible(solv, sup, m))
1403               break;
1404         }
1405
1406         /* if nothing found, check for enhances */
1407       if (!sup && s->enhances)
1408         {
1409           supp = s->repo->idarraydata + s->enhances;
1410           while ((sup = *supp++) != ID_NULL)
1411             if (dep_possible(solv, sup, m))
1412               break;
1413         }
1414         /* if nothing found, goto next solvables */
1415       if (!sup)
1416         continue;
1417       addrpmrulesforsolvable(solv, s, m);
1418       n = 0;
1419     }
1420   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
1421 }
1422
1423
1424 /*-------------------------------------------------------------------
1425  * 
1426  * add package rules for possible updates
1427  * 
1428  * s: solvable
1429  * m: map of already visited solvables
1430  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
1431  */
1432
1433 static void
1434 addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
1435 {
1436   Pool *pool = solv->pool;
1437   int i;
1438     /* queue and buffer for it */
1439   Queue qs;
1440   Id qsbuf[64];
1441
1442   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
1443
1444   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1445     /* find update candidates for 's' */
1446   policy_findupdatepackages(solv, s, &qs, allow_all);
1447     /* add rule for 's' if not already done */
1448   if (!MAPTST(m, s - pool->solvables))
1449     addrpmrulesforsolvable(solv, s, m);
1450     /* foreach update candidate, add rule if not already done */
1451   for (i = 0; i < qs.count; i++)
1452     if (!MAPTST(m, qs.elements[i]))
1453       addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
1454   queue_free(&qs);
1455
1456   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
1457 }
1458
1459 static Id
1460 finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
1461 {
1462   Pool *pool = solv->pool;
1463   int i;
1464
1465   policy_findupdatepackages(solv, s, qs, allow_all);
1466   if (!qs->count)
1467     {
1468       if (allow_all)
1469         return 0;
1470       policy_findupdatepackages(solv, s, qs, 1);
1471       if (!qs->count)
1472         return 0;       /* orphaned */
1473       qs->count = 0;
1474       return -SYSTEMSOLVABLE;
1475     }
1476   if (allow_all)
1477     return s - pool->solvables;
1478   /* check if it is ok to keep the installed package */
1479   for (i = 0; i < qs->count; i++)
1480     {
1481       Solvable *ns = pool->solvables + qs->elements[i];
1482       if (s->evr == ns->evr && solvable_identical(s, ns))
1483         return s - pool->solvables;
1484     }
1485   /* nope, it must be some other package */
1486   return -SYSTEMSOLVABLE;
1487 }
1488
1489 /*-------------------------------------------------------------------
1490  * 
1491  * add rule for update
1492  *   (A|A1|A2|A3...)  An = update candidates for A
1493  *
1494  * s = (installed) solvable
1495  */
1496
1497 static void
1498 addupdaterule(Solver *solv, Solvable *s, int allow_all)
1499 {
1500   /* installed packages get a special upgrade allowed rule */
1501   Pool *pool = solv->pool;
1502   Id p, d;
1503   Queue qs;
1504   Id qsbuf[64];
1505
1506   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
1507   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1508   p = s - pool->solvables;
1509   /* find update candidates for 's' */
1510   if (solv->distupgrade)
1511     p = finddistupgradepackages(solv, s, &qs, allow_all);
1512   else
1513     policy_findupdatepackages(solv, s, &qs, allow_all);
1514   if (!allow_all && qs.count && solv->noobsoletes.size)
1515     {
1516       int i, j;
1517
1518       d = pool_queuetowhatprovides(pool, &qs);
1519       /* filter out all noobsoletes packages as they don't update */
1520       for (i = j = 0; i < qs.count; i++)
1521         {
1522           if (MAPTST(&solv->noobsoletes, qs.elements[i]))
1523             {
1524               /* it's ok if they have same nevra */
1525               Solvable *ps = pool->solvables + qs.elements[i];
1526               if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
1527                 continue;
1528             }
1529           qs.elements[j++] = qs.elements[i];
1530         }
1531       if (j == 0 && p == -SYSTEMSOLVABLE && solv->distupgrade)
1532         {
1533           queue_push(&solv->orphaned, s - pool->solvables);     /* treat as orphaned */
1534           j = qs.count;
1535         }
1536       if (j < qs.count)
1537         {
1538           if (d && solv->updatesystem && solv->installed && s->repo == solv->installed)
1539             {
1540               if (!solv->multiversionupdaters)
1541                 solv->multiversionupdaters = sat_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
1542               solv->multiversionupdaters[s - pool->solvables - solv->installed->start] = d;
1543             }
1544           qs.count = j;
1545         }
1546     }
1547   if (qs.count && p == -SYSTEMSOLVABLE)
1548     p = queue_shift(&qs);
1549   d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
1550   queue_free(&qs);
1551   addrule(solv, p, d);  /* allow update of s */
1552   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
1553 }
1554
1555
1556 /********************************************************************/
1557 /* watches */
1558
1559
1560 /*-------------------------------------------------------------------
1561  * makewatches
1562  *
1563  * initial setup for all watches
1564  */
1565
1566 static void
1567 makewatches(Solver *solv)
1568 {
1569   Rule *r;
1570   int i;
1571   int nsolvables = solv->pool->nsolvables;
1572
1573   sat_free(solv->watches);
1574                                        /* lower half for removals, upper half for installs */
1575   solv->watches = sat_calloc(2 * nsolvables, sizeof(Id));
1576 #if 1
1577   /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
1578   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
1579 #else
1580   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
1581 #endif
1582     {
1583       if (!r->w2)               /* assertions do not need watches */
1584         continue;
1585
1586       /* see addwatches_rule(solv, r) */
1587       r->n1 = solv->watches[nsolvables + r->w1];
1588       solv->watches[nsolvables + r->w1] = r - solv->rules;
1589
1590       r->n2 = solv->watches[nsolvables + r->w2];
1591       solv->watches[nsolvables + r->w2] = r - solv->rules;
1592     }
1593 }
1594
1595
1596 /*-------------------------------------------------------------------
1597  *
1598  * add watches (for rule)
1599  * sets up watches for a single rule
1600  * 
1601  * see also makewatches()
1602  */
1603
1604 static inline void
1605 addwatches_rule(Solver *solv, Rule *r)
1606 {
1607   int nsolvables = solv->pool->nsolvables;
1608
1609   r->n1 = solv->watches[nsolvables + r->w1];
1610   solv->watches[nsolvables + r->w1] = r - solv->rules;
1611
1612   r->n2 = solv->watches[nsolvables + r->w2];
1613   solv->watches[nsolvables + r->w2] = r - solv->rules;
1614 }
1615
1616
1617 /********************************************************************/
1618 /*
1619  * rule propagation
1620  */
1621
1622
1623 /* shortcuts to check if a literal (positive or negative) assignment
1624  * evaluates to 'true' or 'false'
1625  */
1626 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
1627 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
1628 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
1629
1630 /*-------------------------------------------------------------------
1631  * 
1632  * propagate
1633  *
1634  * make decision and propagate to all rules
1635  * 
1636  * Evaluate each term affected by the decision (linked through watches)
1637  * If we find unit rules we make new decisions based on them
1638  * 
1639  * Everything's fixed there, it's just finding rules that are
1640  * unit.
1641  * 
1642  * return : 0 = everything is OK
1643  *          rule = conflict found in this rule
1644  */
1645
1646 static Rule *
1647 propagate(Solver *solv, int level)
1648 {
1649   Pool *pool = solv->pool;
1650   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
1651   Rule *r;                    /* rule */
1652   Id p, pkg, other_watch;
1653   Id *dp;
1654   Id *decisionmap = solv->decisionmap;
1655     
1656   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
1657
1658   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate -----\n");
1659
1660   /* foreach non-propagated decision */
1661   while (solv->propagate_index < solv->decisionq.count)
1662     {
1663         /*
1664          * 'pkg' was just decided
1665          * negate because our watches trigger if literal goes FALSE
1666          */
1667       pkg = -solv->decisionq.elements[solv->propagate_index++];
1668         
1669       IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1670         {
1671           POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
1672           solver_printruleelement(solv, SAT_DEBUG_PROPAGATE, 0, -pkg);
1673         }
1674
1675       /* foreach rule where 'pkg' is now FALSE */
1676       for (rp = watches + pkg; *rp; rp = next_rp)
1677         {
1678           r = solv->rules + *rp;
1679           if (r->d < 0)
1680             {
1681               /* rule is disabled, goto next */
1682               if (pkg == r->w1)
1683                 next_rp = &r->n1;
1684               else
1685                 next_rp = &r->n2;
1686               continue;
1687             }
1688
1689           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1690             {
1691               POOL_DEBUG(SAT_DEBUG_PROPAGATE,"  watch triggered ");
1692               solver_printrule(solv, SAT_DEBUG_PROPAGATE, r);
1693             }
1694
1695             /* 'pkg' was just decided (was set to FALSE)
1696              * 
1697              *  now find other literal watch, check clause
1698              *   and advance on linked list
1699              */
1700           if (pkg == r->w1)
1701             {
1702               other_watch = r->w2;
1703               next_rp = &r->n1;
1704             }
1705           else
1706             {
1707               other_watch = r->w1;
1708               next_rp = &r->n2;
1709             }
1710             
1711             /* 
1712              * This term is already true (through the other literal)
1713              * so we have nothing to do
1714              */
1715           if (DECISIONMAP_TRUE(other_watch))
1716             continue;
1717
1718             /*
1719              * The other literal is FALSE or UNDEF
1720              * 
1721              */
1722             
1723           if (r->d)
1724             {
1725               /* Not a binary clause, try to move our watch.
1726                * 
1727                * Go over all literals and find one that is
1728                *   not other_watch
1729                *   and not FALSE
1730                * 
1731                * (TRUE is also ok, in that case the rule is fulfilled)
1732                */
1733               if (r->p                                /* we have a 'p' */
1734                   && r->p != other_watch              /* which is not watched */
1735                   && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
1736                 {
1737                   p = r->p;
1738                 }
1739               else                                    /* go find a 'd' to make 'true' */
1740                 {
1741                   /* foreach p in 'd'
1742                      we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
1743                    */
1744                   for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
1745                     {
1746                       if (p != other_watch              /* which is not watched */
1747                           && !DECISIONMAP_FALSE(p))     /* and not FALSE */
1748                         break;
1749                     }
1750                 }
1751
1752               if (p)
1753                 {
1754                   /*
1755                    * if we found some p that is UNDEF or TRUE, move
1756                    * watch to it
1757                    */
1758                   IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1759                     {
1760                       if (p > 0)
1761                         POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
1762                       else
1763                         POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
1764                     }
1765                     
1766                   *rp = *next_rp;
1767                   next_rp = rp;
1768                     
1769                   if (pkg == r->w1)
1770                     {
1771                       r->w1 = p;
1772                       r->n1 = watches[p];
1773                     }
1774                   else
1775                     {
1776                       r->w2 = p;
1777                       r->n2 = watches[p];
1778                     }
1779                   watches[p] = r - solv->rules;
1780                   continue;
1781                 }
1782               /* search failed, thus all unwatched literals are FALSE */
1783                 
1784             } /* not binary */
1785             
1786             /*
1787              * unit clause found, set literal other_watch to TRUE
1788              */
1789
1790           if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
1791             return r;                              /* eek, a conflict! */
1792             
1793           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1794             {
1795               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "   unit ");
1796               solver_printrule(solv, SAT_DEBUG_PROPAGATE, r);
1797             }
1798
1799           if (other_watch > 0)
1800             decisionmap[other_watch] = level;    /* install! */
1801           else
1802             decisionmap[-other_watch] = -level;  /* remove! */
1803             
1804           queue_push(&solv->decisionq, other_watch);
1805           queue_push(&solv->decisionq_why, r - solv->rules);
1806
1807           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1808             {
1809               Solvable *s = pool->solvables + (other_watch > 0 ? other_watch : -other_watch);
1810               if (other_watch > 0)
1811                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvable2str(pool, s));
1812               else
1813                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvable2str(pool, s));
1814             }
1815             
1816         } /* foreach rule involving 'pkg' */
1817         
1818     } /* while we have non-decided decisions */
1819     
1820   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate end-----\n");
1821
1822   return 0;     /* all is well */
1823 }
1824
1825
1826 /********************************************************************/
1827 /* Analysis */
1828
1829 /*-------------------------------------------------------------------
1830  * 
1831  * analyze
1832  *   and learn
1833  */
1834
1835 static int
1836 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
1837 {
1838   Pool *pool = solv->pool;
1839   Queue r;
1840   int rlevel = 1;
1841   Map seen;             /* global? */
1842   Id d, v, vv, *dp, why;
1843   int l, i, idx;
1844   int num = 0, l1num = 0;
1845   int learnt_why = solv->learnt_pool.count;
1846   Id *decisionmap = solv->decisionmap;
1847
1848   queue_init(&r);
1849
1850   POOL_DEBUG(SAT_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
1851   map_init(&seen, pool->nsolvables);
1852   idx = solv->decisionq.count;
1853   for (;;)
1854     {
1855       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1856         solver_printruleclass(solv, SAT_DEBUG_ANALYZE, c);
1857       queue_push(&solv->learnt_pool, c - solv->rules);
1858       d = c->d < 0 ? -c->d - 1 : c->d;
1859       dp = d ? pool->whatprovidesdata + d : 0;
1860       /* go through all literals of the rule */
1861       for (i = -1; ; i++)
1862         {
1863           if (i == -1)
1864             v = c->p;
1865           else if (d == 0)
1866             v = i ? 0 : c->w2;
1867           else
1868             v = *dp++;
1869           if (v == 0)
1870             break;
1871
1872           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1873             continue;
1874           vv = v > 0 ? v : -v;
1875           if (MAPTST(&seen, vv))
1876             continue;
1877           l = solv->decisionmap[vv];
1878           if (l < 0)
1879             l = -l;
1880           MAPSET(&seen, vv);
1881           if (l == 1)
1882             l1num++;                    /* need to do this one in level1 pass */
1883           else if (l == level)
1884             num++;                      /* need to do this one as well */
1885           else
1886             {
1887               queue_push(&r, v);        /* not level1 or conflict level, add to new rule */
1888               if (l > rlevel)
1889                 rlevel = l;
1890             }
1891         }
1892 l1retry:
1893       if (!num && !--l1num)
1894         break;  /* all level 1 literals done */
1895       for (;;)
1896         {
1897           assert(idx > 0);
1898           v = solv->decisionq.elements[--idx];
1899           vv = v > 0 ? v : -v;
1900           if (MAPTST(&seen, vv))
1901             break;
1902         }
1903       MAPCLR(&seen, vv);
1904       if (num && --num == 0)
1905         {
1906           *pr = -v;     /* so that v doesn't get lost */
1907           if (!l1num)
1908             break;
1909           POOL_DEBUG(SAT_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
1910           for (i = 0; i < r.count; i++)
1911             {
1912               v = r.elements[i];
1913               MAPCLR(&seen, v > 0 ? v : -v);
1914             }
1915           /* only level 1 marks left */
1916           l1num++;
1917           goto l1retry;
1918         }
1919       why = solv->decisionq_why.elements[idx];
1920       if (why <= 0)     /* just in case, maybe for SYSTEMSOLVABLE */
1921         goto l1retry;
1922       c = solv->rules + why;
1923     }
1924   map_free(&seen);
1925
1926   if (r.count == 0)
1927     *dr = 0;
1928   else if (r.count == 1 && r.elements[0] < 0)
1929     *dr = r.elements[0];
1930   else
1931     *dr = pool_queuetowhatprovides(pool, &r);
1932   IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1933     {
1934       POOL_DEBUG(SAT_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
1935       solver_printruleelement(solv, SAT_DEBUG_ANALYZE, 0, *pr);
1936       for (i = 0; i < r.count; i++)
1937         solver_printruleelement(solv, SAT_DEBUG_ANALYZE, 0, r.elements[i]);
1938     }
1939   /* push end marker on learnt reasons stack */
1940   queue_push(&solv->learnt_pool, 0);
1941   if (whyp)
1942     *whyp = learnt_why;
1943   solv->stats_learned++;
1944   return rlevel;
1945 }
1946
1947
1948 /*-------------------------------------------------------------------
1949  * 
1950  * reset_solver
1951  * 
1952  * reset the solver decisions to right after the rpm rules.
1953  * called after rules have been enabled/disabled
1954  */
1955
1956 static void
1957 reset_solver(Solver *solv)
1958 {
1959   Pool *pool = solv->pool;
1960   int i;
1961   Id v;
1962
1963   /* rewind decisions to direct rpm rule assertions */
1964   for (i = solv->decisionq.count - 1; i >= solv->directdecisions; i--)
1965     {
1966       v = solv->decisionq.elements[i];
1967       solv->decisionmap[v > 0 ? v : -v] = 0;
1968     }
1969
1970   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions done reduced from %d to %d\n", solv->decisionq.count, solv->directdecisions);
1971
1972   solv->decisionq_why.count = solv->directdecisions;
1973   solv->decisionq.count = solv->directdecisions;
1974   solv->recommends_index = -1;
1975   solv->propagate_index = 0;
1976
1977   /* adapt learnt rule status to new set of enabled/disabled rules */
1978   enabledisablelearntrules(solv);
1979
1980   /* redo all job/update decisions */
1981   makeruledecisions(solv);
1982   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
1983 }
1984
1985
1986 /*-------------------------------------------------------------------
1987  * 
1988  * analyze_unsolvable_rule
1989  */
1990
1991 static void
1992 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp)
1993 {
1994   Pool *pool = solv->pool;
1995   int i;
1996   Id why = r - solv->rules;
1997
1998   IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
1999     solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, r);
2000   if (solv->learntrules && why >= solv->learntrules)
2001     {
2002       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
2003         if (solv->learnt_pool.elements[i] > 0)
2004           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp);
2005       return;
2006     }
2007   if (MAPTST(&solv->weakrulemap, why))
2008     if (!*lastweakp || why > *lastweakp)
2009       *lastweakp = why;
2010   /* do not add rpm rules to problem */
2011   if (why < solv->rpmrules_end)
2012     return;
2013   /* turn rule into problem */
2014   if (why >= solv->jobrules && why < solv->jobrules_end)
2015     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
2016   /* return if problem already countains our rule */
2017   if (solv->problems.count)
2018     {
2019       for (i = solv->problems.count - 1; i >= 0; i--)
2020         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
2021           break;
2022         else if (solv->problems.elements[i] == why)
2023           return;
2024     }
2025   queue_push(&solv->problems, why);
2026 }
2027
2028
2029 /*-------------------------------------------------------------------
2030  * 
2031  * analyze_unsolvable
2032  *
2033  * return: 1 - disabled some rules, try again
2034  *         0 - hopeless
2035  */
2036
2037 static int
2038 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
2039 {
2040   Pool *pool = solv->pool;
2041   Rule *r;
2042   Map seen;             /* global to speed things up? */
2043   Id d, v, vv, *dp, why;
2044   int l, i, idx;
2045   Id *decisionmap = solv->decisionmap;
2046   int oldproblemcount;
2047   int oldlearntpoolcount;
2048   Id lastweak;
2049
2050   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
2051   solv->stats_unsolvable++;
2052   oldproblemcount = solv->problems.count;
2053   oldlearntpoolcount = solv->learnt_pool.count;
2054
2055   /* make room for proof index */
2056   /* must update it later, as analyze_unsolvable_rule would confuse
2057    * it with a rule index if we put the real value in already */
2058   queue_push(&solv->problems, 0);
2059
2060   r = cr;
2061   map_init(&seen, pool->nsolvables);
2062   queue_push(&solv->learnt_pool, r - solv->rules);
2063   lastweak = 0;
2064   analyze_unsolvable_rule(solv, r, &lastweak);
2065   d = r->d < 0 ? -r->d - 1 : r->d;
2066   dp = d ? pool->whatprovidesdata + d : 0;
2067   for (i = -1; ; i++)
2068     {
2069       if (i == -1)
2070         v = r->p;
2071       else if (d == 0)
2072         v = i ? 0 : r->w2;
2073       else
2074         v = *dp++;
2075       if (v == 0)
2076         break;
2077       if (DECISIONMAP_TRUE(v))  /* the one true literal */
2078           continue;
2079       vv = v > 0 ? v : -v;
2080       l = solv->decisionmap[vv];
2081       if (l < 0)
2082         l = -l;
2083       MAPSET(&seen, vv);
2084     }
2085   idx = solv->decisionq.count;
2086   while (idx > 0)
2087     {
2088       v = solv->decisionq.elements[--idx];
2089       vv = v > 0 ? v : -v;
2090       if (!MAPTST(&seen, vv))
2091         continue;
2092       why = solv->decisionq_why.elements[idx];
2093       assert(why > 0);
2094       queue_push(&solv->learnt_pool, why);
2095       r = solv->rules + why;
2096       analyze_unsolvable_rule(solv, r, &lastweak);
2097       d = r->d < 0 ? -r->d - 1 : r->d;
2098       dp = d ? pool->whatprovidesdata + d : 0;
2099       for (i = -1; ; i++)
2100         {
2101           if (i == -1)
2102             v = r->p;
2103           else if (d == 0)
2104             v = i ? 0 : r->w2;
2105           else
2106             v = *dp++;
2107           if (v == 0)
2108             break;
2109           if (DECISIONMAP_TRUE(v))      /* the one true literal */
2110               continue;
2111           vv = v > 0 ? v : -v;
2112           l = solv->decisionmap[vv];
2113           if (l < 0)
2114             l = -l;
2115           MAPSET(&seen, vv);
2116         }
2117     }
2118   map_free(&seen);
2119   queue_push(&solv->problems, 0);       /* mark end of this problem */
2120
2121   if (lastweak)
2122     {
2123       Id v;
2124       /* disable last weak rule */
2125       solv->problems.count = oldproblemcount;
2126       solv->learnt_pool.count = oldlearntpoolcount;
2127       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
2128         v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
2129       else
2130         v = lastweak;
2131       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling ");
2132       solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, solv->rules + lastweak);
2133       disableproblem(solv, v);
2134       if (v < 0)
2135         disableupdaterules(solv, solv->job, -(v + 1));
2136       reset_solver(solv);
2137       return 1;
2138     }
2139
2140   /* finish proof */
2141   queue_push(&solv->learnt_pool, 0);
2142   solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
2143
2144   if (disablerules)
2145     {
2146       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
2147         disableproblem(solv, solv->problems.elements[i]);
2148       /* XXX: might want to enable all weak rules again */
2149       reset_solver(solv);
2150       return 1;
2151     }
2152   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
2153   return 0;
2154 }
2155
2156
2157 /********************************************************************/
2158 /* Decision revert */
2159
2160 /*-------------------------------------------------------------------
2161  * 
2162  * revert
2163  * revert decision at level
2164  */
2165
2166 static void
2167 revert(Solver *solv, int level)
2168 {
2169   Pool *pool = solv->pool;
2170   Id v, vv;
2171   while (solv->decisionq.count)
2172     {
2173       v = solv->decisionq.elements[solv->decisionq.count - 1];
2174       vv = v > 0 ? v : -v;
2175       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
2176         break;
2177       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
2178       if (v > 0 && solv->recommendations.count && v == solv->recommendations.elements[solv->recommendations.count - 1])
2179         solv->recommendations.count--;
2180       solv->decisionmap[vv] = 0;
2181       solv->decisionq.count--;
2182       solv->decisionq_why.count--;
2183       solv->propagate_index = solv->decisionq.count;
2184     }
2185   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
2186     {
2187       solv->branches.count--;
2188       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
2189         solv->branches.count--;
2190     }
2191   solv->recommends_index = -1;
2192 }
2193
2194
2195 /*-------------------------------------------------------------------
2196  * 
2197  * watch2onhighest - put watch2 on literal with highest level
2198  */
2199
2200 static inline void
2201 watch2onhighest(Solver *solv, Rule *r)
2202 {
2203   int l, wl = 0;
2204   Id d, v, *dp;
2205
2206   d = r->d < 0 ? -r->d - 1 : r->d;
2207   if (!d)
2208     return;     /* binary rule, both watches are set */
2209   dp = solv->pool->whatprovidesdata + d;
2210   while ((v = *dp++) != 0)
2211     {
2212       l = solv->decisionmap[v < 0 ? -v : v];
2213       if (l < 0)
2214         l = -l;
2215       if (l > wl)
2216         {
2217           r->w2 = dp[-1];
2218           wl = l;
2219         }
2220     }
2221 }
2222
2223
2224 /*-------------------------------------------------------------------
2225  * 
2226  * setpropagatelearn
2227  *
2228  * add free decision (solvable to install) to decisionq
2229  * increase level and propagate decision
2230  * return if no conflict.
2231  *
2232  * in conflict case, analyze conflict rule, add resulting
2233  * rule to learnt rule set, make decision from learnt
2234  * rule (always unit) and re-propagate.
2235  *
2236  * returns the new solver level or 0 if unsolvable
2237  *
2238  */
2239
2240 static int
2241 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
2242 {
2243   Pool *pool = solv->pool;
2244   Rule *r;
2245   Id p = 0, d = 0;
2246   int l, why;
2247
2248   assert(ruleid >= 0);
2249   if (decision)
2250     {
2251       level++;
2252       if (decision > 0)
2253         solv->decisionmap[decision] = level;
2254       else
2255         solv->decisionmap[-decision] = -level;
2256       queue_push(&solv->decisionq, decision);
2257       queue_push(&solv->decisionq_why, -ruleid);        /* <= 0 -> free decision */
2258     }
2259   for (;;)
2260     {
2261       r = propagate(solv, level);
2262       if (!r)
2263         break;
2264       if (level == 1)
2265         return analyze_unsolvable(solv, r, disablerules);
2266       POOL_DEBUG(SAT_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
2267       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
2268       assert(l > 0 && l < level);
2269       POOL_DEBUG(SAT_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
2270       level = l;
2271       revert(solv, level);
2272       r = addrule(solv, p, d);       /* p requires d */
2273       assert(r);
2274       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
2275       queue_push(&solv->learnt_why, why);
2276       if (d)
2277         {
2278           /* at least 2 literals, needs watches */
2279           watch2onhighest(solv, r);
2280           addwatches_rule(solv, r);
2281         }
2282       else
2283         {
2284           /* learnt rule is an assertion */
2285           queue_push(&solv->ruleassertions, r - solv->rules);
2286         }
2287       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
2288       queue_push(&solv->decisionq, p);
2289       queue_push(&solv->decisionq_why, r - solv->rules);
2290       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
2291         {
2292           POOL_DEBUG(SAT_DEBUG_ANALYZE, "decision: ");
2293           solver_printruleelement(solv, SAT_DEBUG_ANALYZE, 0, p);
2294           POOL_DEBUG(SAT_DEBUG_ANALYZE, "new rule: ");
2295           solver_printrule(solv, SAT_DEBUG_ANALYZE, r);
2296         }
2297     }
2298   return level;
2299 }
2300
2301
2302 /*-------------------------------------------------------------------
2303  * 
2304  * select and install
2305  * 
2306  * install best package from the queue. We add an extra package, inst, if
2307  * provided. See comment in weak install section.
2308  *
2309  * returns the new solver level or 0 if unsolvable
2310  *
2311  */
2312
2313 static int
2314 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
2315 {
2316   Pool *pool = solv->pool;
2317   Id p;
2318   int i;
2319
2320   if (dq->count > 1)
2321     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
2322   if (dq->count > 1)
2323     {
2324       /* XXX: didn't we already do that? */
2325       /* XXX: shouldn't we prefer installed packages? */
2326       /* XXX: move to policy.c? */
2327       /* choose the supplemented one */
2328       for (i = 0; i < dq->count; i++)
2329         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
2330           {
2331             dq->elements[0] = dq->elements[i];
2332             dq->count = 1;
2333             break;
2334           }
2335     }
2336   if (dq->count > 1)
2337     {
2338       /* multiple candidates, open a branch */
2339       for (i = 1; i < dq->count; i++)
2340         queue_push(&solv->branches, dq->elements[i]);
2341       queue_push(&solv->branches, -level);
2342     }
2343   p = dq->elements[0];
2344
2345   POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
2346
2347   return setpropagatelearn(solv, level, p, disablerules, ruleid);
2348 }
2349
2350
2351 /********************************************************************/
2352 /* Main solver interface */
2353
2354
2355 /*-------------------------------------------------------------------
2356  * 
2357  * solver_create
2358  * create solver structure
2359  *
2360  * pool: all available solvables
2361  * installed: installed Solvables
2362  *
2363  *
2364  * Upon solving, rules are created to flag the Solvables
2365  * of the 'installed' Repo as installed.
2366  */
2367
2368 Solver *
2369 solver_create(Pool *pool)
2370 {
2371   Solver *solv;
2372   solv = (Solver *)sat_calloc(1, sizeof(Solver));
2373   solv->pool = pool;
2374   solv->installed = pool->installed;
2375
2376   queue_init(&solv->ruletojob);
2377   queue_init(&solv->decisionq);
2378   queue_init(&solv->decisionq_why);
2379   queue_init(&solv->problems);
2380   queue_init(&solv->suggestions);
2381   queue_init(&solv->recommendations);
2382   queue_init(&solv->orphaned);
2383   queue_init(&solv->learnt_why);
2384   queue_init(&solv->learnt_pool);
2385   queue_init(&solv->branches);
2386   queue_init(&solv->covenantq);
2387   queue_init(&solv->weakruleq);
2388   queue_init(&solv->ruleassertions);
2389
2390   map_init(&solv->recommendsmap, pool->nsolvables);
2391   map_init(&solv->suggestsmap, pool->nsolvables);
2392   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
2393   solv->recommends_index = 0;
2394
2395   solv->decisionmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
2396   solv->nrules = 1;
2397   solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
2398   memset(solv->rules, 0, sizeof(Rule));
2399
2400   return solv;
2401 }
2402
2403
2404 /*-------------------------------------------------------------------
2405  * 
2406  * solver_free
2407  */
2408
2409 void
2410 solver_free(Solver *solv)
2411 {
2412   queue_free(&solv->ruletojob);
2413   queue_free(&solv->decisionq);
2414   queue_free(&solv->decisionq_why);
2415   queue_free(&solv->learnt_why);
2416   queue_free(&solv->learnt_pool);
2417   queue_free(&solv->problems);
2418   queue_free(&solv->suggestions);
2419   queue_free(&solv->recommendations);
2420   queue_free(&solv->orphaned);
2421   queue_free(&solv->branches);
2422   queue_free(&solv->covenantq);
2423   queue_free(&solv->weakruleq);
2424   queue_free(&solv->ruleassertions);
2425
2426   map_free(&solv->recommendsmap);
2427   map_free(&solv->suggestsmap);
2428   map_free(&solv->noupdate);
2429   map_free(&solv->weakrulemap);
2430   map_free(&solv->noobsoletes);
2431
2432   sat_free(solv->decisionmap);
2433   sat_free(solv->rules);
2434   sat_free(solv->watches);
2435   sat_free(solv->obsoletes);
2436   sat_free(solv->obsoletes_data);
2437   sat_free(solv->multiversionupdaters);
2438   sat_free(solv);
2439 }
2440
2441
2442 /*-------------------------------------------------------------------
2443  * 
2444  * run_solver
2445  *
2446  * all rules have been set up, now actually run the solver
2447  *
2448  */
2449
2450 static void
2451 run_solver(Solver *solv, int disablerules, int doweak)
2452 {
2453   Queue dq;             /* local decisionqueue */
2454   Queue dqs;            /* local decisionqueue for supplements */
2455   int systemlevel;
2456   int level, olevel;
2457   Rule *r;
2458   int i, j, n;
2459   Solvable *s;
2460   Pool *pool = solv->pool;
2461   Id p, *dp;
2462   int minimizationsteps;
2463
2464   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
2465     {
2466       POOL_DEBUG (SAT_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
2467       for (i = 1; i < solv->nrules; i++)
2468         solver_printruleclass(solv, SAT_DEBUG_RULE_CREATION, solv->rules + i);
2469     }
2470
2471   POOL_DEBUG(SAT_DEBUG_STATS, "initial decisions: %d\n", solv->decisionq.count);
2472
2473   IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2474     solver_printdecisions(solv);
2475
2476   /* start SAT algorithm */
2477   level = 1;
2478   systemlevel = level + 1;
2479   POOL_DEBUG(SAT_DEBUG_STATS, "solving...\n");
2480
2481   queue_init(&dq);
2482   queue_init(&dqs);
2483
2484   /*
2485    * here's the main loop:
2486    * 1) propagate new decisions (only needed for level 1)
2487    * 2) try to keep installed packages
2488    * 3) fulfill all unresolved rules
2489    * 4) install recommended packages
2490    * 5) minimalize solution if we had choices
2491    * if we encounter a problem, we rewind to a safe level and restart
2492    * with step 1
2493    */
2494    
2495   minimizationsteps = 0;
2496   for (;;)
2497     {
2498       /*
2499        * propagate
2500        */
2501
2502       if (level == 1)
2503         {
2504           POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
2505           if ((r = propagate(solv, level)) != 0)
2506             {
2507               if (analyze_unsolvable(solv, r, disablerules))
2508                 continue;
2509               queue_free(&dq);
2510               queue_free(&dqs);
2511               return;
2512             }
2513         }
2514
2515      if (level < systemlevel)
2516         {
2517           POOL_DEBUG(SAT_DEBUG_STATS, "resolving job rules\n");
2518           for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
2519             {
2520               Id l;
2521               if (r->d < 0)             /* ignore disabled rules */
2522                 continue;
2523               queue_empty(&dq);
2524               FOR_RULELITERALS(l, dp, r)
2525                 {
2526                   if (l < 0)
2527                     {
2528                       if (solv->decisionmap[-l] <= 0)
2529                         break;
2530                     }
2531                   else
2532                     {
2533                       if (solv->decisionmap[l] > 0)
2534                         break;
2535                       if (solv->decisionmap[l] == 0)
2536                         queue_push(&dq, l);
2537                     }
2538                 }
2539               if (l || !dq.count)
2540                 continue;
2541               /* prune to installed if not updating */
2542               if (!solv->updatesystem && solv->installed && dq.count > 1)
2543                 {
2544                   int j, k;
2545                   for (j = k = 0; j < dq.count; j++)
2546                     {
2547                       Solvable *s = pool->solvables + dq.elements[j];
2548                       if (s->repo == solv->installed)
2549                         dq.elements[k++] = dq.elements[j];
2550                     }
2551                   if (k)
2552                     dq.count = k;
2553                 }
2554               olevel = level;
2555               level = selectandinstall(solv, level, &dq, disablerules, i);
2556               if (level == 0)
2557                 {
2558                   queue_free(&dq);
2559                   queue_free(&dqs);
2560                   return;
2561                 }
2562               if (level <= olevel)
2563                 break;
2564             }
2565           systemlevel = level + 1;
2566           if (i < solv->jobrules_end)
2567             continue;
2568         }
2569
2570
2571       /*
2572        * installed packages
2573        */
2574
2575       if (level < systemlevel && solv->installed && solv->installed->nsolvables)
2576         {
2577           if (!solv->updatesystem)
2578             {
2579               /*
2580                * Normal run (non-updating)
2581                * Keep as many packages installed as possible
2582                */
2583               POOL_DEBUG(SAT_DEBUG_STATS, "installing old packages\n");
2584                 
2585               for (i = solv->installed->start; i < solv->installed->end; i++)
2586                 {
2587                   s = pool->solvables + i;
2588                     
2589                     /* skip if not installed */
2590                   if (s->repo != solv->installed)
2591                     continue;
2592                     
2593                     /* skip if already decided */
2594                   if (solv->decisionmap[i] != 0)
2595                     continue;
2596                     
2597                   r = solv->rules + solv->updaterules + (i - solv->installed->start);
2598                   if (!r->p)            /* update rule == feature rule? */
2599                     r = r - solv->updaterules + solv->featurerules;
2600                   if (r->p && r->p != i)        /* allowed to keep package? */
2601                     continue;
2602
2603                   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
2604                     
2605                   olevel = level;
2606                   level = setpropagatelearn(solv, level, i, disablerules, r->p ? r - solv->rules : 0);
2607
2608                   if (level == 0)                /* unsolvable */
2609                     {
2610                       queue_free(&dq);
2611                       queue_free(&dqs);
2612                       return;
2613                     }
2614                   if (level <= olevel)
2615                     break;
2616                 }
2617               systemlevel = level + 1;
2618               if (i < solv->installed->end)
2619                 continue;
2620             }
2621           else if (solv->noobsoletes.size && solv->multiversionupdaters)
2622             {
2623               /* see if we can multi-version install the newest package */
2624               for (i = solv->installed->start; i < solv->installed->end; i++)
2625                 {
2626                   Id d;
2627                   s = pool->solvables + i;
2628                   if (s->repo != solv->installed)
2629                     continue;
2630                   if (MAPTST(&solv->noupdate, i - solv->installed->start))
2631                     continue;
2632                   d = solv->multiversionupdaters[i - solv->installed->start];
2633                   if (!d)
2634                     continue;
2635                   queue_empty(&dq);
2636                   queue_push(&dq, i);
2637                   while ((p = pool->whatprovidesdata[d++]) != 0)
2638                     if (solv->decisionmap[p] >= 0)
2639                       queue_push(&dq, p);
2640                   policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
2641                   p = dq.elements[0];
2642                   if (p != i && solv->decisionmap[p] == 0)
2643                     {
2644                       r = solv->rules + solv->featurerules + (i - solv->installed->start);
2645                       if (!r->p)                /* update rule == feature rule? */
2646                         r = r - solv->featurerules + solv->updaterules;
2647                       olevel = level;
2648                       POOL_DEBUG(SAT_DEBUG_POLICY, "installing (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
2649                       level = setpropagatelearn(solv, level, p, disablerules, r->p ? r - solv->rules : 0);
2650                       if (level == 0)
2651                         {
2652                           queue_free(&dq);
2653                           queue_free(&dqs);
2654                           return;
2655                         }
2656                       if (level <= olevel)
2657                         break;
2658                     }
2659                   p = i;
2660                   /* now that the best version is installed, try to
2661                    * keep the original one */
2662                   if (solv->decisionmap[p])     /* already decided? */
2663                    continue;
2664                   r = solv->rules + solv->updaterules + (i - solv->installed->start);
2665                   if (!r->p)            /* update rule == feature rule? */
2666                     r = r - solv->updaterules + solv->featurerules;
2667                   if (r->p == p)        /* allowed to keep package? */
2668                     {
2669                       olevel = level;
2670                       POOL_DEBUG(SAT_DEBUG_POLICY, "keeping (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
2671                       level = setpropagatelearn(solv, level, p, disablerules, r - solv->rules);
2672                       if (level == 0)
2673                         {
2674                           queue_free(&dq);
2675                           queue_free(&dqs);
2676                           return;
2677                         }
2678                       if (level <= olevel)
2679                         break;
2680                     }
2681                 }
2682               systemlevel = level + 1;
2683               if (i < solv->installed->end)
2684                 continue;
2685             }
2686             
2687           POOL_DEBUG(SAT_DEBUG_STATS, "resolving update/feature rules\n");
2688             
2689           for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++)
2690             {
2691               Rule *rr;
2692               s = pool->solvables + i;
2693                 
2694                 /* skip if not installed (can't update) */
2695               if (s->repo != solv->installed)
2696                 continue;
2697                 /* skip if already decided */
2698               if (solv->decisionmap[i] > 0)
2699                 continue;
2700                 
2701                 /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
2702               if (MAPTST(&solv->noupdate, i - solv->installed->start))
2703                 continue;
2704                 
2705               queue_empty(&dq);
2706
2707               rr = r;
2708               if (rr->d < 0)    /* disabled -> look at feature rule ? */
2709                 rr -= solv->installed->end - solv->installed->start;
2710               if (!rr->p)       /* identical to update rule? */
2711                 rr = r;
2712               if (rr->p <= 0)
2713                 continue;       /* no such rule or disabled */
2714         
2715               FOR_RULELITERALS(p, dp, rr)
2716                 {
2717                   if (solv->decisionmap[p] > 0)
2718                     break;
2719                   if (solv->decisionmap[p] == 0)
2720                     queue_push(&dq, p);
2721                 }
2722               if (p || !dq.count)       /* already fulfilled or empty */
2723                 continue;
2724               olevel = level;
2725               level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
2726               if (level == 0)
2727                 {
2728                   queue_free(&dq);
2729                   queue_free(&dqs);
2730                   return;
2731                 }
2732               if (level <= olevel)
2733                 break;
2734             }
2735           systemlevel = level + 1;
2736           if (i < solv->installed->end)
2737             continue;
2738         }
2739
2740       if (level < systemlevel)
2741         systemlevel = level;
2742
2743       /*
2744        * decide
2745        */
2746
2747       POOL_DEBUG(SAT_DEBUG_POLICY, "deciding unresolved rules\n");
2748       for (i = 1, n = 1; ; i++, n++)
2749         {
2750           if (n == solv->nrules)
2751             break;
2752           if (i == solv->nrules)
2753             i = 1;
2754           r = solv->rules + i;
2755           if (r->d < 0)         /* ignore disabled rules */
2756             continue;
2757           queue_empty(&dq);
2758           if (r->d == 0)
2759             {
2760               /* binary or unary rule */
2761               /* need two positive undecided literals */
2762               if (r->p < 0 || r->w2 <= 0)
2763                 continue;
2764               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2765                 continue;
2766               queue_push(&dq, r->p);
2767               queue_push(&dq, r->w2);
2768             }
2769           else
2770             {
2771               /* make sure that
2772                * all negative literals are installed
2773                * no positive literal is installed
2774                * i.e. the rule is not fulfilled and we
2775                * just need to decide on the positive literals
2776                */
2777               if (r->p < 0)
2778                 {
2779                   if (solv->decisionmap[-r->p] <= 0)
2780                     continue;
2781                 }
2782               else
2783                 {
2784                   if (solv->decisionmap[r->p] > 0)
2785                     continue;
2786                   if (solv->decisionmap[r->p] == 0)
2787                     queue_push(&dq, r->p);
2788                 }
2789               dp = pool->whatprovidesdata + r->d;
2790               while ((p = *dp++) != 0)
2791                 {
2792                   if (p < 0)
2793                     {
2794                       if (solv->decisionmap[-p] <= 0)
2795                         break;
2796                     }
2797                   else
2798                     {
2799                       if (solv->decisionmap[p] > 0)
2800                         break;
2801                       if (solv->decisionmap[p] == 0)
2802                         queue_push(&dq, p);
2803                     }
2804                 }
2805               if (p)
2806                 continue;
2807             }
2808           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
2809             {
2810               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "unfulfilled ");
2811               solver_printruleclass(solv, SAT_DEBUG_PROPAGATE, r);
2812             }
2813           /* dq.count < 2 cannot happen as this means that
2814            * the rule is unit */
2815           assert(dq.count > 1);
2816
2817           olevel = level;
2818           level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2819           if (level == 0)
2820             {
2821               queue_free(&dq);
2822               queue_free(&dqs);
2823               return;
2824             }
2825           if (level < systemlevel)
2826             break;
2827           n = 0;
2828         } /* for(), decide */
2829
2830       if (n != solv->nrules)    /* continue if level < systemlevel */
2831         continue;
2832
2833       if (doweak)
2834         {
2835           int qcount;
2836
2837           POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended packages\n");
2838           queue_empty(&dq);     /* recommended packages */
2839           queue_empty(&dqs);    /* supplemented packages */
2840           for (i = 1; i < pool->nsolvables; i++)
2841             {
2842               if (solv->decisionmap[i] < 0)
2843                 continue;
2844               if (solv->decisionmap[i] > 0)
2845                 {
2846                   /* installed, check for recommends */
2847                   Id *recp, rec, pp, p;
2848                   s = pool->solvables + i;
2849                   if (solv->ignorealreadyrecommended && s->repo == solv->installed)
2850                     continue;
2851                   /* XXX need to special case AND ? */
2852                   if (s->recommends)
2853                     {
2854                       recp = s->repo->idarraydata + s->recommends;
2855                       while ((rec = *recp++) != 0)
2856                         {
2857                           qcount = dq.count;
2858                           FOR_PROVIDES(p, pp, rec)
2859                             {
2860                               if (solv->decisionmap[p] > 0)
2861                                 {
2862                                   dq.count = qcount;
2863                                   break;
2864                                 }
2865                               else if (solv->decisionmap[p] == 0)
2866                                 {
2867                                   queue_pushunique(&dq, p);
2868                                 }
2869                             }
2870                         }
2871                     }
2872                 }
2873               else
2874                 {
2875                   s = pool->solvables + i;
2876                   if (!s->supplements)
2877                     continue;
2878                   if (!pool_installable(pool, s))
2879                     continue;
2880                   if (!solver_is_supplementing(solv, s))
2881                     continue;
2882                   queue_push(&dqs, i);
2883                 }
2884             }
2885
2886           /* filter out all packages obsoleted by installed packages */
2887           /* this is no longer needed if we have reverse obsoletes */
2888           if ((dqs.count || dq.count) && solv->installed)
2889             {
2890               Map obsmap;
2891               Id obs, *obsp, po, ppo;
2892
2893               map_init(&obsmap, pool->nsolvables);
2894               for (p = solv->installed->start; p < solv->installed->end; p++)
2895                 {
2896                   s = pool->solvables + p;
2897                   if (s->repo != solv->installed || !s->obsoletes)
2898                     continue;
2899                   if (solv->decisionmap[p] <= 0)
2900                     continue;
2901                   if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
2902                     continue;
2903                   obsp = s->repo->idarraydata + s->obsoletes;
2904                   /* foreach obsoletes */
2905                   while ((obs = *obsp++) != 0)
2906                     FOR_PROVIDES(po, ppo, obs)
2907                       MAPSET(&obsmap, po);
2908                 }
2909               for (i = j = 0; i < dqs.count; i++)
2910                 if (!MAPTST(&obsmap, dqs.elements[i]))
2911                   dqs.elements[j++] = dqs.elements[i];
2912               dqs.count = j;
2913               for (i = j = 0; i < dq.count; i++)
2914                 if (!MAPTST(&obsmap, dq.elements[i]))
2915                   dq.elements[j++] = dq.elements[i];
2916               dq.count = j;
2917               map_free(&obsmap);
2918             }
2919
2920           /* filter out all already supplemented packages if requested */
2921           if (solv->ignorealreadyrecommended && dqs.count)
2922             {
2923               /* turn off all new packages */
2924               for (i = 0; i < solv->decisionq.count; i++)
2925                 {
2926                   p = solv->decisionq.elements[i];
2927                   if (p < 0)
2928                     continue;
2929                   s = pool->solvables + p;
2930                   if (s->repo && s->repo != solv->installed)
2931                     solv->decisionmap[p] = -solv->decisionmap[p];
2932                 }
2933               /* filter out old supplements */
2934               for (i = j = 0; i < dqs.count; i++)
2935                 {
2936                   p = dqs.elements[i];
2937                   s = pool->solvables + p;
2938                   if (!s->supplements)
2939                     continue;
2940                   if (!solver_is_supplementing(solv, s))
2941                     dqs.elements[j++] = p;
2942                 }
2943               dqs.count = j;
2944               /* undo turning off */
2945               for (i = 0; i < solv->decisionq.count; i++)
2946                 {
2947                   p = solv->decisionq.elements[i];
2948                   if (p < 0)
2949                     continue;
2950                   s = pool->solvables + p;
2951                   if (s->repo && s->repo != solv->installed)
2952                     solv->decisionmap[p] = -solv->decisionmap[p];
2953                 }
2954             }
2955
2956           /* make dq contain both recommended and supplemented pkgs */
2957           if (dqs.count)
2958             {
2959               for (i = 0; i < dqs.count; i++)
2960                 queue_pushunique(&dq, dqs.elements[i]);
2961             }
2962
2963 #if 1
2964           if (dq.count)
2965             {
2966               Map dqmap;
2967               int decisioncount = solv->decisionq.count;
2968
2969               if (dq.count == 1)
2970                 {
2971                   /* simple case, just one package. no need to choose  */
2972                   p = dq.elements[0];
2973                   if (dqs.count)
2974                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
2975                   else
2976                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
2977                   queue_push(&solv->recommendations, p);
2978                   level = setpropagatelearn(solv, level, p, 0, 0);
2979                   continue;
2980                 }
2981
2982               /* filter and create a map of result */
2983               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2984               map_init(&dqmap, pool->nsolvables);
2985               for (i = 0; i < dq.count; i++)
2986                 MAPSET(&dqmap, dq.elements[i]);
2987
2988               /* install all supplemented packages */
2989               for (i = 0; i < dqs.count; i++)
2990                 {
2991                   p = dqs.elements[i];
2992                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2993                     continue;
2994                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
2995                   queue_push(&solv->recommendations, p);
2996                   olevel = level;
2997                   level = setpropagatelearn(solv, level, p, 0, 0);
2998                   if (level <= olevel)
2999                     break;
3000                 }
3001               if (i < dqs.count || solv->decisionq.count < decisioncount)
3002                 {
3003                   map_free(&dqmap);
3004                   continue;
3005                 }
3006
3007               /* install all recommended packages */
3008               /* more work as we want to created branches if multiple
3009                * choices are valid */
3010               for (i = 0; i < decisioncount; i++)
3011                 {
3012                   Id rec, *recp, pp;
3013                   p = solv->decisionq.elements[i];
3014                   if (p < 0)
3015                     continue;
3016                   s = pool->solvables + p;
3017                   if (!s->repo || (solv->ignorealreadyrecommended && s->repo == solv->installed))
3018                     continue;
3019                   if (!s->recommends)
3020                     continue;
3021                   recp = s->repo->idarraydata + s->recommends;
3022                   while ((rec = *recp++) != 0)
3023                     {
3024                       queue_empty(&dq);
3025                       FOR_PROVIDES(p, pp, rec)
3026                         {
3027                           if (solv->decisionmap[p] > 0)
3028                             {
3029                               dq.count = 0;
3030                               break;
3031                             }
3032                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
3033                             queue_pushunique(&dq, p);
3034                         }
3035                       if (!dq.count)
3036                         continue;
3037                       if (dq.count > 1)
3038                         {
3039                           /* multiple candidates, open a branch */
3040                           for (i = 1; i < dq.count; i++)
3041                             queue_push(&solv->branches, dq.elements[i]);
3042                           queue_push(&solv->branches, -level);
3043                         }
3044                       p = dq.elements[0];
3045                       POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
3046                       queue_push(&solv->recommendations, p);
3047                       olevel = level;
3048                       level = setpropagatelearn(solv, level, p, 0, 0);
3049                       if (level <= olevel || solv->decisionq.count < decisioncount)
3050                         break;
3051                     }
3052                   if (rec)
3053                     break;      /* had a problem above, quit loop */
3054                 }
3055               map_free(&dqmap);
3056               continue;
3057             }
3058 #else
3059           if (dq.count)
3060             {
3061               if (dq.count > 1)
3062                 policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
3063               p = dq.elements[0];
3064               /* prefer recommended patterns (bnc#450226) */
3065               /* real fix is to minimize recommended packages as well */
3066               for (i = 0; i < dq.count; i++)
3067                 if (!strncmp(id2str(pool, pool->solvables[dq.elements[i]].name), "pattern:", 8))
3068                   {
3069                     p = dq.elements[i];
3070                     break;
3071                   }
3072               POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
3073               queue_push(&solv->recommendations, p);
3074               level = setpropagatelearn(solv, level, p, 0, 0);
3075               continue;
3076             }
3077 #endif
3078         }
3079
3080      if (solv->distupgrade && solv->installed)
3081         {
3082           /* let's see if we can install some unsupported package */
3083           POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n");
3084           for (i = 0; i < solv->orphaned.count; i++)
3085             {
3086               p = solv->orphaned.elements[i];
3087               if (!solv->decisionmap[p])
3088                 break;
3089             }
3090           if (i < solv->orphaned.count)
3091             {
3092               p = solv->orphaned.elements[i];
3093               if (solv->distupgrade_removeunsupported)
3094                 {
3095                   POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
3096                   level = setpropagatelearn(solv, level, -p, 0, 0);
3097                 }
3098               else
3099                 {
3100                   POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
3101                   level = setpropagatelearn(solv, level, p, 0, 0);
3102                 }
3103               continue;
3104             }
3105         }
3106
3107      if (solv->solution_callback)
3108         {
3109           solv->solution_callback(solv, solv->solution_callback_data);
3110           if (solv->branches.count)
3111             {
3112               int i = solv->branches.count - 1;
3113               int l = -solv->branches.elements[i];
3114               Id why;
3115
3116               for (; i > 0; i--)
3117                 if (solv->branches.elements[i - 1] < 0)
3118                   break;
3119               p = solv->branches.elements[i];
3120               POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
3121               queue_empty(&dq);
3122               for (j = i + 1; j < solv->branches.count; j++)
3123                 queue_push(&dq, solv->branches.elements[j]);
3124               solv->branches.count = i;
3125               level = l;
3126               revert(solv, level);
3127               if (dq.count > 1)
3128                 for (j = 0; j < dq.count; j++)
3129                   queue_push(&solv->branches, dq.elements[j]);
3130               olevel = level;
3131               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
3132               assert(why >= 0);
3133               level = setpropagatelearn(solv, level, p, disablerules, why);
3134               if (level == 0)
3135                 {
3136                   queue_free(&dq);
3137                   queue_free(&dqs);
3138                   return;
3139                 }
3140               continue;
3141             }
3142           /* all branches done, we're finally finished */
3143           break;
3144         }
3145
3146       /* minimization step */
3147      if (solv->branches.count)
3148         {
3149           int l = 0, lasti = -1, lastl = -1;
3150           Id why;
3151
3152           p = 0;
3153           for (i = solv->branches.count - 1; i >= 0; i--)
3154             {
3155               p = solv->branches.elements[i];
3156               if (p < 0)
3157                 l = -p;
3158               else if (p > 0 && solv->decisionmap[p] > l + 1)
3159                 {
3160                   lasti = i;
3161                   lastl = l;
3162                 }
3163             }
3164           if (lasti >= 0)
3165             {
3166               /* kill old solvable so that we do not loop */
3167               p = solv->branches.elements[lasti];
3168               solv->branches.elements[lasti] = 0;
3169               POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvable2str(pool, pool->solvables + p));
3170               minimizationsteps++;
3171
3172               level = lastl;
3173               revert(solv, level);
3174               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
3175               assert(why >= 0);
3176               olevel = level;
3177               level = setpropagatelearn(solv, level, p, disablerules, why);
3178               if (level == 0)
3179                 {
3180                   queue_free(&dq);
3181                   queue_free(&dqs);
3182                   return;
3183                 }
3184               continue;
3185             }
3186         }
3187       break;
3188     }
3189   POOL_DEBUG(SAT_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
3190
3191   POOL_DEBUG(SAT_DEBUG_STATS, "done solving.\n\n");
3192   queue_free(&dq);
3193   queue_free(&dqs);
3194 }
3195
3196
3197 /*-------------------------------------------------------------------
3198  * 
3199  * refine_suggestion
3200  * 
3201  * at this point, all rules that led to conflicts are disabled.
3202  * we re-enable all rules of a problem set but rule "sug", then
3203  * continue to disable more rules until there as again a solution.
3204  */
3205
3206 /* FIXME: think about conflicting assertions */
3207
3208 static void
3209 refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
3210 {
3211   Pool *pool = solv->pool;
3212   int i, j;
3213   Id v;
3214   Queue disabled;
3215   int disabledcnt;
3216
3217   IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
3218     {
3219       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
3220       for (i = 0; problem[i]; i++)
3221         {
3222           if (problem[i] == sug)
3223             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
3224           solver_printproblem(solv, problem[i]);
3225         }
3226     }
3227   queue_init(&disabled);
3228   queue_empty(refined);
3229   queue_push(refined, sug);
3230
3231   /* re-enable all problem rules with the exception of "sug"(gestion) */
3232   revert(solv, 1);
3233   reset_solver(solv);
3234
3235   for (i = 0; problem[i]; i++)
3236     if (problem[i] != sug)
3237       enableproblem(solv, problem[i]);
3238
3239   if (sug < 0)
3240     disableupdaterules(solv, job, -(sug + 1));
3241   else if (sug >= solv->updaterules && sug < solv->updaterules_end)
3242     {
3243       /* enable feature rule */
3244       Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
3245       if (r->p)
3246         enablerule(solv, r);
3247     }
3248
3249   enableweakrules(solv);
3250
3251   for (;;)
3252     {
3253       int njob, nfeature, nupdate;
3254       queue_empty(&solv->problems);
3255       revert(solv, 1);          /* XXX no longer needed? */
3256       reset_solver(solv);
3257
3258       if (!solv->problems.count)
3259         run_solver(solv, 0, 0);
3260
3261       if (!solv->problems.count)
3262         {
3263           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
3264           IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
3265             solver_printdecisions(solv);
3266           break;                /* great, no more problems */
3267         }
3268       disabledcnt = disabled.count;
3269       /* start with 1 to skip over proof index */
3270       njob = nfeature = nupdate = 0;
3271       for (i = 1; i < solv->problems.count - 1; i++)
3272         {
3273           /* ignore solutions in refined */
3274           v = solv->problems.elements[i];
3275           if (v == 0)
3276             break;      /* end of problem reached */
3277           for (j = 0; problem[j]; j++)
3278             if (problem[j] != sug && problem[j] == v)
3279               break;
3280           if (problem[j])
3281             continue;
3282           if (v >= solv->featurerules && v < solv->featurerules_end)
3283             nfeature++;
3284           else if (v > 0)
3285             nupdate++;
3286           else
3287             {
3288               if ((job->elements[-v -1] & SOLVER_ESSENTIAL) != 0)
3289                 continue;       /* not that one! */
3290               njob++;
3291             }
3292           queue_push(&disabled, v);
3293         }
3294       if (disabled.count == disabledcnt)
3295         {
3296           /* no solution found, this was an invalid suggestion! */
3297           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
3298           refined->count = 0;
3299           break;
3300         }
3301       if (!njob && nupdate && nfeature)
3302         {
3303           /* got only update rules, filter out feature rules */
3304           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "throwing away feature rules\n");
3305           for (i = j = disabledcnt; i < disabled.count; i++)
3306             {
3307               v = disabled.elements[i];
3308               if (v < solv->featurerules || v >= solv->featurerules_end)
3309                 disabled.elements[j++] = v;
3310             }
3311           disabled.count = j;
3312           nfeature = 0;
3313         }
3314       if (disabled.count == disabledcnt + 1)
3315         {
3316           /* just one suggestion, add it to refined list */
3317           v = disabled.elements[disabledcnt];
3318           if (!nfeature)
3319             queue_push(refined, v);     /* do not record feature rules */
3320           disableproblem(solv, v);
3321           if (v >= solv->updaterules && v < solv->updaterules_end)
3322             {
3323               Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
3324               if (r->p)
3325                 enablerule(solv, r);    /* enable corresponding feature rule */
3326             }
3327           if (v < 0)
3328             disableupdaterules(solv, job, -(v + 1));
3329         }
3330       else
3331         {
3332           /* more than one solution, disable all */
3333           /* do not push anything on refine list, as we do not know which solution to choose */
3334           /* thus, the user will get another problem if he selects this solution, where he
3335            * can choose the right one */
3336           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
3337             {
3338               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
3339               for (i = disabledcnt; i < disabled.count; i++)
3340                 solver_printproblem(solv, disabled.elements[i]);
3341             }
3342           for (i = disabledcnt; i < disabled.count; i++)
3343             {
3344               v = disabled.elements[i];
3345               disableproblem(solv, v);
3346               if (v >= solv->updaterules && v < solv->updaterules_end)
3347                 {
3348                   Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
3349                   if (r->p)
3350                     enablerule(solv, r);
3351                 }
3352             }
3353         }
3354     }
3355   /* all done, get us back into the same state as before */
3356   /* enable refined rules again */
3357   for (i = 0; i < disabled.count; i++)
3358     enableproblem(solv, disabled.elements[i]);
3359   /* disable problem rules again */
3360
3361   /* FIXME! */
3362   for (i = 0; problem[i]; i++)
3363     enableproblem(solv, problem[i]);
3364   disableupdaterules(solv, job, -1);
3365
3366   /* disable problem rules again */
3367   for (i = 0; problem[i]; i++)
3368     disableproblem(solv, problem[i]);
3369   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
3370 }
3371
3372
3373 /*-------------------------------------------------------------------
3374  * sorting helper for problems
3375  *
3376  * bring update rules before job rules
3377  * make essential job rules last
3378  */
3379
3380 Queue *problems_sort_data;
3381
3382 static int
3383 problems_sortcmp(const void *ap, const void *bp)
3384 {
3385   Id a = *(Id *)ap, b = *(Id *)bp;
3386   if (a < 0 && b > 0)
3387     return 1;
3388   if (a > 0 && b < 0)
3389     return -1;
3390   if (a < 0 && b < 0)
3391     {
3392       Queue *job = problems_sort_data;
3393       int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
3394       int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
3395       int x = af - bf;
3396       if (x)
3397         return x;
3398     }
3399   return a - b;
3400 }
3401
3402
3403 /*-------------------------------------------------------------------
3404  * sort problems
3405  */
3406
3407 static void
3408 problems_sort(Solver *solv, Queue *job)
3409 {
3410   int i, j;
3411   if (!solv->problems.count)
3412     return;
3413   for (i = j = 1; i < solv->problems.count; i++)
3414     {
3415       if (!solv->problems.elements[i])
3416         {
3417           if (i > j + 1)
3418             {
3419               problems_sort_data = job;
3420               qsort(solv->problems.elements + j, i - j, sizeof(Id), problems_sortcmp);
3421             }
3422           if (++i == solv->problems.count)
3423             break;
3424           j = i + 1;
3425         }
3426     }
3427 }
3428
3429
3430 /*-------------------------------------------------------------------
3431  * convert problems to solutions
3432  */
3433
3434 static void
3435 problems_to_solutions(Solver *solv, Queue *job)
3436 {
3437   Pool *pool = solv->pool;
3438   Queue problems;
3439   Queue solution;
3440   Queue solutions;
3441   Id *problem;
3442   Id why;
3443   int i, j, nsol, probsolved;
3444   unsigned int now, refnow;
3445
3446   if (!solv->problems.count)
3447     return;
3448   now = sat_timems(0);
3449   problems_sort(solv, job);
3450   queue_clone(&problems, &solv->problems);
3451   queue_init(&solution);
3452   queue_init(&solutions);
3453   /* copy over proof index */
3454   queue_push(&solutions, problems.elements[0]);
3455   problem = problems.elements + 1;
3456   probsolved = 0;
3457   refnow = sat_timems(0);
3458   for (i = 1; i < problems.count; i++)
3459     {
3460       Id v = problems.elements[i];
3461       if (v == 0)
3462         {
3463           /* mark end of this problem */
3464           queue_push(&solutions, 0);
3465           queue_push(&solutions, 0);
3466           POOL_DEBUG(SAT_DEBUG_STATS, "refining took %d ms\n", sat_timems(refnow));
3467           if (i + 1 == problems.count)
3468             break;
3469           /* copy over proof of next problem */
3470           queue_push(&solutions, problems.elements[i + 1]);
3471           i++;
3472           problem = problems.elements + i + 1;
3473           refnow = sat_timems(0);
3474           probsolved = 0;
3475           continue;
3476         }
3477       if (v < 0 && (job->elements[-v - 1] & SOLVER_ESSENTIAL))
3478         {
3479           /* essential job, skip if we already have a non-essential
3480              solution */
3481           if (probsolved > 0)
3482             continue;
3483           probsolved = -1;      /* show all solutions */
3484         }
3485       refine_suggestion(solv, job, problem, v, &solution);
3486       if (!solution.count)
3487         continue;       /* this solution didn't work out */
3488
3489       nsol = 0;
3490       for (j = 0; j < solution.count; j++)
3491         {
3492           why = solution.elements[j];
3493           /* must be either job descriptor or update rule */
3494           assert(why < 0 || (why >= solv->updaterules && why < solv->updaterules_end));
3495 #if 0
3496           solver_printproblem(solv, why);
3497 #endif
3498           if (why < 0)
3499             {
3500               /* job descriptor */
3501               queue_push(&solutions, 0);
3502               queue_push(&solutions, -why);
3503             }
3504           else
3505             {
3506               /* update rule, find replacement package */
3507               Id p, *dp, rp = 0;
3508               Rule *rr;
3509               p = solv->installed->start + (why - solv->updaterules);
3510               rr = solv->rules + solv->featurerules + (why - solv->updaterules);
3511               if (!rr->p)
3512                 rr = solv->rules + why;
3513               if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
3514                 {
3515                   /* distupgrade case, allow to keep old package */
3516                   queue_push(&solutions, p);
3517                   queue_push(&solutions, p);
3518                   nsol++;
3519                   continue;
3520                 }
3521               if (solv->decisionmap[p] > 0)
3522                 continue;       /* false alarm, turned out we can keep the package */
3523               if (rr->w2)
3524                 {
3525                   int mvrp = 0;         /* multi-version replacement */
3526                   FOR_RULELITERALS(rp, dp, rr)
3527                     {
3528                       if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
3529                         {
3530                           mvrp = rp;
3531                           if (!(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, rp)))
3532                             break;
3533                         }
3534                     }
3535                   if (!rp && mvrp)
3536                     {
3537                       /* found only multi-version replacements */
3538                       /* have to split solution into two parts */
3539                       queue_push(&solutions, p);
3540                       queue_push(&solutions, mvrp);
3541                       nsol++;
3542                     }
3543                 }
3544               queue_push(&solutions, p);
3545               queue_push(&solutions, rp);
3546             }
3547           nsol++;
3548         }
3549       /* mark end of this solution */
3550       if (nsol)
3551         {
3552           if (!probsolved)
3553             probsolved = 1;
3554           queue_push(&solutions, 0);
3555           queue_push(&solutions, 0);
3556         }
3557       else
3558         {
3559           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "Oops, everything was fine?\n");
3560         }
3561     }
3562   queue_free(&solution);
3563   queue_free(&problems);
3564   /* copy queue over to solutions */
3565   queue_free(&solv->problems);
3566   queue_clone(&solv->problems, &solutions);
3567
3568   /* bring solver back into problem state */
3569   revert(solv, 1);              /* XXX move to reset_solver? */
3570   reset_solver(solv);
3571
3572   assert(solv->problems.count == solutions.count);
3573   queue_free(&solutions);
3574   POOL_DEBUG(SAT_DEBUG_STATS, "problems_to_solutions took %d ms\n", sat_timems(now));
3575 }
3576
3577
3578 /*-------------------------------------------------------------------
3579  * 
3580  * problem iterator
3581  * 
3582  * advance to next problem
3583  */
3584
3585 Id
3586 solver_next_problem(Solver *solv, Id problem)
3587 {
3588   Id *pp;
3589   if (problem == 0)
3590     return solv->problems.count ? 1 : 0;
3591   pp = solv->problems.elements + problem;
3592   while (pp[0] || pp[1])
3593     {
3594       /* solution */
3595       pp += 2;
3596       while (pp[0] || pp[1])
3597         pp += 2;
3598       pp += 2;
3599     }
3600   pp += 2;
3601   problem = pp - solv->problems.elements;
3602   if (problem >= solv->problems.count)
3603     return 0;
3604   return problem + 1;
3605 }
3606
3607
3608 /*-------------------------------------------------------------------
3609  * 
3610  * solution iterator
3611  */
3612
3613 Id
3614 solver_next_solution(Solver *solv, Id problem, Id solution)
3615 {
3616   Id *pp;
3617   if (solution == 0)
3618     {
3619       solution = problem;
3620       pp = solv->problems.elements + solution;
3621       return pp[0] || pp[1] ? solution : 0;
3622     }
3623   pp = solv->problems.elements + solution;
3624   while (pp[0] || pp[1])
3625     pp += 2;
3626   pp += 2;
3627   solution = pp - solv->problems.elements;
3628   return pp[0] || pp[1] ? solution : 0;
3629 }
3630
3631
3632 /*-------------------------------------------------------------------
3633  * 
3634  * solution element iterator
3635  */
3636
3637 Id
3638 solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
3639 {
3640   Id *pp;
3641   element = element ? element + 2 : solution;
3642   pp = solv->problems.elements + element;
3643   if (!(pp[0] || pp[1]))
3644     return 0;
3645   *p = pp[0];
3646   *rp = pp[1];
3647   return element;
3648 }
3649
3650
3651 /*-------------------------------------------------------------------
3652  * 
3653  * Retrieve information about a problematic rule
3654  *
3655  * this is basically the reverse of addrpmrulesforsolvable
3656  */
3657
3658 SolverProbleminfo
3659 solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
3660 {
3661   Pool *pool = solv->pool;
3662   Repo *installed = solv->installed;
3663   Rule *r;
3664   Solvable *s;
3665   int dontfix = 0;
3666   Id p, d, w2, pp, req, *reqp, con, *conp, obs, *obsp, *dp;
3667
3668   assert(rid > 0);
3669   if (rid >= solv->jobrules && rid < solv->jobrules_end)
3670     {
3671
3672       r = solv->rules + rid;
3673       p = solv->ruletojob.elements[rid - solv->jobrules];
3674       *depp = job->elements[p + 1];
3675       *sourcep = p;
3676       *targetp = job->elements[p];
3677       d = r->d < 0 ? -r->d - 1 : r->d;
3678       if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (job->elements[p] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
3679         return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
3680       return SOLVER_PROBLEM_JOB_RULE;
3681     }
3682   if (rid >= solv->updaterules && rid < solv->updaterules_end)
3683     {
3684       *depp = 0;
3685       *sourcep = solv->installed->start + (rid - solv->updaterules);
3686       *targetp = 0;
3687       return SOLVER_PROBLEM_UPDATE_RULE;
3688     }
3689   assert(rid < solv->rpmrules_end);
3690   r = solv->rules + rid;
3691   assert(r->p < 0);
3692   d = r->d < 0 ? -r->d - 1 : r->d;
3693   if (d == 0 && r->w2 == 0)
3694     {
3695       /* a rpm rule assertion */
3696       s = pool->solvables - r->p;
3697       if (installed && !solv->fixsystem && s->repo == installed)
3698         dontfix = 1;
3699       assert(!dontfix); /* dontfix packages never have a neg assertion */
3700       *sourcep = -r->p;
3701       *targetp = 0;
3702       /* see why the package is not installable */
3703       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
3704         {
3705           *depp = 0;
3706           return SOLVER_PROBLEM_NOT_INSTALLABLE;
3707         }
3708       /* check requires */
3709       if (s->requires)
3710         {
3711           reqp = s->repo->idarraydata + s->requires;
3712           while ((req = *reqp++) != 0)
3713             {
3714               if (req == SOLVABLE_PREREQMARKER)
3715                 continue;
3716               dp = pool->whatprovidesdata + pool_whatprovides(pool, req);
3717               if (*dp == 0)
3718                 break;
3719             }
3720           if (req)
3721             {
3722               *depp = req;
3723               return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP;
3724             }
3725         }
3726       if (!solv->allowselfconflicts && s->conflicts)
3727         {
3728           conp = s->repo->idarraydata + s->conflicts;
3729           while ((con = *conp++) != 0)
3730             FOR_PROVIDES(p, pp, con)
3731               if (p == -r->p)
3732                 {
3733                   *depp = con;
3734                   return SOLVER_PROBLEM_SELF_CONFLICT;
3735                 }
3736         }
3737       /* should never happen */
3738       *depp = 0;
3739       return SOLVER_PROBLEM_RPM_RULE;
3740     }
3741   s = pool->solvables - r->p;
3742   if (installed && !solv->fixsystem && s->repo == installed)
3743     dontfix = 1;
3744   w2 = r->w2;
3745   if (d && pool->whatprovidesdata[d] < 0)
3746     {
3747       /* rule looks like -p|-c|x|x|x..., we only create this for patches with multiversion */
3748       /* reduce it to -p|-c case */
3749       w2 = pool->whatprovidesdata[d];
3750     }
3751   if (d == 0 && w2 < 0)
3752     {
3753       /* a package conflict */
3754       Solvable *s2 = pool->solvables - w2;
3755       int dontfix2 = 0;
3756
3757       if (installed && !solv->fixsystem && s2->repo == installed)
3758         dontfix2 = 1;
3759
3760       /* if both packages have the same name and at least one of them
3761        * is not installed, they conflict */
3762       if (s->name == s2->name && !(installed && s->repo == installed && s2->repo == installed))
3763         {
3764           /* also check noobsoletes map */
3765           if ((s->evr == s2->evr && s->arch == s2->arch) || !solv->noobsoletes.size
3766                 || ((!installed || s->repo != installed) && !MAPTST(&solv->noobsoletes, -r->p))
3767                 || ((!installed || s2->repo != installed) && !MAPTST(&solv->noobsoletes, -w2)))
3768             {
3769               *depp = 0;
3770               *sourcep = -r->p;
3771               *targetp = -w2;
3772               return SOLVER_PROBLEM_SAME_NAME;
3773             }
3774         }
3775
3776       /* check conflicts in both directions */
3777       if (s->conflicts)
3778         {
3779           conp = s->repo->idarraydata + s->conflicts;
3780           while ((con = *conp++) != 0)
3781             {
3782               FOR_PROVIDES(p, pp, con)
3783                 {
3784                   if (dontfix && pool->solvables[p].repo == installed)
3785                     continue;
3786                   if (p != -w2)
3787                     continue;
3788                   *depp = con;
3789                   *sourcep = -r->p;
3790                   *targetp = p;
3791                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
3792                 }
3793             }
3794         }
3795       if (s2->conflicts)
3796         {
3797           conp = s2->repo->idarraydata + s2->conflicts;
3798           while ((con = *conp++) != 0)
3799             {
3800               FOR_PROVIDES(p, pp, con)
3801                 {
3802                   if (dontfix2 && pool->solvables[p].repo == installed)
3803                     continue;
3804                   if (p != -r->p)
3805                     continue;
3806                   *depp = con;
3807                   *sourcep = -w2;
3808                   *targetp = p;
3809                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
3810                 }
3811             }
3812         }
3813       /* check obsoletes in both directions */
3814       if ((!installed || s->repo != installed) && s->obsoletes && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -r->p)))
3815         {
3816           obsp = s->repo->idarraydata + s->obsoletes;
3817           while ((obs = *obsp++) != 0)
3818             {
3819               FOR_PROVIDES(p, pp, obs)
3820                 {
3821                   if (p != -w2)
3822                     continue;
3823                   if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
3824                     continue;
3825                   *depp = obs;
3826                   *sourcep = -r->p;
3827                   *targetp = p;
3828                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3829                 }
3830             }
3831         }
3832       if ((!installed || s2->repo != installed) && s2->obsoletes && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -w2)))
3833         {
3834           obsp = s2->repo->idarraydata + s2->obsoletes;
3835           while ((obs = *obsp++) != 0)
3836             {
3837               FOR_PROVIDES(p, pp, obs)
3838                 {
3839                   if (p != -r->p)
3840                     continue;
3841                   if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
3842                     continue;
3843                   *depp = obs;
3844                   *sourcep = -w2;
3845                   *targetp = p;
3846                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3847                 }
3848             }
3849         }
3850       if (solv->implicitobsoleteusesprovides && (!installed || s->repo != installed) && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -r->p)))
3851         {
3852           FOR_PROVIDES(p, pp, s->name)
3853             {
3854               if (p != -w2)
3855                 continue;
3856               *depp = s->name;
3857               *sourcep = -r->p;
3858               *targetp = p;
3859               return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3860             }
3861         }
3862       if (solv->implicitobsoleteusesprovides && (!installed || s2->repo != installed) && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -w2)))
3863         {
3864           FOR_PROVIDES(p, pp, s2->name)
3865             {
3866               if (p != -r->p)
3867                 continue;
3868               *depp = s2->name;
3869               *sourcep = -w2;
3870               *targetp = p;
3871               return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3872             }
3873         }
3874       /* all cases checked, can't happen */
3875       *depp = 0;
3876       *sourcep = -r->p;
3877       *targetp = 0;
3878       return SOLVER_PROBLEM_RPM_RULE;
3879     }
3880   /* simple requires */
3881   if (s->requires)
3882     {
3883       reqp = s->repo->idarraydata + s->requires;
3884       while ((req = *reqp++) != 0)
3885         {
3886           if (req == SOLVABLE_PREREQMARKER)
3887             continue;
3888           dp = pool->whatprovidesdata + pool_whatprovides(pool, req);
3889           if (d == 0)
3890             {
3891               if (*dp == r->w2 && dp[1] == 0)
3892                 break;
3893             }
3894           else if (dp - pool->whatprovidesdata == d)
3895             break;
3896         }
3897       if (req)
3898         {
3899           *depp = req;
3900           *sourcep = -r->p;
3901           *targetp = 0;
3902           return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE;
3903         }
3904     }
3905   /* all cases checked, can't happen */
3906   *depp = 0;
3907   *sourcep = -r->p;
3908   *targetp = 0;
3909   return SOLVER_PROBLEM_RPM_RULE;
3910 }
3911
3912
3913 /*-------------------------------------------------------------------
3914  * 
3915  * find problem rule
3916  */
3917
3918 static void
3919 findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
3920 {
3921   Id rid, d;
3922   Id lreqr, lconr, lsysr, ljobr;
3923   Rule *r;
3924   int reqassert = 0;
3925
3926   lreqr = lconr = lsysr = ljobr = 0;
3927   while ((rid = solv->learnt_pool.elements[idx++]) != 0)
3928     {
3929       assert(rid > 0);
3930       if (rid >= solv->learntrules)
3931         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
3932       else if (rid >= solv->jobrules && rid < solv->jobrules_end)
3933         {
3934           if (!*jobrp)
3935             *jobrp = rid;
3936         }
3937       else if (rid >= solv->updaterules && rid < solv->updaterules_end)
3938         {
3939           if (!*sysrp)
3940             *sysrp = rid;
3941         }
3942       else
3943         {
3944           assert(rid < solv->rpmrules_end);
3945           r = solv->rules + rid;
3946           d = r->d < 0 ? -r->d - 1 : r->d;
3947           if (!d && r->w2 < 0)
3948             {
3949               if (!*conrp)
3950                 *conrp = rid;
3951             }
3952           else
3953             {
3954               if (!d && r->w2 == 0 && !reqassert)
3955                 {
3956                   if (*reqrp > 0 && r->p < -1)
3957                     {
3958                       Id op = -solv->rules[*reqrp].p;
3959                       if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
3960                         continue;       /* different arch, skip */
3961                     }
3962                   /* prefer assertions */
3963                   *reqrp = rid;
3964                   reqassert = 1;
3965                 }
3966               if (!*reqrp)
3967                 *reqrp = rid;
3968               else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && !reqassert)
3969                 {
3970                   /* prefer rules of installed packages */
3971                   *reqrp = rid;
3972                 }
3973             }
3974         }
3975     }
3976   if (!*reqrp && lreqr)
3977     *reqrp = lreqr;
3978   if (!*conrp && lconr)
3979     *conrp = lconr;
3980   if (!*jobrp && ljobr)
3981     *jobrp = ljobr;
3982   if (!*sysrp && lsysr)
3983     *sysrp = lsysr;
3984 }
3985
3986
3987 /*-------------------------------------------------------------------
3988  * 
3989  * find problem rule
3990  *
3991  * search for a rule that describes the problem to the
3992  * user. A pretty hopeless task, actually. We currently
3993  * prefer simple requires.
3994  */
3995
3996 Id
3997 solver_findproblemrule(Solver *solv, Id problem)
3998 {
3999   Id reqr, conr, sysr, jobr;
4000   Id idx = solv->problems.elements[problem - 1];
4001   reqr = conr = sysr = jobr = 0;
4002   findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
4003   if (reqr)
4004     return reqr;
4005   if (conr)
4006     return conr;
4007   if (sysr)
4008     return sysr;
4009   if (jobr)
4010     return jobr;
4011   assert(0);
4012 }
4013
4014
4015 /*-------------------------------------------------------------------
4016  * 
4017  * create reverse obsoletes map for installed solvables
4018  *
4019  * for each installed solvable find which packages with *different* names
4020  * obsolete the solvable.
4021  * this index is used in policy_findupdatepackages if noupdateprovide is set.
4022  */
4023
4024 static void
4025 create_obsolete_index(Solver *solv)
4026 {
4027   Pool *pool = solv->pool;
4028   Solvable *s;
4029   Repo *installed = solv->installed;
4030   Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
4031   int i, n;
4032
4033   if (!installed || !installed->nsolvables)
4034     return;
4035   solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
4036   for (i = 1; i < pool->nsolvables; i++)
4037     {
4038       s = pool->solvables + i;
4039       if (!s->obsoletes)
4040         continue;
4041       if (!pool_installable(pool, s))
4042         continue;
4043       obsp = s->repo->idarraydata + s->obsoletes;
4044       while ((obs = *obsp++) != 0)
4045         {
4046           FOR_PROVIDES(p, pp, obs)
4047             {
4048               if (pool->solvables[p].repo != installed)
4049                 continue;
4050               if (pool->solvables[p].name == s->name)
4051                 continue;
4052               if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
4053                 continue;
4054               obsoletes[p - installed->start]++;
4055             }
4056         }
4057     }
4058   n = 0;
4059   for (i = 0; i < installed->nsolvables; i++)
4060     if (obsoletes[i])
4061       {
4062         n += obsoletes[i] + 1;
4063         obsoletes[i] = n;
4064       }
4065   solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
4066   POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
4067   for (i = pool->nsolvables - 1; i > 0; i--)
4068     {
4069       s = pool->solvables + i;
4070       if (!s->obsoletes)
4071         continue;
4072       if (!pool_installable(pool, s))
4073         continue;
4074       obsp = s->repo->idarraydata + s->obsoletes;
4075       while ((obs = *obsp++) != 0)
4076         {
4077           FOR_PROVIDES(p, pp, obs)
4078             {
4079               if (pool->solvables[p].repo != installed)
4080                 continue;
4081               if (pool->solvables[p].name == s->name)
4082                 continue;
4083               if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
4084                 continue;
4085               p -= installed->start;
4086               if (obsoletes_data[obsoletes[p]] != i)
4087                 obsoletes_data[--obsoletes[p]] = i;
4088             }
4089         }
4090     }
4091 }
4092
4093
4094 /*-------------------------------------------------------------------
4095  * 
4096  * remove disabled conflicts
4097  */
4098
4099 static void
4100 removedisabledconflicts(Solver *solv, Queue *removed)
4101 {
4102   Pool *pool = solv->pool;
4103   int i, n;
4104   Id p, why, *dp;
4105   Id new;
4106   Rule *r;
4107   Id *decisionmap = solv->decisionmap;
4108
4109   POOL_DEBUG(SAT_DEBUG_SCHUBI, "removedisabledconflicts\n");
4110   queue_empty(removed);
4111   for (i = 0; i < solv->decisionq.count; i++)
4112     {
4113       p = solv->decisionq.elements[i];
4114       if (p > 0)
4115         continue;
4116       /* a conflict. we never do conflicts on free decisions, so there
4117        * must have been an unit rule */
4118       why = solv->decisionq_why.elements[i];
4119       assert(why > 0);
4120       r = solv->rules + why;
4121       if (r->d < 0 && decisionmap[-p])
4122         {
4123           /* rule is now disabled, remove from decisionmap */
4124           POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p);
4125           queue_push(removed, -p);
4126           queue_push(removed, decisionmap[-p]);
4127           decisionmap[-p] = 0;
4128         }
4129     }
4130   if (!removed->count)
4131     return;
4132   /* we removed some confliced packages. some of them might still
4133    * be in conflict, so search for unit rules and re-conflict */
4134   new = 0;
4135   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
4136     {
4137       if (i == solv->nrules)
4138         {
4139           i = 1;
4140           r = solv->rules + i;
4141         }
4142       if (r->d < 0)
4143         continue;
4144       if (!r->w2)
4145         {
4146           if (r->p < 0 && !decisionmap[-r->p])
4147             new = r->p;
4148         }
4149       else if (!r->d)
4150         {
4151           /* binary rule */
4152           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
4153             new = r->p;
4154           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
4155             new = r->w2;
4156         }
4157       else
4158         {
4159           if (r->p < 0 && decisionmap[-r->p] == 0)
4160             new = r->p;
4161           if (new || DECISIONMAP_FALSE(r->p))
4162             {
4163               dp = pool->whatprovidesdata + r->d;
4164               while ((p = *dp++) != 0)
4165                 {
4166                   if (new && p == new)
4167                     continue;
4168                   if (p < 0 && decisionmap[-p] == 0)
4169                     {
4170                       if (new)
4171                         {
4172                           new = 0;
4173                           break;
4174                         }
4175                       new = p;
4176                     }
4177                   else if (!DECISIONMAP_FALSE(p))
4178                     {
4179                       new = 0;
4180                       break;
4181                     }
4182                 }
4183             }
4184         }
4185       if (new)
4186         {
4187           POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new);
4188           decisionmap[-new] = -1;
4189           new = 0;
4190           n = 0;        /* redo all rules */
4191         }
4192     }
4193 }
4194
4195
4196 /*-------------------------------------------------------------------
4197  *
4198  * weaken solvable dependencies
4199  */
4200
4201 static void
4202 weaken_solvable_deps(Solver *solv, Id p)
4203 {
4204   int i;
4205   Rule *r;
4206
4207   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
4208     {
4209       if (r->p != -p)
4210         continue;
4211       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
4212         continue;       /* conflict */
4213       queue_push(&solv->weakruleq, i);
4214     }
4215 }
4216
4217 /********************************************************************/
4218 /* main() */
4219
4220 /*
4221  *
4222  * solve job queue
4223  *
4224  */
4225
4226 void
4227 solver_solve(Solver *solv, Queue *job)
4228 {
4229   Pool *pool = solv->pool;
4230   Repo *installed = solv->installed;
4231   int i;
4232   int oldnrules;
4233   Map addedmap;                /* '1' == have rpm-rules for solvable */
4234   Map installcandidatemap;
4235   Id how, what, select, name, weak, p, pp, d;
4236   Queue q, redoq;
4237   Solvable *s;
4238   int goterase;
4239   Rule *r;
4240   int now, solve_start;
4241
4242   solve_start = sat_timems(0);
4243   POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n");
4244   POOL_DEBUG(SAT_DEBUG_STATS, "fixsystem=%d updatesystem=%d dosplitprovides=%d, noupdateprovide=%d\n", solv->fixsystem, solv->updatesystem, solv->dosplitprovides, solv->noupdateprovide);
4245   POOL_DEBUG(SAT_DEBUG_STATS, "distupgrade=%d distupgrade_removeunsupported=%d\n", solv->distupgrade, solv->distupgrade_removeunsupported);
4246   POOL_DEBUG(SAT_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allowarchchange, solv->allowvendorchange);
4247   POOL_DEBUG(SAT_DEBUG_STATS, "promoteepoch=%d, allowvirtualconflicts=%d, allowselfconflicts=%d\n", pool->promoteepoch, solv->allowvirtualconflicts, solv->allowselfconflicts);
4248   POOL_DEBUG(SAT_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d\n", solv->obsoleteusesprovides, solv->implicitobsoleteusesprovides);
4249   POOL_DEBUG(SAT_DEBUG_STATS, "dontinstallrecommended=%d, ignorealreadyrecommended=%d, dontshowinstalledrecommended=%d\n", solv->dontinstallrecommended, solv->ignorealreadyrecommended, solv->dontshowinstalledrecommended);
4250   /* create whatprovides if not already there */
4251   if (!pool->whatprovides)
4252     pool_createwhatprovides(pool);
4253
4254   /* create obsolete index */
4255   create_obsolete_index(solv);
4256
4257   /* remember job */
4258   solv->job = job;
4259
4260   /*
4261    * create basic rule set of all involved packages
4262    * use addedmap bitmap to make sure we don't create rules twice
4263    *
4264    */
4265
4266   /* create noobsolete map if needed */
4267   for (i = 0; i < job->count; i += 2)
4268     {
4269       how = job->elements[i] & ~SOLVER_WEAK;
4270       if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
4271         continue;
4272       what = job->elements[i + 1];
4273       select = how & SOLVER_SELECTMASK;
4274       if (!solv->noobsoletes.size)
4275         map_init(&solv->noobsoletes, pool->nsolvables);
4276       FOR_JOB_SELECT(p, pp, select, what)
4277         MAPSET(&solv->noobsoletes, p);
4278     }
4279
4280   map_init(&addedmap, pool->nsolvables);
4281   map_init(&installcandidatemap, pool->nsolvables);
4282   queue_init(&q);
4283
4284   /*
4285    * always install our system solvable
4286    */
4287   MAPSET(&addedmap, SYSTEMSOLVABLE);
4288   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
4289   queue_push(&solv->decisionq_why, 0);
4290   solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */
4291
4292   now = sat_timems(0);
4293   /*
4294    * create rules for all package that could be involved with the solving
4295    * so called: rpm rules
4296    *
4297    */
4298   if (installed)
4299     {
4300       oldnrules = solv->nrules;
4301       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
4302       FOR_REPO_SOLVABLES(installed, p, s)
4303         addrpmrulesforsolvable(solv, s, &addedmap);
4304       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
4305       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
4306       oldnrules = solv->nrules;
4307       FOR_REPO_SOLVABLES(installed, p, s)
4308         addrpmrulesforupdaters(solv, s, &addedmap, 1);
4309       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
4310     }
4311
4312   /*
4313    * create rules for all packages involved in the job
4314    * (to be installed or removed)
4315    */
4316     
4317   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for packages involved with a job ***\n");
4318   oldnrules = solv->nrules;
4319   for (i = 0; i < job->count; i += 2)
4320     {
4321       how = job->elements[i];
4322       what = job->elements[i + 1];
4323       select = how & SOLVER_SELECTMASK;
4324
4325       switch (how & SOLVER_JOBMASK)
4326         {
4327         case SOLVER_INSTALL:
4328           FOR_JOB_SELECT(p, pp, select, what)
4329             {
4330               MAPSET(&installcandidatemap, p);
4331               addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
4332             }
4333           break;
4334         case SOLVER_UPDATE:
4335           /* FIXME: semantics? */
4336           FOR_JOB_SELECT(p, pp, select, what)
4337             addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
4338           break;
4339         }
4340     }
4341   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
4342
4343   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
4344
4345   oldnrules = solv->nrules;
4346     
4347     /*
4348      * add rules for suggests, enhances
4349      */
4350   addrpmrulesforweak(solv, &addedmap);
4351   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
4352
4353   IF_POOLDEBUG (SAT_DEBUG_STATS)
4354     {
4355       int possible = 0, installable = 0;
4356       for (i = 1; i < pool->nsolvables; i++)
4357         {
4358           if (pool_installable(pool, pool->solvables + i))
4359             installable++;
4360           if (MAPTST(&addedmap, i))
4361             possible++;
4362         }
4363       POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
4364     }
4365
4366   /*
4367    * first pass done, we now have all the rpm rules we need.
4368    * unify existing rules before going over all job rules and
4369    * policy rules.
4370    * at this point the system is always solvable,
4371    * as an empty system (remove all packages) is a valid solution
4372    */
4373
4374   unifyrules(solv);                               /* remove duplicate rpm rules */
4375
4376   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
4377
4378   solv->directdecisions = solv->decisionq.count;
4379   POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule memory usage: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
4380   POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
4381   POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule creation took %d ms\n", sat_timems(now));
4382
4383   /*
4384    * create feature rules
4385    * 
4386    * foreach installed:
4387    *   create assertion (keep installed, if no update available)
4388    *   or
4389    *   create update rule (A|update1(A)|update2(A)|...)
4390    * 
4391    * those are used later on to keep a version of the installed packages in
4392    * best effort mode
4393    */
4394     
4395   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add feature rules ***\n");
4396   solv->featurerules = solv->nrules;              /* mark start of feature rules */
4397   if (installed)
4398     {
4399         /* foreach possibly installed solvable */
4400       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
4401         {
4402           if (s->repo != installed)
4403             {
4404               addrule(solv, 0, 0);      /* create dummy rule */
4405               continue;
4406             }
4407           addupdaterule(solv, s, 1);    /* allow s to be updated */
4408         }
4409         /*
4410          * assert one rule per installed solvable,
4411          * either an assertion (A)
4412          * or a possible update (A|update1(A)|update2(A)|...)
4413          */
4414       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
4415     }
4416   solv->featurerules_end = solv->nrules;
4417
4418     /*
4419      * Add update rules for installed solvables
4420      * 
4421      * almost identical to feature rules
4422      * except that downgrades/archchanges/vendorchanges are not allowed
4423      */
4424     
4425   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add update rules ***\n");
4426   solv->updaterules = solv->nrules;
4427
4428   if (installed)
4429     { /* foreach installed solvables */
4430       /* we create all update rules, but disable some later on depending on the job */
4431       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
4432         {
4433           Rule *sr;
4434
4435           if (s->repo != installed)
4436             {
4437               addrule(solv, 0, 0);      /* create dummy rule */
4438               continue;
4439             }
4440           addupdaterule(solv, s, 0);    /* allowall = 0: downgrades not allowed */
4441             /*
4442              * check for and remove duplicate
4443              */
4444           r = solv->rules + solv->nrules - 1;           /* r: update rule */
4445           sr = r - (installed->end - installed->start); /* sr: feature rule */
4446           /* it's orphaned if there is no feature rule or the feature rule
4447            * consists just of the installed package */
4448           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
4449             queue_push(&solv->orphaned, i);
4450           if (!r->p)
4451             {
4452               assert(solv->distupgrade && !sr->p);
4453               continue;
4454             }
4455           unifyrules_sortcmp_data = pool;
4456           if (!unifyrules_sortcmp(r, sr))
4457             {
4458               /* identical rule, kill unneeded rule */
4459               if (solv->allowuninstall)
4460                 {
4461                   /* keep feature rule, make it weak */
4462                   memset(r, 0, sizeof(*r));
4463                   queue_push(&solv->weakruleq, sr - solv->rules);
4464                 }
4465               else
4466                 {
4467                   /* keep update rule */
4468                   memset(sr, 0, sizeof(*sr));
4469                 }
4470             }
4471           else if (solv->allowuninstall)
4472             {
4473               /* make both feature and update rule weak */
4474               queue_push(&solv->weakruleq, r - solv->rules);
4475               queue_push(&solv->weakruleq, sr - solv->rules);
4476             }
4477           else
4478             disablerule(solv, sr);
4479         }
4480       /* consistency check: we added a rule for _every_ installed solvable */
4481       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
4482     }
4483   solv->updaterules_end = solv->nrules;
4484
4485
4486   /*
4487    * now add all job rules
4488    */
4489
4490   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add JOB rules ***\n");
4491
4492   solv->jobrules = solv->nrules;
4493   for (i = 0; i < job->count; i += 2)
4494     {
4495       oldnrules = solv->nrules;
4496
4497       how = job->elements[i];
4498       what = job->elements[i + 1];
4499       weak = how & SOLVER_WEAK;
4500       select = how & SOLVER_SELECTMASK;
4501       switch (how & SOLVER_JOBMASK)
4502         {
4503         case SOLVER_INSTALL:
4504           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4505           if (select == SOLVER_SOLVABLE)
4506             {
4507               p = what;
4508               d = 0;
4509             }
4510           else
4511             {
4512               queue_empty(&q);
4513               FOR_JOB_SELECT(p, pp, select, what)
4514                 queue_push(&q, p);
4515               if (!q.count)
4516                 {
4517                   /* no candidate found, make this an impossible rule */
4518                   queue_push(&q, -SYSTEMSOLVABLE);
4519                 }
4520               p = queue_shift(&q);      /* get first candidate */
4521               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
4522             }
4523           addrule(solv, p, d);          /* add install rule */
4524           queue_push(&solv->ruletojob, i);
4525           if (weak)
4526             queue_push(&solv->weakruleq, solv->nrules - 1);
4527           break;
4528         case SOLVER_ERASE:
4529           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4530           if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
4531             {
4532               /* special case for "erase a specific solvable": we also
4533                * erase all other solvables with that name, so that they
4534                * don't get picked up as replacement */
4535               name = pool->solvables[what].name;
4536               FOR_PROVIDES(p, pp, name)
4537                 {
4538                   if (p == what)
4539                     continue;
4540                   s = pool->solvables + p;
4541                   if (s->name != name)
4542                     continue;
4543                   /* keep other versions installed */
4544                   if (s->repo == solv->installed)
4545                     continue;
4546                   /* keep installcandidates of other jobs */
4547                   if (MAPTST(&installcandidatemap, p))
4548                     continue;
4549                   addrule(solv, -p, 0);                 /* remove by Id */
4550                   queue_push(&solv->ruletojob, i);
4551                   if (weak)
4552                     queue_push(&solv->weakruleq, solv->nrules - 1);
4553                 }
4554             }
4555           FOR_JOB_SELECT(p, pp, select, what)
4556             {
4557               addrule(solv, -p, 0);
4558               queue_push(&solv->ruletojob, i);
4559               if (weak)
4560                 queue_push(&solv->weakruleq, solv->nrules - 1);
4561             }
4562           break;
4563
4564         case SOLVER_UPDATE:
4565           POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4566           if (select != SOLVER_SOLVABLE)
4567             break;
4568           s = pool->solvables + what;
4569           POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solvable2str(pool, s));
4570           addupdaterule(solv, s, 0);
4571           queue_push(&solv->ruletojob, i);
4572           if (weak)
4573             queue_push(&solv->weakruleq, solv->nrules - 1);
4574           break;
4575         case SOLVER_WEAKENDEPS:
4576           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4577           if (select != SOLVER_SOLVABLE)
4578             break;
4579           s = pool->solvables + what;
4580           weaken_solvable_deps(solv, what);
4581           break;
4582         case SOLVER_NOOBSOLETES:
4583           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4584           break;
4585         case SOLVER_LOCK:
4586           POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4587           FOR_JOB_SELECT(p, pp, select, what)
4588             {
4589               s = pool->solvables + p;
4590               if (installed && s->repo == installed)
4591                 addrule(solv, p, 0);
4592               else
4593                 addrule(solv, -p, 0);
4594               queue_push(&solv->ruletojob, i);
4595               if (weak)
4596                 queue_push(&solv->weakruleq, solv->nrules - 1);
4597             }
4598           break;
4599         default:
4600           POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
4601           break;
4602         }
4603         
4604         /*
4605          * debug
4606          */
4607         
4608       IF_POOLDEBUG (SAT_DEBUG_JOB)
4609         {
4610           int j;
4611           if (solv->nrules == oldnrules)
4612             POOL_DEBUG(SAT_DEBUG_JOB, " - no rule created\n");
4613           for (j = oldnrules; j < solv->nrules; j++)
4614             {
4615               POOL_DEBUG(SAT_DEBUG_JOB, " - job ");
4616               solver_printrule(solv, SAT_DEBUG_JOB, solv->rules + j);
4617             }
4618         }
4619     }
4620   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
4621   solv->jobrules_end = solv->nrules;
4622
4623     /* all rules created
4624      * --------------------------------------------------------------
4625      * prepare for solving
4626      */
4627     
4628   /* free unneeded memory */
4629   map_free(&addedmap);
4630   map_free(&installcandidatemap);
4631   queue_free(&q);
4632
4633   /* create weak map */
4634   map_init(&solv->weakrulemap, solv->nrules);
4635   for (i = 0; i < solv->weakruleq.count; i++)
4636     {
4637       p = solv->weakruleq.elements[i];
4638       MAPSET(&solv->weakrulemap, p);
4639     }
4640
4641   /* all new rules are learnt after this point */
4642   solv->learntrules = solv->nrules;
4643
4644   /* create assertion index. it is only used to speed up
4645    * makeruledecsions() a bit */
4646   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
4647     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
4648       queue_push(&solv->ruleassertions, i);
4649
4650   /* disable update rules that conflict with our job */
4651   disableupdaterules(solv, job, -1);
4652
4653   /* make decisions based on job/update assertions */
4654   makeruledecisions(solv);
4655
4656   /* create watches chains */
4657   makewatches(solv);
4658
4659   POOL_DEBUG(SAT_DEBUG_STATS, "problems so far: %d\n", solv->problems.count);
4660
4661   /*
4662    * ********************************************
4663    * solve!
4664    * ********************************************
4665    */
4666     
4667   now = sat_timems(0);
4668   run_solver(solv, 1, solv->dontinstallrecommended ? 0 : 1);
4669   POOL_DEBUG(SAT_DEBUG_STATS, "solver took %d ms\n", sat_timems(now));
4670
4671   queue_init(&redoq);
4672   goterase = 0;
4673   /* disable all erase jobs (including weak "keep uninstalled" rules) */
4674   for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++)
4675     {
4676       if (r->d < 0)     /* disabled ? */
4677         continue;
4678       if (r->p > 0)     /* install job? */
4679         continue;
4680       disablerule(solv, r);
4681       goterase++;
4682     }
4683   
4684   if (goterase)
4685     {
4686       enabledisablelearntrules(solv);
4687       removedisabledconflicts(solv, &redoq);
4688     }
4689
4690   /*
4691    * find recommended packages
4692    */
4693     
4694   /* if redoq.count == 0 we already found all recommended in the
4695    * solver run */
4696   if (redoq.count || solv->dontinstallrecommended || !solv->dontshowinstalledrecommended || solv->ignorealreadyrecommended)
4697     {
4698       Id rec, *recp, p, pp;
4699
4700       /* create map of all recommened packages */
4701       solv->recommends_index = -1;
4702       MAPZERO(&solv->recommendsmap);
4703       for (i = 0; i < solv->decisionq.count; i++)
4704         {
4705           p = solv->decisionq.elements[i];
4706           if (p < 0)
4707             continue;
4708           s = pool->solvables + p;
4709           if (s->recommends)
4710             {
4711               recp = s->repo->idarraydata + s->recommends;
4712               while ((rec = *recp++) != 0)
4713                 {
4714                   FOR_PROVIDES(p, pp, rec)
4715                     if (solv->decisionmap[p] > 0)
4716                       break;
4717                   if (p)
4718                     {
4719                       if (!solv->dontshowinstalledrecommended)
4720                         {
4721                           FOR_PROVIDES(p, pp, rec)
4722                             if (solv->decisionmap[p] > 0)
4723                               MAPSET(&solv->recommendsmap, p);
4724                         }
4725                       continue; /* p != 0: already fulfilled */
4726                     }
4727                   FOR_PROVIDES(p, pp, rec)
4728                     MAPSET(&solv->recommendsmap, p);
4729                 }
4730             }
4731         }
4732       for (i = 1; i < pool->nsolvables; i++)
4733         {
4734           if (solv->decisionmap[i] < 0)
4735             continue;
4736           if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended)
4737             continue;
4738           s = pool->solvables + i;
4739           if (!MAPTST(&solv->recommendsmap, i))
4740             {
4741               if (!s->supplements)
4742                 continue;
4743               if (!pool_installable(pool, s))
4744                 continue;
4745               if (!solver_is_supplementing(solv, s))
4746                 continue;
4747             }
4748           if (solv->dontinstallrecommended)
4749             queue_push(&solv->recommendations, i);
4750           else
4751             queue_pushunique(&solv->recommendations, i);
4752         }
4753       /* we use MODE_SUGGEST here so that repo prio is ignored */
4754       policy_filter_unwanted(solv, &solv->recommendations, POLICY_MODE_SUGGEST);
4755     }
4756
4757   /*
4758    * find suggested packages
4759    */
4760     
4761   if (1)
4762     {
4763       Id sug, *sugp, p, pp;
4764
4765       /* create map of all suggests that are still open */
4766       solv->recommends_index = -1;
4767       MAPZERO(&solv->suggestsmap);
4768       for (i = 0; i < solv->decisionq.count; i++)
4769         {
4770           p = solv->decisionq.elements[i];
4771           if (p < 0)
4772             continue;
4773           s = pool->solvables + p;
4774           if (s->suggests)
4775             {
4776               sugp = s->repo->idarraydata + s->suggests;
4777               while ((sug = *sugp++) != 0)
4778                 {
4779                   FOR_PROVIDES(p, pp, sug)
4780                     if (solv->decisionmap[p] > 0)
4781                       break;
4782                   if (p)
4783                     {
4784                       if (!solv->dontshowinstalledrecommended)
4785                         {
4786                           FOR_PROVIDES(p, pp, sug)
4787                             if (solv->decisionmap[p] > 0)
4788                               MAPSET(&solv->suggestsmap, p);
4789                         }
4790                       continue; /* already fulfilled */
4791                     }
4792                   FOR_PROVIDES(p, pp, sug)
4793                     MAPSET(&solv->suggestsmap, p);
4794                 }
4795             }
4796         }
4797       for (i = 1; i < pool->nsolvables; i++)
4798         {
4799           if (solv->decisionmap[i] < 0)
4800             continue;
4801           if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended)
4802             continue;
4803           s = pool->solvables + i;
4804           if (!MAPTST(&solv->suggestsmap, i))
4805             {
4806               if (!s->enhances)
4807                 continue;
4808               if (!pool_installable(pool, s))
4809                 continue;
4810               if (!solver_is_enhancing(solv, s))
4811                 continue;
4812             }
4813           queue_push(&solv->suggestions, i);
4814         }
4815       policy_filter_unwanted(solv, &solv->suggestions, POLICY_MODE_SUGGEST);
4816     }
4817
4818   if (redoq.count)
4819     {
4820       /* restore decisionmap */
4821       for (i = 0; i < redoq.count; i += 2)
4822         solv->decisionmap[redoq.elements[i]] = redoq.elements[i + 1];
4823     }
4824
4825     /*
4826      * if unsolvable, prepare solutions
4827      */
4828
4829   if (solv->problems.count)
4830     {
4831       int recocount = solv->recommendations.count;
4832       solv->recommendations.count = 0;  /* so that revert() doesn't mess with it */
4833       queue_empty(&redoq);
4834       for (i = 0; i < solv->decisionq.count; i++)
4835         {
4836           Id p = solv->decisionq.elements[i];
4837           queue_push(&redoq, p);
4838           queue_push(&redoq, solv->decisionq_why.elements[i]);
4839           queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
4840         }
4841       problems_to_solutions(solv, job);
4842       memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
4843       queue_empty(&solv->decisionq);
4844       queue_empty(&solv->decisionq_why);
4845       for (i = 0; i < redoq.count; i += 3)
4846         {
4847           Id p = redoq.elements[i];
4848           queue_push(&solv->decisionq, p);
4849           queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
4850           solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
4851         }
4852       solv->recommendations.count = recocount;
4853     }
4854
4855   queue_free(&redoq);
4856   POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d learned rules, %d unsolvable\n", solv->stats_learned, solv->stats_unsolvable);
4857   POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start));
4858   solv->job = 0;
4859 }
4860
4861 /***********************************************************************/
4862 /* disk usage computations */
4863
4864 /*-------------------------------------------------------------------
4865  * 
4866  * calculate DU changes
4867  */
4868
4869 void
4870 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
4871 {
4872   Map installedmap;
4873
4874   solver_create_state_maps(solv, &installedmap, 0);
4875   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
4876   map_free(&installedmap);
4877 }
4878
4879
4880 /*-------------------------------------------------------------------
4881  * 
4882  * calculate changes in install size
4883  */
4884
4885 int
4886 solver_calc_installsizechange(Solver *solv)
4887 {
4888   Map installedmap;
4889   int change;
4890
4891   solver_create_state_maps(solv, &installedmap, 0);
4892   change = pool_calc_installsizechange(solv->pool, &installedmap);
4893   map_free(&installedmap);
4894   return change;
4895 }
4896
4897 #define FIND_INVOLVED_DEBUG 0
4898 void
4899 solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
4900 {
4901   Pool *pool = solv->pool;
4902   Map im;
4903   Map installedm;
4904   Solvable *s;
4905   Queue iq;
4906   Queue installedq_internal;
4907   Id tp, ip, p, pp, req, *reqp, sup, *supp;
4908   int i, count;
4909
4910   tp = ts - pool->solvables;
4911   queue_init(&iq);
4912   queue_init(&installedq_internal);
4913   map_init(&im, pool->nsolvables);
4914   map_init(&installedm, pool->nsolvables);
4915
4916   if (!installedq)
4917     {
4918       installedq = &installedq_internal;
4919       if (solv->installed)
4920         {
4921           for (ip = solv->installed->start; ip < solv->installed->end; ip++)
4922             {
4923               s = pool->solvables + ip;
4924               if (s->repo != solv->installed)
4925                 continue;
4926               queue_push(installedq, ip);
4927             }
4928         }
4929     }
4930   for (i = 0; i < installedq->count; i++)
4931     {
4932       ip = installedq->elements[i];
4933       MAPSET(&installedm, ip);
4934       MAPSET(&im, ip);
4935     }
4936
4937   queue_push(&iq, ts - pool->solvables);
4938   while (iq.count)
4939     {
4940       ip = queue_shift(&iq);
4941       if (!MAPTST(&im, ip))
4942         continue;
4943       if (!MAPTST(&installedm, ip))
4944         continue;
4945       MAPCLR(&im, ip);
4946       s = pool->solvables + ip;
4947 #if FIND_INVOLVED_DEBUG
4948       printf("hello %s\n", solvable2str(pool, s));
4949 #endif
4950       if (s->requires)
4951         {
4952           reqp = s->repo->idarraydata + s->requires;
4953           while ((req = *reqp++) != 0)
4954             {
4955               if (req == SOLVABLE_PREREQMARKER)
4956                 continue;
4957               /* count number of installed packages that match */
4958               count = 0;
4959               FOR_PROVIDES(p, pp, req)
4960                 if (MAPTST(&installedm, p))
4961                   count++;
4962               if (count > 1)
4963                 continue;
4964               FOR_PROVIDES(p, pp, req)
4965                 {
4966                   if (MAPTST(&im, p))
4967                     {
4968 #if FIND_INVOLVED_DEBUG
4969                       printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
4970 #endif
4971                       queue_push(&iq, p);
4972                     }
4973                 }
4974             }
4975         }
4976       if (s->recommends)
4977         {
4978           reqp = s->repo->idarraydata + s->recommends;
4979           while ((req = *reqp++) != 0)
4980             {
4981               count = 0;
4982               FOR_PROVIDES(p, pp, req)
4983                 if (MAPTST(&installedm, p))
4984                   count++;
4985               if (count > 1)
4986                 continue;
4987               FOR_PROVIDES(p, pp, req)
4988                 {
4989                   if (MAPTST(&im, p))
4990                     {
4991 #if FIND_INVOLVED_DEBUG
4992                       printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
4993 #endif
4994                       queue_push(&iq, p);
4995                     }
4996                 }
4997             }
4998         }
4999       if (!iq.count)
5000         {
5001           /* supplements pass */
5002           for (i = 0; i < installedq->count; i++)
5003             {
5004               ip = installedq->elements[i];
5005               s = pool->solvables + ip;
5006               if (!s->supplements)
5007                 continue;
5008               if (!MAPTST(&im, ip))
5009                 continue;
5010               supp = s->repo->idarraydata + s->supplements;
5011               while ((sup = *supp++) != 0)
5012                 if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
5013                   break;
5014               /* no longer supplemented, also erase */
5015               if (sup)
5016                 {
5017 #if FIND_INVOLVED_DEBUG
5018                   printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
5019 #endif
5020                   queue_push(&iq, ip);
5021                 }
5022             }
5023         }
5024     }
5025
5026   for (i = 0; i < installedq->count; i++)
5027     {
5028       ip = installedq->elements[i];
5029       if (MAPTST(&im, ip))
5030         queue_push(&iq, ip);
5031     }
5032
5033   while (iq.count)
5034     {
5035       ip = queue_shift(&iq);
5036       if (!MAPTST(&installedm, ip))
5037         continue;
5038       s = pool->solvables + ip;
5039 #if FIND_INVOLVED_DEBUG
5040       printf("bye %s\n", solvable2str(pool, s));
5041 #endif
5042       if (s->requires)
5043         {
5044           reqp = s->repo->idarraydata + s->requires;
5045           while ((req = *reqp++) != 0)
5046             {
5047               FOR_PROVIDES(p, pp, req)
5048                 {
5049                   if (!MAPTST(&im, p))
5050                     {
5051                       if (p == tp)
5052                         continue;
5053 #if FIND_INVOLVED_DEBUG
5054                       printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
5055 #endif
5056                       MAPSET(&im, p);
5057                       queue_push(&iq, p);
5058                     }
5059                 }
5060             }
5061         }
5062       if (s->recommends)
5063         {
5064           reqp = s->repo->idarraydata + s->recommends;
5065           while ((req = *reqp++) != 0)
5066             {
5067               FOR_PROVIDES(p, pp, req)
5068                 {
5069                   if (!MAPTST(&im, p))
5070                     {
5071                       if (p == tp)
5072                         continue;
5073 #if FIND_INVOLVED_DEBUG
5074                       printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
5075 #endif
5076                       MAPSET(&im, p);
5077                       queue_push(&iq, p);
5078                     }
5079                 }
5080             }
5081         }
5082       if (!iq.count)
5083         {
5084           /* supplements pass */
5085           for (i = 0; i < installedq->count; i++)
5086             {
5087               ip = installedq->elements[i];
5088               if (ip == tp)
5089                 continue;
5090               s = pool->solvables + ip;
5091               if (!s->supplements)
5092                 continue;
5093               if (MAPTST(&im, ip))
5094                 continue;
5095               supp = s->repo->idarraydata + s->supplements;
5096               while ((sup = *supp++) != 0)
5097                 if (dep_possible(solv, sup, &im))
5098                   break;
5099               if (sup)
5100                 {
5101 #if FIND_INVOLVED_DEBUG
5102                   printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
5103 #endif
5104                   MAPSET(&im, ip);
5105                   queue_push(&iq, ip);
5106                 }
5107             }
5108         }
5109     }
5110     
5111   queue_free(&iq);
5112
5113   /* convert map into result */
5114   for (i = 0; i < installedq->count; i++)
5115     {
5116       ip = installedq->elements[i];
5117       if (MAPTST(&im, ip))
5118         continue;
5119       if (ip == ts - pool->solvables)
5120         continue;
5121       queue_push(q, ip);
5122     }
5123   map_free(&im);
5124   map_free(&installedm);
5125   queue_free(&installedq_internal);
5126 }
5127
5128 /* EOF */