- also provide a reason for free decisions so that Klaus can
[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 already supplemented packages if requested */
2887           if (solv->ignorealreadyrecommended && dqs.count)
2888             {
2889               /* turn off all new packages */
2890               for (i = 0; i < solv->decisionq.count; i++)
2891                 {
2892                   p = solv->decisionq.elements[i];
2893                   if (p < 0)
2894                     continue;
2895                   s = pool->solvables + p;
2896                   if (s->repo && s->repo != solv->installed)
2897                     solv->decisionmap[p] = -solv->decisionmap[p];
2898                 }
2899               /* filter out old supplements */
2900               for (i = j = 0; i < dqs.count; i++)
2901                 {
2902                   p = dqs.elements[i];
2903                   s = pool->solvables + p;
2904                   if (!s->supplements)
2905                     continue;
2906                   if (!solver_is_supplementing(solv, s))
2907                     dqs.elements[j++] = p;
2908                 }
2909               dqs.count = j;
2910               /* undo turning off */
2911               for (i = 0; i < solv->decisionq.count; i++)
2912                 {
2913                   p = solv->decisionq.elements[i];
2914                   if (p < 0)
2915                     continue;
2916                   s = pool->solvables + p;
2917                   if (s->repo && s->repo != solv->installed)
2918                     solv->decisionmap[p] = -solv->decisionmap[p];
2919                 }
2920             }
2921
2922           /* make dq contain both recommended and supplemented pkgs */
2923           if (dqs.count)
2924             {
2925               for (i = 0; i < dqs.count; i++)
2926                 queue_pushunique(&dq, dqs.elements[i]);
2927             }
2928
2929 #if 1
2930           if (dq.count)
2931             {
2932               Map dqmap;
2933               int decisioncount = solv->decisionq.count;
2934
2935               if (dq.count == 1)
2936                 {
2937                   /* simple case, just one package. no need to choose  */
2938                   p = dq.elements[0];
2939                   if (dqs.count)
2940                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
2941                   else
2942                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
2943                   queue_push(&solv->recommendations, p);
2944                   level = setpropagatelearn(solv, level, p, 0, 0);
2945                   continue;
2946                 }
2947
2948               /* filter and create a map of result */
2949               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2950               map_init(&dqmap, pool->nsolvables);
2951               for (i = 0; i < dq.count; i++)
2952                 MAPSET(&dqmap, dq.elements[i]);
2953
2954               /* install all supplemented packages */
2955               for (i = 0; i < dqs.count; i++)
2956                 {
2957                   p = dqs.elements[i];
2958                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2959                     continue;
2960                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
2961                   queue_push(&solv->recommendations, p);
2962                   olevel = level;
2963                   level = setpropagatelearn(solv, level, p, 0, 0);
2964                   if (level <= olevel)
2965                     break;
2966                 }
2967               if (i < dqs.count || solv->decisionq.count < decisioncount)
2968                 {
2969                   map_free(&dqmap);
2970                   continue;
2971                 }
2972
2973               /* install all recommended packages */
2974               /* more work as we want to created branches if multiple
2975                * choices are valid */
2976               for (i = 0; i < decisioncount; i++)
2977                 {
2978                   Id rec, *recp, pp;
2979                   p = solv->decisionq.elements[i];
2980                   if (p < 0)
2981                     continue;
2982                   s = pool->solvables + p;
2983                   if (!s->repo || (solv->ignorealreadyrecommended && s->repo == solv->installed))
2984                     continue;
2985                   if (!s->recommends)
2986                     continue;
2987                   recp = s->repo->idarraydata + s->recommends;
2988                   while ((rec = *recp++) != 0)
2989                     {
2990                       queue_empty(&dq);
2991                       FOR_PROVIDES(p, pp, rec)
2992                         {
2993                           if (solv->decisionmap[p] > 0)
2994                             {
2995                               dq.count = 0;
2996                               break;
2997                             }
2998                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2999                             queue_pushunique(&dq, p);
3000                         }
3001                       if (!dq.count)
3002                         continue;
3003                       if (dq.count > 1)
3004                         {
3005                           /* multiple candidates, open a branch */
3006                           for (i = 1; i < dq.count; i++)
3007                             queue_push(&solv->branches, dq.elements[i]);
3008                           queue_push(&solv->branches, -level);
3009                         }
3010                       p = dq.elements[0];
3011                       POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
3012                       queue_push(&solv->recommendations, p);
3013                       olevel = level;
3014                       level = setpropagatelearn(solv, level, p, 0, 0);
3015                       if (level <= olevel || solv->decisionq.count < decisioncount)
3016                         break;
3017                     }
3018                   if (rec)
3019                     break;      /* had a problem above, quit loop */
3020                 }
3021               map_free(&dqmap);
3022               continue;
3023             }
3024 #else
3025           if (dq.count)
3026             {
3027               if (dq.count > 1)
3028                 policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
3029               p = dq.elements[0];
3030               /* prefer recommended patterns (bnc#450226) */
3031               /* real fix is to minimize recommended packages as well */
3032               for (i = 0; i < dq.count; i++)
3033                 if (!strncmp(id2str(pool, pool->solvables[dq.elements[i]].name), "pattern:", 8))
3034                   {
3035                     p = dq.elements[i];
3036                     break;
3037                   }
3038               POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
3039               queue_push(&solv->recommendations, p);
3040               level = setpropagatelearn(solv, level, p, 0, 0);
3041               continue;
3042             }
3043 #endif
3044         }
3045
3046      if (solv->distupgrade && solv->installed)
3047         {
3048           /* let's see if we can install some unsupported package */
3049           POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n");
3050           for (i = 0; i < solv->orphaned.count; i++)
3051             {
3052               p = solv->orphaned.elements[i];
3053               if (!solv->decisionmap[p])
3054                 break;
3055             }
3056           if (i < solv->orphaned.count)
3057             {
3058               p = solv->orphaned.elements[i];
3059               if (solv->distupgrade_removeunsupported)
3060                 {
3061                   POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
3062                   level = setpropagatelearn(solv, level, -p, 0, 0);
3063                 }
3064               else
3065                 {
3066                   POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
3067                   level = setpropagatelearn(solv, level, p, 0, 0);
3068                 }
3069               continue;
3070             }
3071         }
3072
3073      if (solv->solution_callback)
3074         {
3075           solv->solution_callback(solv, solv->solution_callback_data);
3076           if (solv->branches.count)
3077             {
3078               int i = solv->branches.count - 1;
3079               int l = -solv->branches.elements[i];
3080               Id why;
3081
3082               for (; i > 0; i--)
3083                 if (solv->branches.elements[i - 1] < 0)
3084                   break;
3085               p = solv->branches.elements[i];
3086               POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
3087               queue_empty(&dq);
3088               for (j = i + 1; j < solv->branches.count; j++)
3089                 queue_push(&dq, solv->branches.elements[j]);
3090               solv->branches.count = i;
3091               level = l;
3092               revert(solv, level);
3093               if (dq.count > 1)
3094                 for (j = 0; j < dq.count; j++)
3095                   queue_push(&solv->branches, dq.elements[j]);
3096               olevel = level;
3097               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
3098               assert(why >= 0);
3099               level = setpropagatelearn(solv, level, p, disablerules, why);
3100               if (level == 0)
3101                 {
3102                   queue_free(&dq);
3103                   queue_free(&dqs);
3104                   return;
3105                 }
3106               continue;
3107             }
3108           /* all branches done, we're finally finished */
3109           break;
3110         }
3111
3112       /* minimization step */
3113      if (solv->branches.count)
3114         {
3115           int l = 0, lasti = -1, lastl = -1;
3116           Id why;
3117
3118           p = 0;
3119           for (i = solv->branches.count - 1; i >= 0; i--)
3120             {
3121               p = solv->branches.elements[i];
3122               if (p < 0)
3123                 l = -p;
3124               else if (p > 0 && solv->decisionmap[p] > l + 1)
3125                 {
3126                   lasti = i;
3127                   lastl = l;
3128                 }
3129             }
3130           if (lasti >= 0)
3131             {
3132               /* kill old solvable so that we do not loop */
3133               p = solv->branches.elements[lasti];
3134               solv->branches.elements[lasti] = 0;
3135               POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvable2str(pool, pool->solvables + p));
3136               minimizationsteps++;
3137
3138               level = lastl;
3139               revert(solv, level);
3140               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
3141               assert(why >= 0);
3142               olevel = level;
3143               level = setpropagatelearn(solv, level, p, disablerules, why);
3144               if (level == 0)
3145                 {
3146                   queue_free(&dq);
3147                   queue_free(&dqs);
3148                   return;
3149                 }
3150               continue;
3151             }
3152         }
3153       break;
3154     }
3155   POOL_DEBUG(SAT_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
3156
3157   POOL_DEBUG(SAT_DEBUG_STATS, "done solving.\n\n");
3158   queue_free(&dq);
3159   queue_free(&dqs);
3160 }
3161
3162
3163 /*-------------------------------------------------------------------
3164  * 
3165  * refine_suggestion
3166  * 
3167  * at this point, all rules that led to conflicts are disabled.
3168  * we re-enable all rules of a problem set but rule "sug", then
3169  * continue to disable more rules until there as again a solution.
3170  */
3171
3172 /* FIXME: think about conflicting assertions */
3173
3174 static void
3175 refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
3176 {
3177   Pool *pool = solv->pool;
3178   int i, j;
3179   Id v;
3180   Queue disabled;
3181   int disabledcnt;
3182
3183   IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
3184     {
3185       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
3186       for (i = 0; problem[i]; i++)
3187         {
3188           if (problem[i] == sug)
3189             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
3190           solver_printproblem(solv, problem[i]);
3191         }
3192     }
3193   queue_init(&disabled);
3194   queue_empty(refined);
3195   queue_push(refined, sug);
3196
3197   /* re-enable all problem rules with the exception of "sug"(gestion) */
3198   revert(solv, 1);
3199   reset_solver(solv);
3200
3201   for (i = 0; problem[i]; i++)
3202     if (problem[i] != sug)
3203       enableproblem(solv, problem[i]);
3204
3205   if (sug < 0)
3206     disableupdaterules(solv, job, -(sug + 1));
3207   else if (sug >= solv->updaterules && sug < solv->updaterules_end)
3208     {
3209       /* enable feature rule */
3210       Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
3211       if (r->p)
3212         enablerule(solv, r);
3213     }
3214
3215   enableweakrules(solv);
3216
3217   for (;;)
3218     {
3219       int njob, nfeature, nupdate;
3220       queue_empty(&solv->problems);
3221       revert(solv, 1);          /* XXX no longer needed? */
3222       reset_solver(solv);
3223
3224       if (!solv->problems.count)
3225         run_solver(solv, 0, 0);
3226
3227       if (!solv->problems.count)
3228         {
3229           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
3230           IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
3231             solver_printdecisions(solv);
3232           break;                /* great, no more problems */
3233         }
3234       disabledcnt = disabled.count;
3235       /* start with 1 to skip over proof index */
3236       njob = nfeature = nupdate = 0;
3237       for (i = 1; i < solv->problems.count - 1; i++)
3238         {
3239           /* ignore solutions in refined */
3240           v = solv->problems.elements[i];
3241           if (v == 0)
3242             break;      /* end of problem reached */
3243           for (j = 0; problem[j]; j++)
3244             if (problem[j] != sug && problem[j] == v)
3245               break;
3246           if (problem[j])
3247             continue;
3248           if (v >= solv->featurerules && v < solv->featurerules_end)
3249             nfeature++;
3250           else if (v > 0)
3251             nupdate++;
3252           else
3253             {
3254               if ((job->elements[-v -1] & SOLVER_ESSENTIAL) != 0)
3255                 continue;       /* not that one! */
3256               njob++;
3257             }
3258           queue_push(&disabled, v);
3259         }
3260       if (disabled.count == disabledcnt)
3261         {
3262           /* no solution found, this was an invalid suggestion! */
3263           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
3264           refined->count = 0;
3265           break;
3266         }
3267       if (!njob && nupdate && nfeature)
3268         {
3269           /* got only update rules, filter out feature rules */
3270           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "throwing away feature rules\n");
3271           for (i = j = disabledcnt; i < disabled.count; i++)
3272             {
3273               v = disabled.elements[i];
3274               if (v < solv->featurerules || v >= solv->featurerules_end)
3275                 disabled.elements[j++] = v;
3276             }
3277           disabled.count = j;
3278           nfeature = 0;
3279         }
3280       if (disabled.count == disabledcnt + 1)
3281         {
3282           /* just one suggestion, add it to refined list */
3283           v = disabled.elements[disabledcnt];
3284           if (!nfeature)
3285             queue_push(refined, v);     /* do not record feature rules */
3286           disableproblem(solv, v);
3287           if (v >= solv->updaterules && v < solv->updaterules_end)
3288             {
3289               Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
3290               if (r->p)
3291                 enablerule(solv, r);    /* enable corresponding feature rule */
3292             }
3293           if (v < 0)
3294             disableupdaterules(solv, job, -(v + 1));
3295         }
3296       else
3297         {
3298           /* more than one solution, disable all */
3299           /* do not push anything on refine list, as we do not know which solution to choose */
3300           /* thus, the user will get another problem if he selects this solution, where he
3301            * can choose the right one */
3302           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
3303             {
3304               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
3305               for (i = disabledcnt; i < disabled.count; i++)
3306                 solver_printproblem(solv, disabled.elements[i]);
3307             }
3308           for (i = disabledcnt; i < disabled.count; i++)
3309             {
3310               v = disabled.elements[i];
3311               disableproblem(solv, v);
3312               if (v >= solv->updaterules && v < solv->updaterules_end)
3313                 {
3314                   Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
3315                   if (r->p)
3316                     enablerule(solv, r);
3317                 }
3318             }
3319         }
3320     }
3321   /* all done, get us back into the same state as before */
3322   /* enable refined rules again */
3323   for (i = 0; i < disabled.count; i++)
3324     enableproblem(solv, disabled.elements[i]);
3325   /* disable problem rules again */
3326
3327   /* FIXME! */
3328   for (i = 0; problem[i]; i++)
3329     enableproblem(solv, problem[i]);
3330   disableupdaterules(solv, job, -1);
3331
3332   /* disable problem rules again */
3333   for (i = 0; problem[i]; i++)
3334     disableproblem(solv, problem[i]);
3335   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
3336 }
3337
3338
3339 /*-------------------------------------------------------------------
3340  * sorting helper for problems
3341  *
3342  * bring update rules before job rules
3343  * make essential job rules last
3344  */
3345
3346 Queue *problems_sort_data;
3347
3348 static int
3349 problems_sortcmp(const void *ap, const void *bp)
3350 {
3351   Id a = *(Id *)ap, b = *(Id *)bp;
3352   if (a < 0 && b > 0)
3353     return 1;
3354   if (a > 0 && b < 0)
3355     return -1;
3356   if (a < 0 && b < 0)
3357     {
3358       Queue *job = problems_sort_data;
3359       int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
3360       int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
3361       int x = af - bf;
3362       if (x)
3363         return x;
3364     }
3365   return a - b;
3366 }
3367
3368
3369 /*-------------------------------------------------------------------
3370  * sort problems
3371  */
3372
3373 static void
3374 problems_sort(Solver *solv, Queue *job)
3375 {
3376   int i, j;
3377   if (!solv->problems.count)
3378     return;
3379   for (i = j = 1; i < solv->problems.count; i++)
3380     {
3381       if (!solv->problems.elements[i])
3382         {
3383           if (i > j + 1)
3384             {
3385               problems_sort_data = job;
3386               qsort(solv->problems.elements + j, i - j, sizeof(Id), problems_sortcmp);
3387             }
3388           if (++i == solv->problems.count)
3389             break;
3390           j = i + 1;
3391         }
3392     }
3393 }
3394
3395
3396 /*-------------------------------------------------------------------
3397  * convert problems to solutions
3398  */
3399
3400 static void
3401 problems_to_solutions(Solver *solv, Queue *job)
3402 {
3403   Pool *pool = solv->pool;
3404   Queue problems;
3405   Queue solution;
3406   Queue solutions;
3407   Id *problem;
3408   Id why;
3409   int i, j, nsol, probsolved;
3410   unsigned int now, refnow;
3411
3412   if (!solv->problems.count)
3413     return;
3414   now = sat_timems(0);
3415   problems_sort(solv, job);
3416   queue_clone(&problems, &solv->problems);
3417   queue_init(&solution);
3418   queue_init(&solutions);
3419   /* copy over proof index */
3420   queue_push(&solutions, problems.elements[0]);
3421   problem = problems.elements + 1;
3422   probsolved = 0;
3423   refnow = sat_timems(0);
3424   for (i = 1; i < problems.count; i++)
3425     {
3426       Id v = problems.elements[i];
3427       if (v == 0)
3428         {
3429           /* mark end of this problem */
3430           queue_push(&solutions, 0);
3431           queue_push(&solutions, 0);
3432           POOL_DEBUG(SAT_DEBUG_STATS, "refining took %d ms\n", sat_timems(refnow));
3433           if (i + 1 == problems.count)
3434             break;
3435           /* copy over proof of next problem */
3436           queue_push(&solutions, problems.elements[i + 1]);
3437           i++;
3438           problem = problems.elements + i + 1;
3439           refnow = sat_timems(0);
3440           probsolved = 0;
3441           continue;
3442         }
3443       if (v < 0 && (job->elements[-v - 1] & SOLVER_ESSENTIAL))
3444         {
3445           /* essential job, skip if we already have a non-essential
3446              solution */
3447           if (probsolved > 0)
3448             continue;
3449           probsolved = -1;      /* show all solutions */
3450         }
3451       refine_suggestion(solv, job, problem, v, &solution);
3452       if (!solution.count)
3453         continue;       /* this solution didn't work out */
3454
3455       nsol = 0;
3456       for (j = 0; j < solution.count; j++)
3457         {
3458           why = solution.elements[j];
3459           /* must be either job descriptor or update rule */
3460           assert(why < 0 || (why >= solv->updaterules && why < solv->updaterules_end));
3461 #if 0
3462           solver_printproblem(solv, why);
3463 #endif
3464           if (why < 0)
3465             {
3466               /* job descriptor */
3467               queue_push(&solutions, 0);
3468               queue_push(&solutions, -why);
3469             }
3470           else
3471             {
3472               /* update rule, find replacement package */
3473               Id p, *dp, rp = 0;
3474               Rule *rr;
3475               p = solv->installed->start + (why - solv->updaterules);
3476               rr = solv->rules + solv->featurerules + (why - solv->updaterules);
3477               if (!rr->p)
3478                 rr = solv->rules + why;
3479               if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
3480                 {
3481                   /* distupgrade case, allow to keep old package */
3482                   queue_push(&solutions, p);
3483                   queue_push(&solutions, p);
3484                   nsol++;
3485                   continue;
3486                 }
3487               if (solv->decisionmap[p] > 0)
3488                 continue;       /* false alarm, turned out we can keep the package */
3489               if (rr->w2)
3490                 {
3491                   int mvrp = 0;         /* multi-version replacement */
3492                   FOR_RULELITERALS(rp, dp, rr)
3493                     {
3494                       if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
3495                         {
3496                           mvrp = rp;
3497                           if (!(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, rp)))
3498                             break;
3499                         }
3500                     }
3501                   if (!rp && mvrp)
3502                     {
3503                       /* found only multi-version replacements */
3504                       /* have to split solution into two parts */
3505                       queue_push(&solutions, p);
3506                       queue_push(&solutions, mvrp);
3507                       nsol++;
3508                     }
3509                 }
3510               queue_push(&solutions, p);
3511               queue_push(&solutions, rp);
3512             }
3513           nsol++;
3514         }
3515       /* mark end of this solution */
3516       if (nsol)
3517         {
3518           if (!probsolved)
3519             probsolved = 1;
3520           queue_push(&solutions, 0);
3521           queue_push(&solutions, 0);
3522         }
3523       else
3524         {
3525           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "Oops, everything was fine?\n");
3526         }
3527     }
3528   queue_free(&solution);
3529   queue_free(&problems);
3530   /* copy queue over to solutions */
3531   queue_free(&solv->problems);
3532   queue_clone(&solv->problems, &solutions);
3533
3534   /* bring solver back into problem state */
3535   revert(solv, 1);              /* XXX move to reset_solver? */
3536   reset_solver(solv);
3537
3538   assert(solv->problems.count == solutions.count);
3539   queue_free(&solutions);
3540   POOL_DEBUG(SAT_DEBUG_STATS, "problems_to_solutions took %d ms\n", sat_timems(now));
3541 }
3542
3543
3544 /*-------------------------------------------------------------------
3545  * 
3546  * problem iterator
3547  * 
3548  * advance to next problem
3549  */
3550
3551 Id
3552 solver_next_problem(Solver *solv, Id problem)
3553 {
3554   Id *pp;
3555   if (problem == 0)
3556     return solv->problems.count ? 1 : 0;
3557   pp = solv->problems.elements + problem;
3558   while (pp[0] || pp[1])
3559     {
3560       /* solution */
3561       pp += 2;
3562       while (pp[0] || pp[1])
3563         pp += 2;
3564       pp += 2;
3565     }
3566   pp += 2;
3567   problem = pp - solv->problems.elements;
3568   if (problem >= solv->problems.count)
3569     return 0;
3570   return problem + 1;
3571 }
3572
3573
3574 /*-------------------------------------------------------------------
3575  * 
3576  * solution iterator
3577  */
3578
3579 Id
3580 solver_next_solution(Solver *solv, Id problem, Id solution)
3581 {
3582   Id *pp;
3583   if (solution == 0)
3584     {
3585       solution = problem;
3586       pp = solv->problems.elements + solution;
3587       return pp[0] || pp[1] ? solution : 0;
3588     }
3589   pp = solv->problems.elements + solution;
3590   while (pp[0] || pp[1])
3591     pp += 2;
3592   pp += 2;
3593   solution = pp - solv->problems.elements;
3594   return pp[0] || pp[1] ? solution : 0;
3595 }
3596
3597
3598 /*-------------------------------------------------------------------
3599  * 
3600  * solution element iterator
3601  */
3602
3603 Id
3604 solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
3605 {
3606   Id *pp;
3607   element = element ? element + 2 : solution;
3608   pp = solv->problems.elements + element;
3609   if (!(pp[0] || pp[1]))
3610     return 0;
3611   *p = pp[0];
3612   *rp = pp[1];
3613   return element;
3614 }
3615
3616
3617 /*-------------------------------------------------------------------
3618  * 
3619  * Retrieve information about a problematic rule
3620  *
3621  * this is basically the reverse of addrpmrulesforsolvable
3622  */
3623
3624 SolverProbleminfo
3625 solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
3626 {
3627   Pool *pool = solv->pool;
3628   Repo *installed = solv->installed;
3629   Rule *r;
3630   Solvable *s;
3631   int dontfix = 0;
3632   Id p, d, w2, pp, req, *reqp, con, *conp, obs, *obsp, *dp;
3633
3634   assert(rid > 0);
3635   if (rid >= solv->jobrules && rid < solv->jobrules_end)
3636     {
3637
3638       r = solv->rules + rid;
3639       p = solv->ruletojob.elements[rid - solv->jobrules];
3640       *depp = job->elements[p + 1];
3641       *sourcep = p;
3642       *targetp = job->elements[p];
3643       d = r->d < 0 ? -r->d - 1 : r->d;
3644       if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (job->elements[p] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
3645         return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
3646       return SOLVER_PROBLEM_JOB_RULE;
3647     }
3648   if (rid >= solv->updaterules && rid < solv->updaterules_end)
3649     {
3650       *depp = 0;
3651       *sourcep = solv->installed->start + (rid - solv->updaterules);
3652       *targetp = 0;
3653       return SOLVER_PROBLEM_UPDATE_RULE;
3654     }
3655   assert(rid < solv->rpmrules_end);
3656   r = solv->rules + rid;
3657   assert(r->p < 0);
3658   d = r->d < 0 ? -r->d - 1 : r->d;
3659   if (d == 0 && r->w2 == 0)
3660     {
3661       /* a rpm rule assertion */
3662       s = pool->solvables - r->p;
3663       if (installed && !solv->fixsystem && s->repo == installed)
3664         dontfix = 1;
3665       assert(!dontfix); /* dontfix packages never have a neg assertion */
3666       *sourcep = -r->p;
3667       *targetp = 0;
3668       /* see why the package is not installable */
3669       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
3670         {
3671           *depp = 0;
3672           return SOLVER_PROBLEM_NOT_INSTALLABLE;
3673         }
3674       /* check requires */
3675       if (s->requires)
3676         {
3677           reqp = s->repo->idarraydata + s->requires;
3678           while ((req = *reqp++) != 0)
3679             {
3680               if (req == SOLVABLE_PREREQMARKER)
3681                 continue;
3682               dp = pool->whatprovidesdata + pool_whatprovides(pool, req);
3683               if (*dp == 0)
3684                 break;
3685             }
3686           if (req)
3687             {
3688               *depp = req;
3689               return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP;
3690             }
3691         }
3692       if (!solv->allowselfconflicts && s->conflicts)
3693         {
3694           conp = s->repo->idarraydata + s->conflicts;
3695           while ((con = *conp++) != 0)
3696             FOR_PROVIDES(p, pp, con)
3697               if (p == -r->p)
3698                 {
3699                   *depp = con;
3700                   return SOLVER_PROBLEM_SELF_CONFLICT;
3701                 }
3702         }
3703       /* should never happen */
3704       *depp = 0;
3705       return SOLVER_PROBLEM_RPM_RULE;
3706     }
3707   s = pool->solvables - r->p;
3708   if (installed && !solv->fixsystem && s->repo == installed)
3709     dontfix = 1;
3710   w2 = r->w2;
3711   if (d && pool->whatprovidesdata[d] < 0)
3712     {
3713       /* rule looks like -p|-c|x|x|x..., we only create this for patches with multiversion */
3714       /* reduce it to -p|-c case */
3715       w2 = pool->whatprovidesdata[d];
3716     }
3717   if (d == 0 && w2 < 0)
3718     {
3719       /* a package conflict */
3720       Solvable *s2 = pool->solvables - w2;
3721       int dontfix2 = 0;
3722
3723       if (installed && !solv->fixsystem && s2->repo == installed)
3724         dontfix2 = 1;
3725
3726       /* if both packages have the same name and at least one of them
3727        * is not installed, they conflict */
3728       if (s->name == s2->name && !(installed && s->repo == installed && s2->repo == installed))
3729         {
3730           /* also check noobsoletes map */
3731           if ((s->evr == s2->evr && s->arch == s2->arch) || !solv->noobsoletes.size
3732                 || ((!installed || s->repo != installed) && !MAPTST(&solv->noobsoletes, -r->p))
3733                 || ((!installed || s2->repo != installed) && !MAPTST(&solv->noobsoletes, -w2)))
3734             {
3735               *depp = 0;
3736               *sourcep = -r->p;
3737               *targetp = -w2;
3738               return SOLVER_PROBLEM_SAME_NAME;
3739             }
3740         }
3741
3742       /* check conflicts in both directions */
3743       if (s->conflicts)
3744         {
3745           conp = s->repo->idarraydata + s->conflicts;
3746           while ((con = *conp++) != 0)
3747             {
3748               FOR_PROVIDES(p, pp, con)
3749                 {
3750                   if (dontfix && pool->solvables[p].repo == installed)
3751                     continue;
3752                   if (p != -w2)
3753                     continue;
3754                   *depp = con;
3755                   *sourcep = -r->p;
3756                   *targetp = p;
3757                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
3758                 }
3759             }
3760         }
3761       if (s2->conflicts)
3762         {
3763           conp = s2->repo->idarraydata + s2->conflicts;
3764           while ((con = *conp++) != 0)
3765             {
3766               FOR_PROVIDES(p, pp, con)
3767                 {
3768                   if (dontfix2 && pool->solvables[p].repo == installed)
3769                     continue;
3770                   if (p != -r->p)
3771                     continue;
3772                   *depp = con;
3773                   *sourcep = -w2;
3774                   *targetp = p;
3775                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
3776                 }
3777             }
3778         }
3779       /* check obsoletes in both directions */
3780       if ((!installed || s->repo != installed) && s->obsoletes && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -r->p)))
3781         {
3782           obsp = s->repo->idarraydata + s->obsoletes;
3783           while ((obs = *obsp++) != 0)
3784             {
3785               FOR_PROVIDES(p, pp, obs)
3786                 {
3787                   if (p != -w2)
3788                     continue;
3789                   if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
3790                     continue;
3791                   *depp = obs;
3792                   *sourcep = -r->p;
3793                   *targetp = p;
3794                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3795                 }
3796             }
3797         }
3798       if ((!installed || s2->repo != installed) && s2->obsoletes && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -w2)))
3799         {
3800           obsp = s2->repo->idarraydata + s2->obsoletes;
3801           while ((obs = *obsp++) != 0)
3802             {
3803               FOR_PROVIDES(p, pp, obs)
3804                 {
3805                   if (p != -r->p)
3806                     continue;
3807                   if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
3808                     continue;
3809                   *depp = obs;
3810                   *sourcep = -w2;
3811                   *targetp = p;
3812                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3813                 }
3814             }
3815         }
3816       if (solv->implicitobsoleteusesprovides && (!installed || s->repo != installed) && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -r->p)))
3817         {
3818           FOR_PROVIDES(p, pp, s->name)
3819             {
3820               if (p != -w2)
3821                 continue;
3822               *depp = s->name;
3823               *sourcep = -r->p;
3824               *targetp = p;
3825               return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3826             }
3827         }
3828       if (solv->implicitobsoleteusesprovides && (!installed || s2->repo != installed) && !(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, -w2)))
3829         {
3830           FOR_PROVIDES(p, pp, s2->name)
3831             {
3832               if (p != -r->p)
3833                 continue;
3834               *depp = s2->name;
3835               *sourcep = -w2;
3836               *targetp = p;
3837               return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3838             }
3839         }
3840       /* all cases checked, can't happen */
3841       *depp = 0;
3842       *sourcep = -r->p;
3843       *targetp = 0;
3844       return SOLVER_PROBLEM_RPM_RULE;
3845     }
3846   /* simple requires */
3847   if (s->requires)
3848     {
3849       reqp = s->repo->idarraydata + s->requires;
3850       while ((req = *reqp++) != 0)
3851         {
3852           if (req == SOLVABLE_PREREQMARKER)
3853             continue;
3854           dp = pool->whatprovidesdata + pool_whatprovides(pool, req);
3855           if (d == 0)
3856             {
3857               if (*dp == r->w2 && dp[1] == 0)
3858                 break;
3859             }
3860           else if (dp - pool->whatprovidesdata == d)
3861             break;
3862         }
3863       if (req)
3864         {
3865           *depp = req;
3866           *sourcep = -r->p;
3867           *targetp = 0;
3868           return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE;
3869         }
3870     }
3871   /* all cases checked, can't happen */
3872   *depp = 0;
3873   *sourcep = -r->p;
3874   *targetp = 0;
3875   return SOLVER_PROBLEM_RPM_RULE;
3876 }
3877
3878
3879 /*-------------------------------------------------------------------
3880  * 
3881  * find problem rule
3882  */
3883
3884 static void
3885 findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
3886 {
3887   Id rid, d;
3888   Id lreqr, lconr, lsysr, ljobr;
3889   Rule *r;
3890   int reqassert = 0;
3891
3892   lreqr = lconr = lsysr = ljobr = 0;
3893   while ((rid = solv->learnt_pool.elements[idx++]) != 0)
3894     {
3895       assert(rid > 0);
3896       if (rid >= solv->learntrules)
3897         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
3898       else if (rid >= solv->jobrules && rid < solv->jobrules_end)
3899         {
3900           if (!*jobrp)
3901             *jobrp = rid;
3902         }
3903       else if (rid >= solv->updaterules && rid < solv->updaterules_end)
3904         {
3905           if (!*sysrp)
3906             *sysrp = rid;
3907         }
3908       else
3909         {
3910           assert(rid < solv->rpmrules_end);
3911           r = solv->rules + rid;
3912           d = r->d < 0 ? -r->d - 1 : r->d;
3913           if (!d && r->w2 < 0)
3914             {
3915               if (!*conrp)
3916                 *conrp = rid;
3917             }
3918           else
3919             {
3920               if (!d && r->w2 == 0 && !reqassert)
3921                 {
3922                   if (*reqrp > 0 && r->p < -1)
3923                     {
3924                       Id op = -solv->rules[*reqrp].p;
3925                       if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
3926                         continue;       /* different arch, skip */
3927                     }
3928                   /* prefer assertions */
3929                   *reqrp = rid;
3930                   reqassert = 1;
3931                 }
3932               if (!*reqrp)
3933                 *reqrp = rid;
3934               else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && !reqassert)
3935                 {
3936                   /* prefer rules of installed packages */
3937                   *reqrp = rid;
3938                 }
3939             }
3940         }
3941     }
3942   if (!*reqrp && lreqr)
3943     *reqrp = lreqr;
3944   if (!*conrp && lconr)
3945     *conrp = lconr;
3946   if (!*jobrp && ljobr)
3947     *jobrp = ljobr;
3948   if (!*sysrp && lsysr)
3949     *sysrp = lsysr;
3950 }
3951
3952
3953 /*-------------------------------------------------------------------
3954  * 
3955  * find problem rule
3956  *
3957  * search for a rule that describes the problem to the
3958  * user. A pretty hopeless task, actually. We currently
3959  * prefer simple requires.
3960  */
3961
3962 Id
3963 solver_findproblemrule(Solver *solv, Id problem)
3964 {
3965   Id reqr, conr, sysr, jobr;
3966   Id idx = solv->problems.elements[problem - 1];
3967   reqr = conr = sysr = jobr = 0;
3968   findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
3969   if (reqr)
3970     return reqr;
3971   if (conr)
3972     return conr;
3973   if (sysr)
3974     return sysr;
3975   if (jobr)
3976     return jobr;
3977   assert(0);
3978 }
3979
3980
3981 /*-------------------------------------------------------------------
3982  * 
3983  * create reverse obsoletes map for installed solvables
3984  *
3985  * for each installed solvable find which packages with *different* names
3986  * obsolete the solvable.
3987  * this index is used in policy_findupdatepackages if noupdateprovide is set.
3988  */
3989
3990 static void
3991 create_obsolete_index(Solver *solv)
3992 {
3993   Pool *pool = solv->pool;
3994   Solvable *s;
3995   Repo *installed = solv->installed;
3996   Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
3997   int i, n;
3998
3999   if (!installed || !installed->nsolvables)
4000     return;
4001   solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
4002   for (i = 1; i < pool->nsolvables; i++)
4003     {
4004       s = pool->solvables + i;
4005       if (!s->obsoletes)
4006         continue;
4007       if (!pool_installable(pool, s))
4008         continue;
4009       obsp = s->repo->idarraydata + s->obsoletes;
4010       while ((obs = *obsp++) != 0)
4011         {
4012           FOR_PROVIDES(p, pp, obs)
4013             {
4014               if (pool->solvables[p].repo != installed)
4015                 continue;
4016               if (pool->solvables[p].name == s->name)
4017                 continue;
4018               if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
4019                 continue;
4020               obsoletes[p - installed->start]++;
4021             }
4022         }
4023     }
4024   n = 0;
4025   for (i = 0; i < installed->nsolvables; i++)
4026     if (obsoletes[i])
4027       {
4028         n += obsoletes[i] + 1;
4029         obsoletes[i] = n;
4030       }
4031   solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
4032   POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
4033   for (i = pool->nsolvables - 1; i > 0; i--)
4034     {
4035       s = pool->solvables + i;
4036       if (!s->obsoletes)
4037         continue;
4038       if (!pool_installable(pool, s))
4039         continue;
4040       obsp = s->repo->idarraydata + s->obsoletes;
4041       while ((obs = *obsp++) != 0)
4042         {
4043           FOR_PROVIDES(p, pp, obs)
4044             {
4045               if (pool->solvables[p].repo != installed)
4046                 continue;
4047               if (pool->solvables[p].name == s->name)
4048                 continue;
4049               if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
4050                 continue;
4051               p -= installed->start;
4052               if (obsoletes_data[obsoletes[p]] != i)
4053                 obsoletes_data[--obsoletes[p]] = i;
4054             }
4055         }
4056     }
4057 }
4058
4059
4060 /*-------------------------------------------------------------------
4061  * 
4062  * remove disabled conflicts
4063  */
4064
4065 static void
4066 removedisabledconflicts(Solver *solv, Queue *removed)
4067 {
4068   Pool *pool = solv->pool;
4069   int i, n;
4070   Id p, why, *dp;
4071   Id new;
4072   Rule *r;
4073   Id *decisionmap = solv->decisionmap;
4074
4075   POOL_DEBUG(SAT_DEBUG_SCHUBI, "removedisabledconflicts\n");
4076   queue_empty(removed);
4077   for (i = 0; i < solv->decisionq.count; i++)
4078     {
4079       p = solv->decisionq.elements[i];
4080       if (p > 0)
4081         continue;
4082       /* a conflict. we never do conflicts on free decisions, so there
4083        * must have been an unit rule */
4084       why = solv->decisionq_why.elements[i];
4085       assert(why > 0);
4086       r = solv->rules + why;
4087       if (r->d < 0 && decisionmap[-p])
4088         {
4089           /* rule is now disabled, remove from decisionmap */
4090           POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p);
4091           queue_push(removed, -p);
4092           queue_push(removed, decisionmap[-p]);
4093           decisionmap[-p] = 0;
4094         }
4095     }
4096   if (!removed->count)
4097     return;
4098   /* we removed some confliced packages. some of them might still
4099    * be in conflict, so search for unit rules and re-conflict */
4100   new = 0;
4101   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
4102     {
4103       if (i == solv->nrules)
4104         {
4105           i = 1;
4106           r = solv->rules + i;
4107         }
4108       if (r->d < 0)
4109         continue;
4110       if (!r->w2)
4111         {
4112           if (r->p < 0 && !decisionmap[-r->p])
4113             new = r->p;
4114         }
4115       else if (!r->d)
4116         {
4117           /* binary rule */
4118           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
4119             new = r->p;
4120           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
4121             new = r->w2;
4122         }
4123       else
4124         {
4125           if (r->p < 0 && decisionmap[-r->p] == 0)
4126             new = r->p;
4127           if (new || DECISIONMAP_FALSE(r->p))
4128             {
4129               dp = pool->whatprovidesdata + r->d;
4130               while ((p = *dp++) != 0)
4131                 {
4132                   if (new && p == new)
4133                     continue;
4134                   if (p < 0 && decisionmap[-p] == 0)
4135                     {
4136                       if (new)
4137                         {
4138                           new = 0;
4139                           break;
4140                         }
4141                       new = p;
4142                     }
4143                   else if (!DECISIONMAP_FALSE(p))
4144                     {
4145                       new = 0;
4146                       break;
4147                     }
4148                 }
4149             }
4150         }
4151       if (new)
4152         {
4153           POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new);
4154           decisionmap[-new] = -1;
4155           new = 0;
4156           n = 0;        /* redo all rules */
4157         }
4158     }
4159 }
4160
4161
4162 /*-------------------------------------------------------------------
4163  *
4164  * weaken solvable dependencies
4165  */
4166
4167 static void
4168 weaken_solvable_deps(Solver *solv, Id p)
4169 {
4170   int i;
4171   Rule *r;
4172
4173   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
4174     {
4175       if (r->p != -p)
4176         continue;
4177       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
4178         continue;       /* conflict */
4179       queue_push(&solv->weakruleq, i);
4180     }
4181 }
4182
4183 /********************************************************************/
4184 /* main() */
4185
4186 /*
4187  *
4188  * solve job queue
4189  *
4190  */
4191
4192 void
4193 solver_solve(Solver *solv, Queue *job)
4194 {
4195   Pool *pool = solv->pool;
4196   Repo *installed = solv->installed;
4197   int i;
4198   int oldnrules;
4199   Map addedmap;                /* '1' == have rpm-rules for solvable */
4200   Map installcandidatemap;
4201   Id how, what, select, name, weak, p, pp, d;
4202   Queue q, redoq;
4203   Solvable *s;
4204   int goterase;
4205   Rule *r;
4206   int now, solve_start;
4207
4208   solve_start = sat_timems(0);
4209   POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n");
4210   POOL_DEBUG(SAT_DEBUG_STATS, "fixsystem=%d updatesystem=%d dosplitprovides=%d, noupdateprovide=%d\n", solv->fixsystem, solv->updatesystem, solv->dosplitprovides, solv->noupdateprovide);
4211   POOL_DEBUG(SAT_DEBUG_STATS, "distupgrade=%d distupgrade_removeunsupported=%d\n", solv->distupgrade, solv->distupgrade_removeunsupported);
4212   POOL_DEBUG(SAT_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allowarchchange, solv->allowvendorchange);
4213   POOL_DEBUG(SAT_DEBUG_STATS, "promoteepoch=%d, allowvirtualconflicts=%d, allowselfconflicts=%d\n", pool->promoteepoch, solv->allowvirtualconflicts, solv->allowselfconflicts);
4214   POOL_DEBUG(SAT_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d\n", solv->obsoleteusesprovides, solv->implicitobsoleteusesprovides);
4215   POOL_DEBUG(SAT_DEBUG_STATS, "dontinstallrecommended=%d, ignorealreadyrecommended=%d, dontshowinstalledrecommended=%d\n", solv->dontinstallrecommended, solv->ignorealreadyrecommended, solv->dontshowinstalledrecommended);
4216   /* create whatprovides if not already there */
4217   if (!pool->whatprovides)
4218     pool_createwhatprovides(pool);
4219
4220   /* create obsolete index */
4221   create_obsolete_index(solv);
4222
4223   /* remember job */
4224   solv->job = job;
4225
4226   /*
4227    * create basic rule set of all involved packages
4228    * use addedmap bitmap to make sure we don't create rules twice
4229    *
4230    */
4231
4232   /* create noobsolete map if needed */
4233   for (i = 0; i < job->count; i += 2)
4234     {
4235       how = job->elements[i] & ~SOLVER_WEAK;
4236       if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
4237         continue;
4238       what = job->elements[i + 1];
4239       select = how & SOLVER_SELECTMASK;
4240       if (!solv->noobsoletes.size)
4241         map_init(&solv->noobsoletes, pool->nsolvables);
4242       FOR_JOB_SELECT(p, pp, select, what)
4243         MAPSET(&solv->noobsoletes, p);
4244     }
4245
4246   map_init(&addedmap, pool->nsolvables);
4247   map_init(&installcandidatemap, pool->nsolvables);
4248   queue_init(&q);
4249
4250   /*
4251    * always install our system solvable
4252    */
4253   MAPSET(&addedmap, SYSTEMSOLVABLE);
4254   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
4255   queue_push(&solv->decisionq_why, 0);
4256   solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */
4257
4258   now = sat_timems(0);
4259   /*
4260    * create rules for all package that could be involved with the solving
4261    * so called: rpm rules
4262    *
4263    */
4264   if (installed)
4265     {
4266       oldnrules = solv->nrules;
4267       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
4268       FOR_REPO_SOLVABLES(installed, p, s)
4269         addrpmrulesforsolvable(solv, s, &addedmap);
4270       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
4271       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
4272       oldnrules = solv->nrules;
4273       FOR_REPO_SOLVABLES(installed, p, s)
4274         addrpmrulesforupdaters(solv, s, &addedmap, 1);
4275       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
4276     }
4277
4278   /*
4279    * create rules for all packages involved in the job
4280    * (to be installed or removed)
4281    */
4282     
4283   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for packages involved with a job ***\n");
4284   oldnrules = solv->nrules;
4285   for (i = 0; i < job->count; i += 2)
4286     {
4287       how = job->elements[i];
4288       what = job->elements[i + 1];
4289       select = how & SOLVER_SELECTMASK;
4290
4291       switch (how & SOLVER_JOBMASK)
4292         {
4293         case SOLVER_INSTALL:
4294           FOR_JOB_SELECT(p, pp, select, what)
4295             {
4296               MAPSET(&installcandidatemap, p);
4297               addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
4298             }
4299           break;
4300         case SOLVER_UPDATE:
4301           /* FIXME: semantics? */
4302           FOR_JOB_SELECT(p, pp, select, what)
4303             addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
4304           break;
4305         }
4306     }
4307   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
4308
4309   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
4310
4311   oldnrules = solv->nrules;
4312     
4313     /*
4314      * add rules for suggests, enhances
4315      */
4316   addrpmrulesforweak(solv, &addedmap);
4317   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
4318
4319   IF_POOLDEBUG (SAT_DEBUG_STATS)
4320     {
4321       int possible = 0, installable = 0;
4322       for (i = 1; i < pool->nsolvables; i++)
4323         {
4324           if (pool_installable(pool, pool->solvables + i))
4325             installable++;
4326           if (MAPTST(&addedmap, i))
4327             possible++;
4328         }
4329       POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
4330     }
4331
4332   /*
4333    * first pass done, we now have all the rpm rules we need.
4334    * unify existing rules before going over all job rules and
4335    * policy rules.
4336    * at this point the system is always solvable,
4337    * as an empty system (remove all packages) is a valid solution
4338    */
4339
4340   unifyrules(solv);                               /* remove duplicate rpm rules */
4341
4342   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
4343
4344   solv->directdecisions = solv->decisionq.count;
4345   POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule memory usage: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
4346   POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
4347   POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule creation took %d ms\n", sat_timems(now));
4348
4349   /*
4350    * create feature rules
4351    * 
4352    * foreach installed:
4353    *   create assertion (keep installed, if no update available)
4354    *   or
4355    *   create update rule (A|update1(A)|update2(A)|...)
4356    * 
4357    * those are used later on to keep a version of the installed packages in
4358    * best effort mode
4359    */
4360     
4361   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add feature rules ***\n");
4362   solv->featurerules = solv->nrules;              /* mark start of feature rules */
4363   if (installed)
4364     {
4365         /* foreach possibly installed solvable */
4366       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
4367         {
4368           if (s->repo != installed)
4369             {
4370               addrule(solv, 0, 0);      /* create dummy rule */
4371               continue;
4372             }
4373           addupdaterule(solv, s, 1);    /* allow s to be updated */
4374         }
4375         /*
4376          * assert one rule per installed solvable,
4377          * either an assertion (A)
4378          * or a possible update (A|update1(A)|update2(A)|...)
4379          */
4380       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
4381     }
4382   solv->featurerules_end = solv->nrules;
4383
4384     /*
4385      * Add update rules for installed solvables
4386      * 
4387      * almost identical to feature rules
4388      * except that downgrades/archchanges/vendorchanges are not allowed
4389      */
4390     
4391   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add update rules ***\n");
4392   solv->updaterules = solv->nrules;
4393
4394   if (installed)
4395     { /* foreach installed solvables */
4396       /* we create all update rules, but disable some later on depending on the job */
4397       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
4398         {
4399           Rule *sr;
4400
4401           if (s->repo != installed)
4402             {
4403               addrule(solv, 0, 0);      /* create dummy rule */
4404               continue;
4405             }
4406           addupdaterule(solv, s, 0);    /* allowall = 0: downgrades not allowed */
4407             /*
4408              * check for and remove duplicate
4409              */
4410           r = solv->rules + solv->nrules - 1;           /* r: update rule */
4411           sr = r - (installed->end - installed->start); /* sr: feature rule */
4412           /* it's orphaned if there is no feature rule or the feature rule
4413            * consists just of the installed package */
4414           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
4415             queue_push(&solv->orphaned, i);
4416           if (!r->p)
4417             {
4418               assert(solv->distupgrade && !sr->p);
4419               continue;
4420             }
4421           unifyrules_sortcmp_data = pool;
4422           if (!unifyrules_sortcmp(r, sr))
4423             {
4424               /* identical rule, kill unneeded rule */
4425               if (solv->allowuninstall)
4426                 {
4427                   /* keep feature rule, make it weak */
4428                   memset(r, 0, sizeof(*r));
4429                   queue_push(&solv->weakruleq, sr - solv->rules);
4430                 }
4431               else
4432                 {
4433                   /* keep update rule */
4434                   memset(sr, 0, sizeof(*sr));
4435                 }
4436             }
4437           else if (solv->allowuninstall)
4438             {
4439               /* make both feature and update rule weak */
4440               queue_push(&solv->weakruleq, r - solv->rules);
4441               queue_push(&solv->weakruleq, sr - solv->rules);
4442             }
4443           else
4444             disablerule(solv, sr);
4445         }
4446       /* consistency check: we added a rule for _every_ installed solvable */
4447       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
4448     }
4449   solv->updaterules_end = solv->nrules;
4450
4451
4452   /*
4453    * now add all job rules
4454    */
4455
4456   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add JOB rules ***\n");
4457
4458   solv->jobrules = solv->nrules;
4459   for (i = 0; i < job->count; i += 2)
4460     {
4461       oldnrules = solv->nrules;
4462
4463       how = job->elements[i];
4464       what = job->elements[i + 1];
4465       weak = how & SOLVER_WEAK;
4466       select = how & SOLVER_SELECTMASK;
4467       switch (how & SOLVER_JOBMASK)
4468         {
4469         case SOLVER_INSTALL:
4470           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4471           if (select == SOLVER_SOLVABLE)
4472             {
4473               p = what;
4474               d = 0;
4475             }
4476           else
4477             {
4478               queue_empty(&q);
4479               FOR_JOB_SELECT(p, pp, select, what)
4480                 queue_push(&q, p);
4481               if (!q.count)
4482                 {
4483                   /* no candidate found, make this an impossible rule */
4484                   queue_push(&q, -SYSTEMSOLVABLE);
4485                 }
4486               p = queue_shift(&q);      /* get first candidate */
4487               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
4488             }
4489           addrule(solv, p, d);          /* add install rule */
4490           queue_push(&solv->ruletojob, i);
4491           if (weak)
4492             queue_push(&solv->weakruleq, solv->nrules - 1);
4493           break;
4494         case SOLVER_ERASE:
4495           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4496           if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
4497             {
4498               /* special case for "erase a specific solvable": we also
4499                * erase all other solvables with that name, so that they
4500                * don't get picked up as replacement */
4501               name = pool->solvables[what].name;
4502               FOR_PROVIDES(p, pp, name)
4503                 {
4504                   if (p == what)
4505                     continue;
4506                   s = pool->solvables + p;
4507                   if (s->name != name)
4508                     continue;
4509                   /* keep other versions installed */
4510                   if (s->repo == solv->installed)
4511                     continue;
4512                   /* keep installcandidates of other jobs */
4513                   if (MAPTST(&installcandidatemap, p))
4514                     continue;
4515                   addrule(solv, -p, 0);                 /* remove by Id */
4516                   queue_push(&solv->ruletojob, i);
4517                   if (weak)
4518                     queue_push(&solv->weakruleq, solv->nrules - 1);
4519                 }
4520             }
4521           FOR_JOB_SELECT(p, pp, select, what)
4522             {
4523               addrule(solv, -p, 0);
4524               queue_push(&solv->ruletojob, i);
4525               if (weak)
4526                 queue_push(&solv->weakruleq, solv->nrules - 1);
4527             }
4528           break;
4529
4530         case SOLVER_UPDATE:
4531           POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4532           if (select != SOLVER_SOLVABLE)
4533             break;
4534           s = pool->solvables + what;
4535           POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solvable2str(pool, s));
4536           addupdaterule(solv, s, 0);
4537           queue_push(&solv->ruletojob, i);
4538           if (weak)
4539             queue_push(&solv->weakruleq, solv->nrules - 1);
4540           break;
4541         case SOLVER_WEAKENDEPS:
4542           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4543           if (select != SOLVER_SOLVABLE)
4544             break;
4545           s = pool->solvables + what;
4546           weaken_solvable_deps(solv, what);
4547           break;
4548         case SOLVER_NOOBSOLETES:
4549           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4550           break;
4551         case SOLVER_LOCK:
4552           POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
4553           FOR_JOB_SELECT(p, pp, select, what)
4554             {
4555               s = pool->solvables + p;
4556               if (installed && s->repo == installed)
4557                 addrule(solv, p, 0);
4558               else
4559                 addrule(solv, -p, 0);
4560               queue_push(&solv->ruletojob, i);
4561               if (weak)
4562                 queue_push(&solv->weakruleq, solv->nrules - 1);
4563             }
4564           break;
4565         default:
4566           POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
4567           break;
4568         }
4569         
4570         /*
4571          * debug
4572          */
4573         
4574       IF_POOLDEBUG (SAT_DEBUG_JOB)
4575         {
4576           int j;
4577           if (solv->nrules == oldnrules)
4578             POOL_DEBUG(SAT_DEBUG_JOB, " - no rule created\n");
4579           for (j = oldnrules; j < solv->nrules; j++)
4580             {
4581               POOL_DEBUG(SAT_DEBUG_JOB, " - job ");
4582               solver_printrule(solv, SAT_DEBUG_JOB, solv->rules + j);
4583             }
4584         }
4585     }
4586   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
4587   solv->jobrules_end = solv->nrules;
4588
4589     /* all rules created
4590      * --------------------------------------------------------------
4591      * prepare for solving
4592      */
4593     
4594   /* free unneeded memory */
4595   map_free(&addedmap);
4596   map_free(&installcandidatemap);
4597   queue_free(&q);
4598
4599   /* create weak map */
4600   map_init(&solv->weakrulemap, solv->nrules);
4601   for (i = 0; i < solv->weakruleq.count; i++)
4602     {
4603       p = solv->weakruleq.elements[i];
4604       MAPSET(&solv->weakrulemap, p);
4605     }
4606
4607   /* all new rules are learnt after this point */
4608   solv->learntrules = solv->nrules;
4609
4610   /* create assertion index. it is only used to speed up
4611    * makeruledecsions() a bit */
4612   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
4613     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
4614       queue_push(&solv->ruleassertions, i);
4615
4616   /* disable update rules that conflict with our job */
4617   disableupdaterules(solv, job, -1);
4618
4619   /* make decisions based on job/update assertions */
4620   makeruledecisions(solv);
4621
4622   /* create watches chains */
4623   makewatches(solv);
4624
4625   POOL_DEBUG(SAT_DEBUG_STATS, "problems so far: %d\n", solv->problems.count);
4626
4627   /*
4628    * ********************************************
4629    * solve!
4630    * ********************************************
4631    */
4632     
4633   now = sat_timems(0);
4634   run_solver(solv, 1, solv->dontinstallrecommended ? 0 : 1);
4635   POOL_DEBUG(SAT_DEBUG_STATS, "solver took %d ms\n", sat_timems(now));
4636
4637   queue_init(&redoq);
4638   goterase = 0;
4639   /* disable all erase jobs (including weak "keep uninstalled" rules) */
4640   for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++)
4641     {
4642       if (r->d < 0)     /* disabled ? */
4643         continue;
4644       if (r->p > 0)     /* install job? */
4645         continue;
4646       disablerule(solv, r);
4647       goterase++;
4648     }
4649   
4650   if (goterase)
4651     {
4652       enabledisablelearntrules(solv);
4653       removedisabledconflicts(solv, &redoq);
4654     }
4655
4656   /*
4657    * find recommended packages
4658    */
4659     
4660   /* if redoq.count == 0 we already found all recommended in the
4661    * solver run */
4662   if (redoq.count || solv->dontinstallrecommended || !solv->dontshowinstalledrecommended || solv->ignorealreadyrecommended)
4663     {
4664       Id rec, *recp, p, pp;
4665
4666       /* create map of all recommened packages */
4667       solv->recommends_index = -1;
4668       MAPZERO(&solv->recommendsmap);
4669       for (i = 0; i < solv->decisionq.count; i++)
4670         {
4671           p = solv->decisionq.elements[i];
4672           if (p < 0)
4673             continue;
4674           s = pool->solvables + p;
4675           if (s->recommends)
4676             {
4677               recp = s->repo->idarraydata + s->recommends;
4678               while ((rec = *recp++) != 0)
4679                 {
4680                   FOR_PROVIDES(p, pp, rec)
4681                     if (solv->decisionmap[p] > 0)
4682                       break;
4683                   if (p)
4684                     {
4685                       if (!solv->dontshowinstalledrecommended)
4686                         {
4687                           FOR_PROVIDES(p, pp, rec)
4688                             if (solv->decisionmap[p] > 0)
4689                               MAPSET(&solv->recommendsmap, p);
4690                         }
4691                       continue; /* p != 0: already fulfilled */
4692                     }
4693                   FOR_PROVIDES(p, pp, rec)
4694                     MAPSET(&solv->recommendsmap, p);
4695                 }
4696             }
4697         }
4698       for (i = 1; i < pool->nsolvables; i++)
4699         {
4700           if (solv->decisionmap[i] < 0)
4701             continue;
4702           if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended)
4703             continue;
4704           s = pool->solvables + i;
4705           if (!MAPTST(&solv->recommendsmap, i))
4706             {
4707               if (!s->supplements)
4708                 continue;
4709               if (!pool_installable(pool, s))
4710                 continue;
4711               if (!solver_is_supplementing(solv, s))
4712                 continue;
4713             }
4714           if (solv->dontinstallrecommended)
4715             queue_push(&solv->recommendations, i);
4716           else
4717             queue_pushunique(&solv->recommendations, i);
4718         }
4719       /* we use MODE_SUGGEST here so that repo prio is ignored */
4720       policy_filter_unwanted(solv, &solv->recommendations, POLICY_MODE_SUGGEST);
4721     }
4722
4723   /*
4724    * find suggested packages
4725    */
4726     
4727   if (1)
4728     {
4729       Id sug, *sugp, p, pp;
4730
4731       /* create map of all suggests that are still open */
4732       solv->recommends_index = -1;
4733       MAPZERO(&solv->suggestsmap);
4734       for (i = 0; i < solv->decisionq.count; i++)
4735         {
4736           p = solv->decisionq.elements[i];
4737           if (p < 0)
4738             continue;
4739           s = pool->solvables + p;
4740           if (s->suggests)
4741             {
4742               sugp = s->repo->idarraydata + s->suggests;
4743               while ((sug = *sugp++) != 0)
4744                 {
4745                   FOR_PROVIDES(p, pp, sug)
4746                     if (solv->decisionmap[p] > 0)
4747                       break;
4748                   if (p)
4749                     {
4750                       if (!solv->dontshowinstalledrecommended)
4751                         {
4752                           FOR_PROVIDES(p, pp, sug)
4753                             if (solv->decisionmap[p] > 0)
4754                               MAPSET(&solv->suggestsmap, p);
4755                         }
4756                       continue; /* already fulfilled */
4757                     }
4758                   FOR_PROVIDES(p, pp, sug)
4759                     MAPSET(&solv->suggestsmap, p);
4760                 }
4761             }
4762         }
4763       for (i = 1; i < pool->nsolvables; i++)
4764         {
4765           if (solv->decisionmap[i] < 0)
4766             continue;
4767           if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended)
4768             continue;
4769           s = pool->solvables + i;
4770           if (!MAPTST(&solv->suggestsmap, i))
4771             {
4772               if (!s->enhances)
4773                 continue;
4774               if (!pool_installable(pool, s))
4775                 continue;
4776               if (!solver_is_enhancing(solv, s))
4777                 continue;
4778             }
4779           queue_push(&solv->suggestions, i);
4780         }
4781       policy_filter_unwanted(solv, &solv->suggestions, POLICY_MODE_SUGGEST);
4782     }
4783
4784   if (redoq.count)
4785     {
4786       /* restore decisionmap */
4787       for (i = 0; i < redoq.count; i += 2)
4788         solv->decisionmap[redoq.elements[i]] = redoq.elements[i + 1];
4789     }
4790
4791     /*
4792      * if unsolvable, prepare solutions
4793      */
4794
4795   if (solv->problems.count)
4796     {
4797       int recocount = solv->recommendations.count;
4798       solv->recommendations.count = 0;  /* so that revert() doesn't mess with it */
4799       queue_empty(&redoq);
4800       for (i = 0; i < solv->decisionq.count; i++)
4801         {
4802           Id p = solv->decisionq.elements[i];
4803           queue_push(&redoq, p);
4804           queue_push(&redoq, solv->decisionq_why.elements[i]);
4805           queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
4806         }
4807       problems_to_solutions(solv, job);
4808       memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
4809       queue_empty(&solv->decisionq);
4810       queue_empty(&solv->decisionq_why);
4811       for (i = 0; i < redoq.count; i += 3)
4812         {
4813           Id p = redoq.elements[i];
4814           queue_push(&solv->decisionq, p);
4815           queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
4816           solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
4817         }
4818       solv->recommendations.count = recocount;
4819     }
4820
4821   queue_free(&redoq);
4822   POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d learned rules, %d unsolvable\n", solv->stats_learned, solv->stats_unsolvable);
4823   POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start));
4824   solv->job = 0;
4825 }
4826
4827 /***********************************************************************/
4828 /* disk usage computations */
4829
4830 /*-------------------------------------------------------------------
4831  * 
4832  * calculate DU changes
4833  */
4834
4835 void
4836 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
4837 {
4838   Map installedmap;
4839
4840   solver_create_state_maps(solv, &installedmap, 0);
4841   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
4842   map_free(&installedmap);
4843 }
4844
4845
4846 /*-------------------------------------------------------------------
4847  * 
4848  * calculate changes in install size
4849  */
4850
4851 int
4852 solver_calc_installsizechange(Solver *solv)
4853 {
4854   Map installedmap;
4855   int change;
4856
4857   solver_create_state_maps(solv, &installedmap, 0);
4858   change = pool_calc_installsizechange(solv->pool, &installedmap);
4859   map_free(&installedmap);
4860   return change;
4861 }
4862
4863 #define FIND_INVOLVED_DEBUG 0
4864 void
4865 solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
4866 {
4867   Pool *pool = solv->pool;
4868   Map im;
4869   Map installedm;
4870   Solvable *s;
4871   Queue iq;
4872   Queue installedq_internal;
4873   Id tp, ip, p, pp, req, *reqp, sup, *supp;
4874   int i, count;
4875
4876   tp = ts - pool->solvables;
4877   queue_init(&iq);
4878   queue_init(&installedq_internal);
4879   map_init(&im, pool->nsolvables);
4880   map_init(&installedm, pool->nsolvables);
4881
4882   if (!installedq)
4883     {
4884       installedq = &installedq_internal;
4885       if (solv->installed)
4886         {
4887           for (ip = solv->installed->start; ip < solv->installed->end; ip++)
4888             {
4889               s = pool->solvables + ip;
4890               if (s->repo != solv->installed)
4891                 continue;
4892               queue_push(installedq, ip);
4893             }
4894         }
4895     }
4896   for (i = 0; i < installedq->count; i++)
4897     {
4898       ip = installedq->elements[i];
4899       MAPSET(&installedm, ip);
4900       MAPSET(&im, ip);
4901     }
4902
4903   queue_push(&iq, ts - pool->solvables);
4904   while (iq.count)
4905     {
4906       ip = queue_shift(&iq);
4907       if (!MAPTST(&im, ip))
4908         continue;
4909       if (!MAPTST(&installedm, ip))
4910         continue;
4911       MAPCLR(&im, ip);
4912       s = pool->solvables + ip;
4913 #if FIND_INVOLVED_DEBUG
4914       printf("hello %s\n", solvable2str(pool, s));
4915 #endif
4916       if (s->requires)
4917         {
4918           reqp = s->repo->idarraydata + s->requires;
4919           while ((req = *reqp++) != 0)
4920             {
4921               if (req == SOLVABLE_PREREQMARKER)
4922                 continue;
4923               /* count number of installed packages that match */
4924               count = 0;
4925               FOR_PROVIDES(p, pp, req)
4926                 if (MAPTST(&installedm, p))
4927                   count++;
4928               if (count > 1)
4929                 continue;
4930               FOR_PROVIDES(p, pp, req)
4931                 {
4932                   if (MAPTST(&im, p))
4933                     {
4934 #if FIND_INVOLVED_DEBUG
4935                       printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
4936 #endif
4937                       queue_push(&iq, p);
4938                     }
4939                 }
4940             }
4941         }
4942       if (s->recommends)
4943         {
4944           reqp = s->repo->idarraydata + s->recommends;
4945           while ((req = *reqp++) != 0)
4946             {
4947               count = 0;
4948               FOR_PROVIDES(p, pp, req)
4949                 if (MAPTST(&installedm, p))
4950                   count++;
4951               if (count > 1)
4952                 continue;
4953               FOR_PROVIDES(p, pp, req)
4954                 {
4955                   if (MAPTST(&im, p))
4956                     {
4957 #if FIND_INVOLVED_DEBUG
4958                       printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
4959 #endif
4960                       queue_push(&iq, p);
4961                     }
4962                 }
4963             }
4964         }
4965       if (!iq.count)
4966         {
4967           /* supplements pass */
4968           for (i = 0; i < installedq->count; i++)
4969             {
4970               ip = installedq->elements[i];
4971               s = pool->solvables + ip;
4972               if (!s->supplements)
4973                 continue;
4974               if (!MAPTST(&im, ip))
4975                 continue;
4976               supp = s->repo->idarraydata + s->supplements;
4977               while ((sup = *supp++) != 0)
4978                 if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
4979                   break;
4980               /* no longer supplemented, also erase */
4981               if (sup)
4982                 {
4983 #if FIND_INVOLVED_DEBUG
4984                   printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
4985 #endif
4986                   queue_push(&iq, ip);
4987                 }
4988             }
4989         }
4990     }
4991
4992   for (i = 0; i < installedq->count; i++)
4993     {
4994       ip = installedq->elements[i];
4995       if (MAPTST(&im, ip))
4996         queue_push(&iq, ip);
4997     }
4998
4999   while (iq.count)
5000     {
5001       ip = queue_shift(&iq);
5002       if (!MAPTST(&installedm, ip))
5003         continue;
5004       s = pool->solvables + ip;
5005 #if FIND_INVOLVED_DEBUG
5006       printf("bye %s\n", solvable2str(pool, s));
5007 #endif
5008       if (s->requires)
5009         {
5010           reqp = s->repo->idarraydata + s->requires;
5011           while ((req = *reqp++) != 0)
5012             {
5013               FOR_PROVIDES(p, pp, req)
5014                 {
5015                   if (!MAPTST(&im, p))
5016                     {
5017                       if (p == tp)
5018                         continue;
5019 #if FIND_INVOLVED_DEBUG
5020                       printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
5021 #endif
5022                       MAPSET(&im, p);
5023                       queue_push(&iq, p);
5024                     }
5025                 }
5026             }
5027         }
5028       if (s->recommends)
5029         {
5030           reqp = s->repo->idarraydata + s->recommends;
5031           while ((req = *reqp++) != 0)
5032             {
5033               FOR_PROVIDES(p, pp, req)
5034                 {
5035                   if (!MAPTST(&im, p))
5036                     {
5037                       if (p == tp)
5038                         continue;
5039 #if FIND_INVOLVED_DEBUG
5040                       printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
5041 #endif
5042                       MAPSET(&im, p);
5043                       queue_push(&iq, p);
5044                     }
5045                 }
5046             }
5047         }
5048       if (!iq.count)
5049         {
5050           /* supplements pass */
5051           for (i = 0; i < installedq->count; i++)
5052             {
5053               ip = installedq->elements[i];
5054               if (ip == tp)
5055                 continue;
5056               s = pool->solvables + ip;
5057               if (!s->supplements)
5058                 continue;
5059               if (MAPTST(&im, ip))
5060                 continue;
5061               supp = s->repo->idarraydata + s->supplements;
5062               while ((sup = *supp++) != 0)
5063                 if (dep_possible(solv, sup, &im))
5064                   break;
5065               if (sup)
5066                 {
5067 #if FIND_INVOLVED_DEBUG
5068                   printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
5069 #endif
5070                   MAPSET(&im, ip);
5071                   queue_push(&iq, ip);
5072                 }
5073             }
5074         }
5075     }
5076     
5077   queue_free(&iq);
5078
5079   /* convert map into result */
5080   for (i = 0; i < installedq->count; i++)
5081     {
5082       ip = installedq->elements[i];
5083       if (MAPTST(&im, ip))
5084         continue;
5085       if (ip == ts - pool->solvables)
5086         continue;
5087       queue_push(q, ip);
5088     }
5089   map_free(&im);
5090   map_free(&installedm);
5091   queue_free(&installedq_internal);
5092 }
5093
5094 /* EOF */