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