- rename xmalloc/... functions to sat_malloc, as we're a
[platform/upstream/libsolv.git] / src / solver.c
1 /*
2  * Copyright (c) 2007, 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
27 #define RULES_BLOCK 63
28 #define REGARD_RECOMMENDS_OF_INSTALLED_ITEMS 0
29
30
31 int
32 solver_dep_installed(Solver *solv, Id dep)
33 {
34   /* disable for now, splitprovides don't work anyway and it breaks
35      a testcase */
36 #if 0
37   Pool *pool = solv->pool;
38   Id p, *pp;
39
40   if (ISRELDEP(dep))
41     {
42       Reldep *rd = GETRELDEP(pool, dep);
43       if (rd->flags == REL_AND)
44         {
45           if (!solver_dep_installed(solv, rd->name))
46             return 0;
47           return solver_dep_installed(solv, rd->evr);
48         }
49       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
50         return solver_dep_installed(solv, rd->evr);
51     }
52   FOR_PROVIDES(p, pp, dep)
53     {
54       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
55         return 1;
56     }
57 #endif
58   return 0;
59 }
60
61
62 /* this mirrors solver_dep_fulfilled but uses map m instead of the decisionmap */
63 static inline int
64 dep_possible(Solver *solv, Id dep, Map *m)
65 {
66   Pool *pool = solv->pool;
67   Id p, *pp;
68
69   if (ISRELDEP(dep))
70     {
71       Reldep *rd = GETRELDEP(pool, dep);
72       if (rd->flags == REL_AND)
73         {
74           if (!dep_possible(solv, rd->name, m))
75             return 0;
76           return dep_possible(solv, rd->evr, m);
77         }
78       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
79         return solver_dep_installed(solv, rd->evr);
80     }
81   FOR_PROVIDES(p, pp, dep)
82     {
83       if (MAPTST(m, p))
84         return 1;
85     }
86   return 0;
87 }
88
89 /*-----------------------------------------------------------------*/
90
91 /*
92  * print rules
93  */
94
95 static void
96 printruleelement(Solver *solv, int type, Rule *r, Id v)
97 {
98   Pool *pool = solv->pool;
99   Solvable *s;
100   if (v < 0)
101     {
102       s = pool->solvables + -v;
103       POOL_DEBUG(type, "    !%s [%d]", solvable2str(pool, s), -v);
104     }
105   else
106     {
107       s = pool->solvables + v;
108       POOL_DEBUG(type, "    %s [%d]", solvable2str(pool, s), v);
109     }
110   if (r)
111     {
112       if (r->w1 == v)
113         POOL_DEBUG(type, " (w1)");
114       if (r->w2 == v)
115         POOL_DEBUG(type, " (w2)");
116     }
117   if (solv->decisionmap[s - pool->solvables] > 0)
118     POOL_DEBUG(type, " Install.level%d", solv->decisionmap[s - pool->solvables]);
119   if (solv->decisionmap[s - pool->solvables] < 0)
120     POOL_DEBUG(type, " Conflict.level%d", -solv->decisionmap[s - pool->solvables]);
121   POOL_DEBUG(type, "\n");
122 }
123
124
125 /*
126  * print rule
127  */
128
129 static void
130 printrule(Solver *solv, int type, Rule *r)
131 {
132   Pool *pool = solv->pool;
133   int i;
134   Id v;
135
136   if (r >= solv->rules && r < solv->rules + solv->nrules)   /* r is a solver rule */
137     POOL_DEBUG(type, "Rule #%d:", (int)(r - solv->rules));
138   else
139     POOL_DEBUG(type, "Rule:");                 /* r is any rule */
140   if (r && r->w1 == 0)
141     POOL_DEBUG(type, " (disabled)");
142   POOL_DEBUG(type, "\n");
143   for (i = 0; ; i++)
144     {
145       if (i == 0)
146           /* print direct literal */ 
147         v = r->p;
148       else if (r->d == ID_NULL)
149         {
150           if (i == 2)
151             break;
152           /* binary rule --> print w2 as second literal */
153           v = r->w2;
154         }
155       else
156           /* every other which is in d */
157         v = solv->pool->whatprovidesdata[r->d + i - 1];
158       if (v == ID_NULL)
159         break;
160       printruleelement(solv, type, r, v);
161     }
162   POOL_DEBUG(type, "    next rules: %d %d\n", r->n1, r->n2);
163 }
164
165 static void
166 printruleclass(Solver *solv, int type, Rule *r)
167 {
168   Pool *pool = solv->pool;
169   if (r - solv->rules >= solv->learntrules)
170     POOL_DEBUG(type, "LEARNT ");
171   else if (r - solv->rules >= solv->weakrules)
172     POOL_DEBUG(type, "WEAK ");
173   else if (r - solv->rules >= solv->systemrules)
174     POOL_DEBUG(type, "SYSTEM ");
175   else if (r - solv->rules >= solv->jobrules)
176     POOL_DEBUG(type, "JOB ");
177   printrule(solv, type, r);
178 }
179
180
181 /*-----------------------------------------------------------------*/
182
183 /*
184  * Rule handling
185  */
186
187 static Pool *unifyrules_sortcmp_data;
188
189 /*
190  * compare rules for unification sort
191  */
192
193 static int
194 unifyrules_sortcmp(const void *ap, const void *bp)
195 {
196   Pool *pool = unifyrules_sortcmp_data;
197   Rule *a = (Rule *)ap;
198   Rule *b = (Rule *)bp;
199   Id *ad, *bd;
200   int x;
201   
202   x = a->p - b->p;
203   if (x)
204     return x;                          /* p differs */
205
206   /* identical p */
207   if (a->d == 0 && b->d == 0)
208     return a->w2 - b->w2;              /* assertion: return w2 diff */
209
210   if (a->d == 0)                       /* a is assertion, b not */
211     {
212       x = a->w2 - pool->whatprovidesdata[b->d];
213       return x ? x : -1;
214     }
215
216   if (b->d == 0)                       /* b is assertion, a not */
217     {
218       x = pool->whatprovidesdata[a->d] - b->w2;
219       return x ? x : 1;
220     }
221
222   /* compare whatprovidesdata */
223   ad = pool->whatprovidesdata + a->d;
224   bd = pool->whatprovidesdata + b->d;
225   while (*bd)
226     if ((x = *ad++ - *bd++) != 0)
227       return x;
228   return *ad;
229 }
230
231
232 /*
233  * unify rules
234  */
235
236 static void
237 unifyrules(Solver *solv)
238 {
239   Pool *pool = solv->pool;
240   int i, j;
241   Rule *ir, *jr;
242
243   if (solv->nrules <= 1)               /* nothing to unify */
244     return;
245
246   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
247
248   /* sort rules first */
249   unifyrules_sortcmp_data = solv->pool;
250   qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
251
252   /* prune rules
253    * i = unpruned
254    * j = pruned
255    */
256   jr = 0;
257   for (i = j = 1, ir = solv->rules + 1; i < solv->nrules; i++, ir++)
258     {
259       if (jr && !unifyrules_sortcmp(ir, jr))
260         continue;                      /* prune! */
261       jr = solv->rules + j++;          /* keep! */
262       if (ir != jr)
263         *jr = *ir;
264     }
265
266   /* reduced count from nrules to j rules */
267   POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
268
269   /* adapt rule buffer */
270   solv->nrules = j;
271   solv->rules = (Rule *)sat_realloc(solv->rules, ((solv->nrules + RULES_BLOCK) & ~RULES_BLOCK) * sizeof(Rule));
272   IF_POOLDEBUG (SAT_DEBUG_STATS)
273     {
274       int binr = 0;
275       int lits = 0;
276       Id *dp;
277       Rule *r;
278
279       for (i = 1; i < solv->nrules; i++)
280         {
281           r = solv->rules + i;
282           if (r->d == 0)
283             binr++;
284           else
285             {
286               dp = solv->pool->whatprovidesdata + r->d;
287               while (*dp++)
288                 lits++;
289             }
290         }
291       POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
292       POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
293     }
294   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");  
295 }
296
297 #if 0
298
299 /*
300  * hash rule
301  */
302
303 static Hashval
304 hashrule(Solver *solv, Id p, Id d, int n)
305 {
306   unsigned int x = (unsigned int)p;
307   int *dp;
308
309   if (n <= 1)
310     return (x * 37) ^ (unsigned int)d; 
311   dp = solv->pool->whatprovidesdata + d;
312   while (*dp)
313     x = (x * 37) ^ (unsigned int)*dp++;
314   return x;
315 }
316 #endif
317
318
319 /*
320  * add rule
321  *  p = direct literal; always < 0 for installed rpm rules
322  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
323  *
324  *
325  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
326  * 
327  * p < 0 : pkg id of A
328  * d > 0 : Offset in whatprovidesdata (list of providers of b)
329  * 
330  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
331  * p < 0 : pkg id of A
332  * d < 0 : Id of solvable (e.g. B1)
333  * 
334  * d == 0: unary rule, assertion => (A) or (-A)
335  * 
336  *   Install:    p > 0, d = 0   (A)             user requested install
337  *   Remove:     p < 0, d = 0   (-A)            user requested remove
338  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
339  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
340  *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
341  *   ?           p > 0, d < 0   (A|-B)
342  *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
343  *
344  *   resulting watches:
345  *   ------------------
346  *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
347  *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
348  *   every other : w1 = p, w2 = whatprovidesdata[d];
349  *   Disabled rule: w1 = 0
350  *
351  *   always returns a rule for non-rpm rules
352  */
353
354 static Rule *
355 addrule(Solver *solv, Id p, Id d)
356 {
357   Pool *pool = solv->pool;
358   Rule *r = 0;
359   Id *dp = 0;
360
361   int n = 0;                           /* number of literals in rule - 1
362                                           0 = direct assertion (single literal)
363                                           1 = binary rule
364                                         */
365
366   /* it often happenes that requires lead to adding the same rpm rule
367    * multiple times, so we prune those duplicates right away to make
368    * the work for unifyrules a bit easier */
369
370   if (solv->nrules && !solv->jobrules)
371     {
372       r = solv->rules + solv->nrules - 1;   /* get the last added rule */
373       if (r->p == p && r->d == d && d != 0)   /* identical and not user requested */
374         return r;
375     }
376
377   if (d < 0)
378     {
379       /* always a binary rule */
380       if (p == d)
381         return 0;                      /* ignore self conflict */
382       n = 1;
383     }
384   else if (d > 0)
385     {
386       for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
387         if (*dp == -p)
388           return 0;                     /* rule is self-fulfilling */
389       if (n == 1)
390         d = dp[-1];                     /* take single literal */
391     }
392
393   if (n == 0 && !solv->jobrules)
394     {
395       /* this is a rpm rule assertion, we do not have to allocate it */
396       /* it can be identified by a level of 1 and a zero reason */
397       /* we must not drop those rules from the decisionq when rewinding! */
398       assert(p < 0);
399       assert(solv->decisionmap[-p] == 0 || solv->decisionmap[-p] == -1);
400       if (solv->decisionmap[-p])
401         return 0;       /* already got that one */
402       queue_push(&solv->decisionq, p);
403       queue_push(&solv->decisionq_why, 0);
404       solv->decisionmap[-p] = -1;
405       return 0;
406     }
407   if (n == 1 && p > d)
408     {
409       /* smallest literal first so we can find dups */
410       n = p;
411       p = d;
412       d = n;
413       n = 1;                           /* re-set n, was used as temp var */
414     }
415
416   /* check if the last added rule is exactly the same as what we're looking for. */
417   if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
418     return r;  /* binary rule */
419
420   if (r && n > 1 && r->d && r->p == p)
421     {
422       /* Rule where d is an offset in whatprovidesdata */
423       Id *dp2;
424       if (d == r->d)
425         return r;
426       dp2 = pool->whatprovidesdata + r->d;
427       for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
428         if (*dp != *dp2)
429           break;
430       if (*dp == *dp2)
431         return r;
432    }
433   
434   /*
435    * allocate new rule
436    */
437
438   /* check and extend rule buffer */
439   if ((solv->nrules & RULES_BLOCK) == 0)
440     {
441       solv->rules = (Rule *)sat_realloc(solv->rules, (solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
442     }
443
444   r = solv->rules + solv->nrules++;    /* point to rule space */
445
446   r->p = p;
447   if (n == 0)
448     {
449       /* direct assertion, no watch needed */
450       r->d = 0;
451       r->w1 = p;
452       r->w2 = 0;
453     }
454   else if (n == 1)
455     {
456       /* binary rule */
457       r->d = 0;
458       r->w1 = p;
459       r->w2 = d;
460     }
461   else
462     {
463       r->d = d;
464       r->w1 = p;
465       r->w2 = pool->whatprovidesdata[d];
466     }
467   r->n1 = 0;
468   r->n2 = 0;
469
470   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
471     {
472       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
473       printrule(solv, SAT_DEBUG_RULE_CREATION, r);
474     }
475   
476   return r;
477 }
478
479 static inline void
480 disablerule(Solver *solv, Rule *r)
481 {
482   r->w1 = 0;
483 }
484
485 static inline void
486 enablerule(Solver *solv, Rule *r)
487 {
488   if (r->d == 0 || r->w2 != r->p)
489     r->w1 = r->p;
490   else
491     r->w1 = solv->pool->whatprovidesdata[r->d];
492 }
493
494
495 /**********************************************************************************/
496
497 /* a problem is an item on the solver's problem list. It can either be >0, in that
498  * case it is a system (upgrade) rule, or it can be <0, which makes it refer to a job
499  * consisting of multiple job rules.
500  */
501
502 static void 
503 disableproblem(Solver *solv, Id v)
504 {
505   Rule *r;
506   int i;
507   Id *jp;
508
509   if (v > 0)
510     {
511       disablerule(solv, solv->rules + v);
512       return;
513     }
514   v = -(v + 1);
515   jp = solv->ruletojob.elements;
516   for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
517     if (*jp == v)
518       disablerule(solv, r);
519 }
520
521 static void 
522 enableproblem(Solver *solv, Id v)
523 {
524   Rule *r;
525   int i;
526   Id *jp;
527
528   if (v > 0)
529     {
530       enablerule(solv, solv->rules + v);
531       return;
532     }
533   v = -(v + 1);
534   jp = solv->ruletojob.elements;
535   for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
536     if (*jp == v)
537       enablerule(solv, r);
538 }
539
540 static void
541 printproblem(Solver *solv, Id v)
542 {
543   Pool *pool = solv->pool;
544   int i;
545   Rule *r;
546   Id *jp;
547
548   if (v > 0)
549     printrule(solv, SAT_DEBUG_SOLUTIONS, solv->rules + v);
550   else
551     {
552       v = -(v + 1);
553       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "JOB %d\n", v);
554       jp = solv->ruletojob.elements;
555       for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
556         if (*jp == v)
557           {
558             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "- ");
559             printrule(solv, SAT_DEBUG_SOLUTIONS, r);
560           }
561       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "ENDJOB\n");
562     }
563 }
564
565
566
567 /************************************************************************/
568
569 /* go through system and job rules and add direct assertions
570  * to the decisionqueue. If we find a conflict, disable rules and
571  * add them to problem queue.
572  * (disablerules is always true for the cases when we get called)
573  */
574 static void
575 makeruledecisions(Solver *solv)
576 {
577   Pool *pool = solv->pool;
578   int i, ri;
579   Rule *r, *rr;
580   Id v, vv;
581   int decisionstart;
582
583   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions ; size decisionq: %d -----\n",solv->decisionq.count);
584   
585   decisionstart = solv->decisionq.count;
586   /* rpm rules don't have assertions, so we can start with the job
587    * rules */
588   for (ri = solv->jobrules, r = solv->rules + ri; ri < solv->nrules; ri++, r++)
589     {
590       if (!r->w1 || r->w2)      /* disabled or no assertion */
591         continue;
592       v = r->p;
593       vv = v > 0 ? v : -v;
594       if (solv->decisionmap[vv] == 0)
595         {
596           queue_push(&solv->decisionq, v);
597           queue_push(&solv->decisionq_why, r - solv->rules);
598           solv->decisionmap[vv] = v > 0 ? 1 : -1;
599           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
600             {
601               Solvable *s = solv->pool->solvables + vv;
602               if (v < 0)
603                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", solvable2str(solv->pool, s));
604               else
605                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "installing  %s (assertion)\n", solvable2str(solv->pool, s));
606             }
607           continue;
608         }
609       if (v > 0 && solv->decisionmap[vv] > 0)
610         continue;
611       if (v < 0 && solv->decisionmap[vv] < 0)
612         continue;
613       /* found a conflict! */
614       /* ri >= learntrules cannot happen, as this would mean that the
615        * problem was not solvable, so we wouldn't have created the
616        * learnt rule at all */
617       assert(ri < solv->learntrules);
618       /* if we are weak, just disable ourself */
619       if (ri >= solv->weakrules)
620         {
621           POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
622           printrule(solv, SAT_DEBUG_UNSOLVABLE, r);
623           disablerule(solv, r);
624           continue;
625         }
626
627       /* only job and system rules left in the decisionq*/
628       /* find the decision which is the "opposite" of the jobrule */
629       for (i = 0; i < solv->decisionq.count; i++)
630         if (solv->decisionq.elements[i] == -v)
631           break;
632       assert(i < solv->decisionq.count);
633       if (solv->decisionq_why.elements[i] == 0)
634         {
635           /* conflict with rpm rule, need only disable our rule */
636           assert(v > 0 || v == -SYSTEMSOLVABLE);
637           /* record proof */
638           queue_push(&solv->problems, solv->learnt_pool.count);
639           queue_push(&solv->learnt_pool, ri);
640           queue_push(&solv->learnt_pool, v != -SYSTEMSOLVABLE ? -v : v);
641           queue_push(&solv->learnt_pool, 0);
642           POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
643           if (ri < solv->systemrules)
644             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
645           else
646             v = ri;
647           queue_push(&solv->problems, v);
648           disableproblem(solv, v);
649           queue_push(&solv->problems, 0);
650           continue;
651         }
652       /* record proof */
653       queue_push(&solv->problems, solv->learnt_pool.count);
654       queue_push(&solv->learnt_pool, ri);
655       queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
656       queue_push(&solv->learnt_pool, 0);
657
658       /* conflict with another job or system rule */
659       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflicting system/job assertions over literal %d\n", vv);
660       /* push all of our rules asserting this literal on the problem stack */
661       for (i = solv->jobrules, rr = solv->rules + i; i < solv->nrules; i++, rr++)
662         {
663           if (!rr->w1 || rr->w2)
664             continue;
665           if (rr->p != vv && rr->p != -vv)
666             continue;
667           POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
668           v = i;
669           if (i < solv->systemrules)
670             v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
671           queue_push(&solv->problems, v);
672           disableproblem(solv, v);
673         }
674       queue_push(&solv->problems, 0);
675
676       /* start over */
677       while (solv->decisionq.count > decisionstart)
678         {
679           v = solv->decisionq.elements[--solv->decisionq.count];
680           --solv->decisionq_why.count;
681           vv = v > 0 ? v : -v;
682           solv->decisionmap[vv] = 0;
683         }
684       ri = solv->jobrules - 1;
685       r = solv->rules + ri;
686     }
687   
688     POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions end; size decisionq: %d -----\n",solv->decisionq.count);
689 }
690
691 /*
692  * we have enabled or disabled some of our rules. We now reenable all
693  * of our learnt rules but the ones that were learnt from rules that
694  * are now disabled.
695  */
696 static void
697 enabledisablelearntrules(Solver *solv)
698 {
699   Pool *pool = solv->pool;
700   Rule *r;
701   Id why, *whyp;
702   int i;
703
704   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
705   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
706     {
707       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
708       while ((why = *whyp++) != 0)
709         {
710           if (why < 0)
711             continue;           /* rpm assertion */
712           assert(why < i);
713           if (!solv->rules[why].w1)
714             break;
715         }
716       /* why != 0: we found a disabled rule, disable the learnt rule */
717       if (why && r->w1)
718         {
719           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
720             {
721               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "disabling learnt ");
722               printrule(solv, SAT_DEBUG_SOLUTIONS, r);
723             }
724           disablerule(solv, r);
725         }
726       else if (!why && !r->w1)
727         {
728           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
729             {
730               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "re-enabling learnt ");
731               printrule(solv, SAT_DEBUG_SOLUTIONS, r);
732             }
733           enablerule(solv, r);
734         }
735     }
736 }
737
738
739 /* FIXME: bad code ahead, replace as soon as possible */
740 static void
741 disableupdaterules(Solver *solv, Queue *job, int jobidx)
742 {
743   Pool *pool = solv->pool;
744   int i, j;
745   Id how, what, p, *pp;
746   Solvable *s;
747   Repo *installed;
748   Rule *r;
749   Id lastjob = -1;
750
751   installed = solv->installed;
752   if (!installed)
753     return;
754
755   if (jobidx != -1)
756     {
757       how = job->elements[jobidx];
758       switch(how)
759         {
760         case SOLVER_INSTALL_SOLVABLE:
761         case SOLVER_ERASE_SOLVABLE:
762         case SOLVER_ERASE_SOLVABLE_NAME:
763         case SOLVER_ERASE_SOLVABLE_PROVIDES:
764           break;
765         default:
766           return;
767         }
768     }
769   /* go through all enabled job rules */
770   MAPZERO(&solv->noupdate);
771   for (i = solv->jobrules; i < solv->systemrules; i++)
772     {
773       r = solv->rules + i;
774       if (!r->w1)       /* disabled? */
775         continue;
776       j = solv->ruletojob.elements[i - solv->jobrules];
777       if (j == lastjob)
778         continue;
779       lastjob = j;
780       how = job->elements[j];
781       what = job->elements[j + 1];
782       switch(how)
783         {
784         case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
785           s = pool->solvables + what;
786           FOR_PROVIDES(p, pp, s->name)
787             {
788               if (pool->solvables[p].name != s->name)
789                 continue;
790               if (pool->solvables[p].repo == installed)
791                 MAPSET(&solv->noupdate, p - installed->start);
792             }
793           break;
794         case SOLVER_ERASE_SOLVABLE:
795           s = pool->solvables + what;
796           if (s->repo == installed)
797             MAPSET(&solv->noupdate, what - installed->start);
798           break;
799         case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
800         case SOLVER_ERASE_SOLVABLE_PROVIDES:
801           FOR_PROVIDES(p, pp, what)
802             {
803               if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
804                 continue;
805               if (pool->solvables[p].repo == installed)
806                 MAPSET(&solv->noupdate, p - installed->start);
807             }
808           break;
809         default:
810           break;
811         }
812     }
813
814   /* fixup update rule status */
815   if (solv->allowuninstall)
816     return;             /* no update rules at all */
817
818   if (jobidx != -1)
819     {
820       /* we just disabled job #jobidx. enable all update rules
821        * that aren't disabled by the remaining job rules */
822       how = job->elements[jobidx];
823       what = job->elements[jobidx + 1];
824       switch(how)
825         {
826         case SOLVER_INSTALL_SOLVABLE:
827           s = pool->solvables + what;
828           FOR_PROVIDES(p, pp, s->name)
829             {
830               if (pool->solvables[p].name != s->name)
831                 continue;
832               if (pool->solvables[p].repo != installed)
833                 continue;
834               if (MAPTST(&solv->noupdate, p - installed->start))
835                 continue;
836               r = solv->rules + solv->systemrules + (p - installed->start);
837               if (r->w1)
838                 continue;
839               enablerule(solv, r);
840               IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
841                 {
842                   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
843                   printrule(solv, SAT_DEBUG_SOLUTIONS, r);
844                 }
845             }
846           break;
847         case SOLVER_ERASE_SOLVABLE:
848           s = pool->solvables + what;
849           if (s->repo != installed)
850             break;
851           if (MAPTST(&solv->noupdate, what - installed->start))
852             break;
853           r = solv->rules + solv->systemrules + (what - installed->start);
854           if (r->w1)
855             break;
856           enablerule(solv, r);
857           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
858             {
859               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
860               printrule(solv, SAT_DEBUG_SOLUTIONS, r);
861             }
862           break;
863         case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
864         case SOLVER_ERASE_SOLVABLE_PROVIDES:
865           FOR_PROVIDES(p, pp, what)
866             {
867               if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
868                 continue;
869               if (pool->solvables[p].repo != installed)
870                 continue;
871               if (MAPTST(&solv->noupdate, p - installed->start))
872                 continue;
873               r = solv->rules + solv->systemrules + (p - installed->start);
874               if (r->w1)
875                 continue;
876               enablerule(solv, r);
877               IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
878                 {
879                   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
880                   printrule(solv, SAT_DEBUG_SOLUTIONS, r);
881                 }
882             }
883           break;
884         default:
885           break;
886         }
887       return;
888     }
889
890   for (i = 0; i < installed->nsolvables; i++)
891     {
892       r = solv->rules + solv->systemrules + i;
893       if (r->w1 && MAPTST(&solv->noupdate, i))
894         disablerule(solv, r);   /* was enabled, need to disable */
895     }
896 }
897
898
899 /*
900  * add (install) rules for solvable
901  * for unfulfilled requirements, conflicts, obsoletes,....
902  * add a negative assertion for solvables that are not installable
903  */
904
905 static void
906 addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
907 {
908   Pool *pool = solv->pool;
909   Repo *installed = solv->installed;
910   Queue q;
911   Id qbuf[64];
912   int i;
913   int dontfix;
914   Id req, *reqp;
915   Id con, *conp;
916   Id obs, *obsp;
917   Id rec, *recp;
918   Id sug, *sugp;
919   Id p, *pp;
920   Id *dp;
921   Id n;
922
923   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
924   
925   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
926   queue_push(&q, s - pool->solvables);  /* push solvable Id */
927
928   while (q.count)
929     {
930       /*
931        * n: Id of solvable
932        * s: Pointer to solvable
933        */
934       
935       n = queue_shift(&q);
936       if (MAPTST(m, n))                /* continue if already done */
937         continue;
938
939       MAPSET(m, n);
940       s = pool->solvables + n;         /* s = Solvable in question */
941
942       dontfix = 0;
943       if (installed                     /* Installed system available */
944           && !solv->fixsystem           /* NOT repair errors in rpm dependency graph */
945           && s->repo == installed)      /* solvable is installed? */
946       {
947         dontfix = 1;                   /* dont care about broken rpm deps */
948       }
949
950       if (!dontfix && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
951         {
952           POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
953           addrule(solv, -n, 0);         /* uninstallable */
954         }
955
956       /*-----------------------------------------
957        * check requires of s
958        */
959       
960       if (s->requires)
961         {
962           reqp = s->repo->idarraydata + s->requires;
963           while ((req = *reqp++) != 0) /* go throw all requires */
964             {
965               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
966                 continue;
967
968               dp = pool_whatprovides(pool, req);
969
970               if (*dp == SYSTEMSOLVABLE)        /* always installed */
971                 continue;
972
973               if (dontfix)
974                 {
975                   /* the strategy here is to not insist on dependencies
976                    * that are already broken. so if we find one provider
977                    * that was already installed, we know that the
978                    * dependency was not broken before so we enforce it */
979                   for (i = 0; (p = dp[i]) != 0; i++)    /* for all providers */
980                     {
981                       if (pool->solvables[p].repo == installed)
982                         break;          /* provider was installed */
983                     }
984                   if (!p)               /* previously broken dependency */
985                     {
986                       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
987                       continue;
988                     }
989                 }
990
991               if (!*dp)
992                 {
993                   /* nothing provides req! */
994                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
995                   addrule(solv, -n, 0); /* mark requestor as uninstallable */
996                   continue;
997                 }
998
999               IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
1000                 {
1001                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
1002                   for (i = 0; dp[i]; i++)
1003                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvable2str(pool, pool->solvables + dp[i]));
1004                 }
1005
1006               /* add 'requires' dependency */
1007               /* rule: (-requestor|provider1|provider2|...|providerN) */
1008               addrule(solv, -n, dp - pool->whatprovidesdata);
1009
1010               /* descend the dependency tree */
1011               for (; *dp; dp++)   /* loop through all providers */
1012                 {
1013                   if (!MAPTST(m, *dp))
1014                     queue_push(&q, *dp);
1015                 }
1016
1017             } /* while, requirements of n */
1018
1019         } /* if, requirements */
1020
1021       /* that's all we check for src packages */
1022       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
1023         continue;
1024       
1025       /*-----------------------------------------
1026        * check conflicts of s
1027        */
1028       
1029       if (s->conflicts)
1030         {
1031           conp = s->repo->idarraydata + s->conflicts;
1032           while ((con = *conp++) != 0)
1033             {
1034               FOR_PROVIDES(p, pp, con)
1035                 {
1036                    /* dontfix: dont care about conflicts with already installed packs */
1037                   if (dontfix && pool->solvables[p].repo == installed)
1038                     continue;
1039                  /* rule: -n|-p: either solvable _or_ provider of conflict */
1040                   addrule(solv, -n, -p);
1041                 }
1042             }
1043         }
1044
1045       /*-----------------------------------------
1046        * check obsoletes if not installed
1047        */
1048       if (!installed || pool->solvables[n].repo != installed)
1049         {                              /* not installed */
1050           if (s->obsoletes)
1051             {
1052               obsp = s->repo->idarraydata + s->obsoletes;
1053               while ((obs = *obsp++) != 0)
1054                 {
1055                   FOR_PROVIDES(p, pp, obs)
1056                     addrule(solv, -n, -p);
1057                 }
1058             }
1059           FOR_PROVIDES(p, pp, s->name)
1060             {
1061               if (s->name == pool->solvables[p].name)
1062                 addrule(solv, -n, -p);
1063             }
1064         }
1065
1066       /*-----------------------------------------
1067        * add recommends to the rule list
1068        */
1069       if (s->recommends)
1070         {
1071           recp = s->repo->idarraydata + s->recommends;
1072           while ((rec = *recp++) != 0)
1073             {
1074               FOR_PROVIDES(p, pp, rec)
1075                 if (!MAPTST(m, p))
1076                   queue_push(&q, p);
1077             }
1078         }
1079       if (s->suggests)
1080         {
1081           sugp = s->repo->idarraydata + s->suggests;
1082           while ((sug = *sugp++) != 0)
1083             {
1084               FOR_PROVIDES(p, pp, sug)
1085                 if (!MAPTST(m, p))
1086                   queue_push(&q, p);
1087             }
1088         }
1089     }
1090   queue_free(&q);
1091   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
1092 }
1093
1094 static void
1095 addrpmrulesforweak(Solver *solv, Map *m)
1096 {
1097   Pool *pool = solv->pool;
1098   Solvable *s;
1099   Id sup, *supp;
1100   int i, n;
1101
1102   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
1103   for (i = n = 1; n < pool->nsolvables; i++, n++)
1104     {
1105       if (i == pool->nsolvables)
1106         i = 1;
1107       if (MAPTST(m, i))
1108         continue;
1109       s = pool->solvables + i;
1110       if (!pool_installable(pool, s))
1111         continue;
1112       sup = 0;
1113       if (s->supplements)
1114         {
1115           supp = s->repo->idarraydata + s->supplements;
1116           while ((sup = *supp++) != ID_NULL)
1117             if (dep_possible(solv, sup, m))
1118               break;
1119         }
1120       if (!sup && s->freshens)
1121         {
1122           supp = s->repo->idarraydata + s->freshens;
1123           while ((sup = *supp++) != ID_NULL)
1124             if (dep_possible(solv, sup, m))
1125               break;
1126         }
1127       if (!sup && s->enhances)
1128         {
1129           supp = s->repo->idarraydata + s->enhances;
1130           while ((sup = *supp++) != ID_NULL)
1131             if (dep_possible(solv, sup, m))
1132               break;
1133         }
1134       if (!sup)
1135         continue;
1136       addrpmrulesforsolvable(solv, s, m);
1137       n = 0;
1138     }
1139   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");  
1140 }
1141
1142 static void
1143 addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allowall)
1144 {
1145   Pool *pool = solv->pool;
1146   int i;
1147   Queue qs;
1148   Id qsbuf[64];
1149
1150   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
1151
1152   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1153   policy_findupdatepackages(solv, s, &qs, allowall);
1154   if (!MAPTST(m, s - pool->solvables))  /* add rule for s if not already done */
1155     addrpmrulesforsolvable(solv, s, m); 
1156   for (i = 0; i < qs.count; i++)
1157     if (!MAPTST(m, qs.elements[i]))
1158       addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
1159   queue_free(&qs);
1160   
1161   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
1162 }
1163
1164 /*
1165  * add rule for update
1166  *   (A|A1|A2|A3...)  An = update candidates for A
1167  * 
1168  * s = (installed) solvable
1169  */
1170
1171 static void
1172 addupdaterule(Solver *solv, Solvable *s, int allowall)
1173 {
1174   /* installed packages get a special upgrade allowed rule */
1175   Pool *pool = solv->pool;
1176   Id d;
1177   Queue qs;
1178   Id qsbuf[64];
1179
1180   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
1181
1182   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1183   policy_findupdatepackages(solv, s, &qs, allowall);
1184   if (qs.count == 0)                   /* no updaters found */
1185     d = 0;
1186   else
1187     d = pool_queuetowhatprovides(pool, &qs);    /* intern computed queue */
1188   queue_free(&qs);
1189   addrule(solv, s - pool->solvables, d);        /* allow update of s */
1190   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");  
1191 }
1192
1193
1194 /*-----------------------------------------------------------------*/
1195 /* watches */
1196
1197 /*
1198  * print watches
1199  *
1200  */
1201
1202 static void
1203 printWatches(Solver *solv, int type)
1204 {
1205   Pool *pool = solv->pool;
1206   int counter;
1207     
1208   POOL_DEBUG(type, "Watches: \n");
1209
1210   for (counter = -(pool->nsolvables); counter <= pool->nsolvables; counter ++)
1211      {
1212          POOL_DEBUG(type, "    solvable [%d] -- rule [%d]\n", counter, solv->watches[counter+pool->nsolvables]);
1213      }
1214 }
1215
1216 /*
1217  * makewatches
1218  * 
1219  * initial setup for all watches
1220  */
1221
1222 static void
1223 makewatches(Solver *solv)
1224 {
1225   Rule *r;
1226   int i;
1227   int nsolvables = solv->pool->nsolvables;
1228
1229   sat_free(solv->watches);
1230                                        /* lower half for removals, upper half for installs */
1231   solv->watches = (Id *)sat_calloc(2 * nsolvables, sizeof(Id));
1232 #if 1
1233   /* do it reverse so rpm rules get triggered first */
1234   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
1235 #else
1236   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
1237 #endif
1238     {
1239       if (!r->w1                       /* rule is disabled */
1240           || !r->w2)                   /* rule is assertion */
1241         continue;
1242
1243       /* see addwatches(solv, r) */
1244       r->n1 = solv->watches[nsolvables + r->w1];
1245       solv->watches[nsolvables + r->w1] = r - solv->rules;
1246
1247       r->n2 = solv->watches[nsolvables + r->w2];
1248       solv->watches[nsolvables + r->w2] = r - solv->rules;
1249     }
1250 }
1251
1252
1253 /*
1254  * add watches (for rule)
1255  */
1256
1257 static void
1258 addwatches(Solver *solv, Rule *r)
1259 {
1260   int nsolvables = solv->pool->nsolvables;
1261
1262   r->n1 = solv->watches[nsolvables + r->w1];
1263   solv->watches[nsolvables + r->w1] = r - solv->rules;
1264
1265   r->n2 = solv->watches[nsolvables + r->w2];
1266   solv->watches[nsolvables + r->w2] = r - solv->rules;
1267 }
1268
1269
1270 /*-----------------------------------------------------------------*/
1271 /* rule propagation */
1272
1273 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
1274
1275 /*
1276  * propagate
1277  * 
1278  * propagate decision to all rules
1279  * return : 0 = everything is OK
1280  *          watched rule = there is a conflict
1281  */
1282
1283 static Rule *
1284 propagate(Solver *solv, int level)
1285 {
1286   Pool *pool = solv->pool;
1287   Id *rp, *nrp;
1288   Rule *r;
1289   Id p, pkg, ow;
1290   Id *dp;
1291   Id *decisionmap = solv->decisionmap;
1292   Id *watches = solv->watches + pool->nsolvables;
1293
1294   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate -----\n");
1295
1296   while (solv->propagate_index < solv->decisionq.count)
1297     {
1298       /* negate because our watches trigger if literal goes FALSE */
1299       pkg = -solv->decisionq.elements[solv->propagate_index++];
1300       IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1301         {
1302           POOL_DEBUG(SAT_DEBUG_PROPAGATE, "popagate for decision %d level %d\n", -pkg, level);
1303           printruleelement(solv, SAT_DEBUG_PROPAGATE, 0, -pkg);
1304           printWatches(solv, SAT_DEBUG_SCHUBI);
1305         }
1306
1307       for (rp = watches + pkg; *rp; rp = nrp)
1308         {
1309           r = solv->rules + *rp;
1310           
1311           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1312             {
1313               POOL_DEBUG(SAT_DEBUG_PROPAGATE,"  watch triggered ");
1314               printrule(solv, SAT_DEBUG_PROPAGATE, r);
1315             }
1316           
1317           if (pkg == r->w1)
1318             {
1319               ow = r->w2; /* regard the second watchpoint to come to a solution */
1320               nrp = &r->n1;
1321             }
1322           else
1323             {
1324               ow = r->w1; /* regard the first watchpoint to come to a solution */
1325               nrp = &r->n2;
1326             }
1327           /* if clause is TRUE, nothing to do */
1328           if (DECISIONMAP_TRUE(ow))
1329             continue;
1330
1331           if (r->d)
1332             {
1333               /* not a binary clause, check if we need to move our watch */
1334               /* search for a literal that is not ow and not false */
1335               /* (true is also ok, in that case the rule is fulfilled) */
1336               if (r->p && r->p != ow && !DECISIONMAP_TRUE(-r->p))
1337                 p = r->p;
1338               else
1339                 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
1340                   if (p != ow && !DECISIONMAP_TRUE(-p))
1341                     break;
1342               if (p)
1343                 {
1344                   /* p is free to watch, move watch to p */
1345                   IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1346                     {
1347                       if (p > 0)
1348                         POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
1349                       else
1350                         POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
1351                     }
1352                   *rp = *nrp;
1353                   nrp = rp;
1354                   if (pkg == r->w1)
1355                     {
1356                       r->w1 = p;
1357                       r->n1 = watches[p];
1358                     }
1359                   else
1360                     {
1361                       r->w2 = p;
1362                       r->n2 = watches[p];
1363                     }
1364                   watches[p] = r - solv->rules;
1365                   continue;
1366                 }
1367             }
1368           /* unit clause found, set other watch to TRUE */
1369           if (DECISIONMAP_TRUE(-ow))
1370             return r;           /* eek, a conflict! */
1371           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1372             {
1373               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "   unit ");
1374               printrule(solv, SAT_DEBUG_PROPAGATE, r);
1375             }
1376           if (ow > 0)
1377             decisionmap[ow] = level;
1378           else
1379             decisionmap[-ow] = -level;
1380           queue_push(&solv->decisionq, ow);
1381           queue_push(&solv->decisionq_why, r - solv->rules);
1382           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1383             {
1384               Solvable *s = pool->solvables + (ow > 0 ? ow : -ow);
1385               if (ow > 0)
1386                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvable2str(pool, s));
1387               else
1388                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvable2str(pool, s));
1389             }
1390         }
1391     }
1392   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate end-----\n");
1393   
1394   return 0;     /* all is well */
1395 }
1396
1397
1398 /*-----------------------------------------------------------------*/
1399 /* Analysis */
1400
1401 /*
1402  * analyze
1403  *   and learn
1404  */
1405
1406 static int
1407 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
1408 {
1409   Pool *pool = solv->pool;
1410   Queue r;
1411   int rlevel = 1;
1412   Map seen;             /* global? */
1413   Id v, vv, *dp, why;
1414   int l, i, idx;
1415   int num = 0, l1num = 0;
1416   int learnt_why = solv->learnt_pool.count;
1417   Id *decisionmap = solv->decisionmap;
1418  
1419   queue_init(&r);
1420
1421   POOL_DEBUG(SAT_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
1422   map_init(&seen, pool->nsolvables);
1423   idx = solv->decisionq.count;
1424   for (;;)
1425     {
1426       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1427         printruleclass(solv, SAT_DEBUG_ANALYZE, c);
1428       queue_push(&solv->learnt_pool, c - solv->rules);
1429       dp = c->d ? pool->whatprovidesdata + c->d : 0;
1430       /* go through all literals of the rule */
1431       for (i = -1; ; i++)
1432         {
1433           if (i == -1)
1434             v = c->p;
1435           else if (c->d == 0)
1436             v = i ? 0 : c->w2;
1437           else
1438             v = *dp++;
1439           if (v == 0)
1440             break;
1441
1442           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1443             continue;
1444           vv = v > 0 ? v : -v;
1445           if (MAPTST(&seen, vv))
1446             continue;
1447           l = solv->decisionmap[vv];
1448           if (l < 0)
1449             l = -l;
1450           if (l == 1)
1451             {
1452               /* a level 1 literal, mark it for later */
1453               MAPSET(&seen, vv);        /* mark for scanning in level 1 phase */
1454               l1num++;
1455               continue;
1456             }
1457           MAPSET(&seen, vv);
1458           if (l == level)
1459             num++;                      /* need to do this one as well */
1460           else
1461             {
1462               queue_push(&r, v);
1463               if (l > rlevel)
1464                 rlevel = l;
1465             }
1466         }
1467       assert(num > 0);
1468       for (;;)
1469         {
1470           v = solv->decisionq.elements[--idx];
1471           vv = v > 0 ? v : -v;
1472           if (MAPTST(&seen, vv))
1473             break;
1474         }
1475       c = solv->rules + solv->decisionq_why.elements[idx];
1476       MAPCLR(&seen, vv);
1477       if (--num == 0)
1478         break;
1479     }
1480   *pr = -v;     /* so that v doesn't get lost */
1481
1482   /* add involved level 1 rules */
1483   if (l1num)
1484     {
1485       POOL_DEBUG(SAT_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
1486       idx++;
1487       while (idx)
1488         {
1489           v = solv->decisionq.elements[--idx];
1490           vv = v > 0 ? v : -v;
1491           if (!MAPTST(&seen, vv))
1492             continue;
1493           why = solv->decisionq_why.elements[idx];
1494           if (!why)
1495             {
1496               queue_push(&solv->learnt_pool, -vv); 
1497               IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1498                 {
1499                   POOL_DEBUG(SAT_DEBUG_ANALYZE, "RPM ASSERT Rule:\n");
1500                   printruleelement(solv, SAT_DEBUG_ANALYZE, 0, v);
1501                 }
1502               continue;
1503             }
1504           queue_push(&solv->learnt_pool, why);
1505           c = solv->rules + why;
1506           IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1507             printruleclass(solv, SAT_DEBUG_ANALYZE, c);
1508           for (i = -1; ; i++)
1509             {
1510               if (i == -1)
1511                 v = c->p;
1512               else if (c->d == 0)
1513                 v = i ? 0 : c->w2;
1514               else
1515                 v = *dp++;
1516               if (v == 0)
1517                 break;
1518               if (DECISIONMAP_TRUE(v))  /* the one true literal */
1519                 continue;
1520               vv = v > 0 ? v : -v;
1521               l = solv->decisionmap[vv];
1522               if (l != 1 && l != -1)
1523                 continue;
1524               MAPSET(&seen, vv);
1525             }
1526         }
1527     }
1528   map_free(&seen);
1529
1530   if (r.count == 0)
1531     *dr = 0;
1532   else if (r.count == 1 && r.elements[0] < 0)
1533     *dr = r.elements[0];
1534   else
1535     *dr = pool_queuetowhatprovides(pool, &r);
1536   IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1537     {
1538       POOL_DEBUG(SAT_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
1539       printruleelement(solv, SAT_DEBUG_ANALYZE, 0, *pr);
1540       for (i = 0; i < r.count; i++)
1541         printruleelement(solv, SAT_DEBUG_ANALYZE, 0, r.elements[i]);
1542     }
1543   /* push end marker on learnt reasons stack */
1544   queue_push(&solv->learnt_pool, 0);
1545   if (whyp)
1546     *whyp = learnt_why;
1547   return rlevel;
1548 }
1549
1550
1551 /*
1552  * reset_solver
1553  * reset the solver decisions to right after the rpm rules.
1554  * called after rules have been enabled/disabled
1555  */
1556
1557 static void
1558 reset_solver(Solver *solv)
1559 {
1560   Pool *pool = solv->pool;
1561   int i;
1562   Id v;
1563
1564   enabledisablelearntrules(solv);
1565
1566   /* redo all direct rpm rule decisions */
1567   /* we break at the first decision with a why attached, this is
1568    * either a job/system rule assertion or a propagated decision */
1569   for (i = solv->decisionq.count - 1; i >= solv->directdecisions; i--)
1570     {
1571       v = solv->decisionq.elements[i];
1572       solv->decisionmap[v > 0 ? v : -v] = 0;
1573     }
1574
1575   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions done reduced from %d to %d\n", solv->decisionq.count, solv->directdecisions);
1576
1577   solv->decisionq_why.count = solv->directdecisions;
1578   solv->decisionq.count = solv->directdecisions;
1579   solv->recommends_index = -1;
1580   solv->propagate_index = 0;
1581
1582   /* redo all job/system decisions */
1583   makeruledecisions(solv);
1584   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
1585   /* recreate watch chains */
1586   makewatches(solv);
1587 }
1588
1589
1590 /*
1591  * analyze_unsolvable_rule
1592  */
1593
1594 static void
1595 analyze_unsolvable_rule(Solver *solv, Rule *r)
1596 {
1597   Pool *pool = solv->pool;
1598   int i;
1599   Id why = r - solv->rules;
1600   IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
1601     printruleclass(solv, SAT_DEBUG_UNSOLVABLE, r);
1602   if (solv->learntrules && why >= solv->learntrules)
1603     {
1604       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1605         if (solv->learnt_pool.elements[i] > 0)
1606           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i]);
1607       return;
1608     }
1609   /* do not add rpm rules to problem */
1610   if (why < solv->jobrules)
1611     return;
1612   /* turn rule into problem */
1613   if (why >= solv->jobrules && why < solv->systemrules)
1614     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1615   /* return if problem already countains our rule */
1616   if (solv->problems.count)
1617     {
1618       for (i = solv->problems.count - 1; i >= 0; i--)
1619         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1620           break;
1621         else if (solv->problems.elements[i] == why)
1622           return;
1623     }
1624   queue_push(&solv->problems, why);
1625 }
1626
1627
1628 /*
1629  * analyze_unsolvable
1630  *
1631  * return: 1 - disabled some rules, try again
1632  *         0 - hopeless
1633  */
1634
1635 static int
1636 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1637 {
1638   Pool *pool = solv->pool;
1639   Rule *r;
1640   Map seen;             /* global to speed things up? */
1641   Id v, vv, *dp, why;
1642   int l, i, idx;
1643   Id *decisionmap = solv->decisionmap;
1644   int oldproblemcount;
1645   int oldlearntpoolcount;
1646   int lastweak;
1647
1648   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1649   oldproblemcount = solv->problems.count;
1650   oldlearntpoolcount = solv->learnt_pool.count;
1651
1652   /* make room for proof index */
1653   /* must update it later, as analyze_unsolvable_rule would confuse
1654    * it with a rule index if we put the real value in already */
1655   queue_push(&solv->problems, 0);
1656
1657   r = cr;
1658   map_init(&seen, pool->nsolvables);
1659   queue_push(&solv->learnt_pool, r - solv->rules);
1660   analyze_unsolvable_rule(solv, r);
1661   dp = r->d ? pool->whatprovidesdata + r->d : 0;
1662   for (i = -1; ; i++)
1663     {
1664       if (i == -1)
1665         v = r->p;
1666       else if (r->d == 0)
1667         v = i ? 0 : r->w2;
1668       else
1669         v = *dp++;
1670       if (v == 0)
1671         break;
1672       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1673           continue;
1674       vv = v > 0 ? v : -v;
1675       l = solv->decisionmap[vv];
1676       if (l < 0)
1677         l = -l;
1678       MAPSET(&seen, vv);
1679     }
1680   idx = solv->decisionq.count;
1681   while (idx > 0)
1682     {
1683       v = solv->decisionq.elements[--idx];
1684       vv = v > 0 ? v : -v;
1685       if (!MAPTST(&seen, vv))
1686         continue;
1687       why = solv->decisionq_why.elements[idx];
1688       if (!why)
1689         {
1690           /* level 1 and no why, must be an rpm assertion */
1691           IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
1692             {
1693               POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "RPM ");
1694               printruleelement(solv, SAT_DEBUG_UNSOLVABLE, 0, v);
1695             }
1696           /* this is the only positive rpm assertion */
1697           if (v == SYSTEMSOLVABLE)
1698             v = -v;
1699           assert(v < 0);
1700           queue_push(&solv->learnt_pool, v);
1701           continue;
1702         }
1703       queue_push(&solv->learnt_pool, why);
1704       r = solv->rules + why;
1705       analyze_unsolvable_rule(solv, r);
1706       dp = r->d ? pool->whatprovidesdata + r->d : 0;
1707       for (i = -1; ; i++)
1708         {
1709           if (i == -1)
1710             v = r->p;
1711           else if (r->d == 0)
1712             v = i ? 0 : r->w2;
1713           else
1714             v = *dp++;
1715           if (v == 0)
1716             break;
1717           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1718               continue;
1719           vv = v > 0 ? v : -v;
1720           l = solv->decisionmap[vv];
1721           if (l < 0)
1722             l = -l;
1723           MAPSET(&seen, vv);
1724         }
1725     }
1726   map_free(&seen);
1727   queue_push(&solv->problems, 0);       /* mark end of this problem */
1728
1729   lastweak = 0;
1730   if (solv->weakrules != solv->learntrules)
1731     {
1732       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1733         {
1734           why = solv->problems.elements[i];
1735           if (why < solv->weakrules || why >= solv->learntrules)
1736             continue;
1737           if (!lastweak || lastweak < why)
1738             lastweak = why;
1739         }
1740     }
1741   if (lastweak)
1742     {
1743       /* disable last weak rule */
1744       solv->problems.count = oldproblemcount;
1745       solv->learnt_pool.count = oldlearntpoolcount;
1746       r = solv->rules + lastweak;
1747       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling weak ");
1748       printrule(solv, SAT_DEBUG_UNSOLVABLE, r);
1749       disablerule(solv, r);
1750       reset_solver(solv);
1751       return 1;
1752     }
1753
1754   /* finish proof */
1755   queue_push(&solv->learnt_pool, 0);
1756   solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1757
1758   if (disablerules)
1759     {
1760       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1761         disableproblem(solv, solv->problems.elements[i]);
1762       reset_solver(solv);
1763       return 1;
1764     }
1765   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1766   return 0;
1767 }
1768
1769
1770 /*-----------------------------------------------------------------*/
1771 /* Decision revert */
1772
1773 /*
1774  * revert
1775  * revert decision at level
1776  */
1777
1778 static void
1779 revert(Solver *solv, int level)
1780 {
1781   Pool *pool = solv->pool;
1782   Id v, vv;
1783   while (solv->decisionq.count)
1784     {
1785       v = solv->decisionq.elements[solv->decisionq.count - 1];
1786       vv = v > 0 ? v : -v;
1787       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1788         break;
1789       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1790       solv->decisionmap[vv] = 0;
1791       solv->decisionq.count--;
1792       solv->decisionq_why.count--;
1793       solv->propagate_index = solv->decisionq.count;
1794     }
1795   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1796     {
1797       solv->branches.count--;
1798       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1799         solv->branches.count--;
1800     }
1801   solv->recommends_index = -1;
1802 }
1803
1804
1805 /*
1806  * watch2onhighest - put watch2 on literal with highest level
1807  */
1808
1809 static inline void
1810 watch2onhighest(Solver *solv, Rule *r)
1811 {
1812   int l, wl = 0;
1813   Id v, *dp;
1814
1815   if (!r->d)
1816     return;     /* binary rule, both watches are set */
1817   dp = solv->pool->whatprovidesdata + r->d;
1818   while ((v = *dp++) != 0)
1819     {
1820       l = solv->decisionmap[v < 0 ? -v : v];
1821       if (l < 0)
1822         l = -l;
1823       if (l > wl)
1824         {
1825           r->w2 = dp[-1];
1826           wl = l;
1827         }
1828     }
1829 }
1830
1831
1832 /*
1833  * setpropagatelearn
1834  *
1835  * add free decision to decision q, increase level
1836  * propagate decision, return if no conflict.
1837  * in conflict case, analyze conflict rule, add resulting
1838  * rule to learnt rule set, make decision from learnt
1839  * rule (always unit) and re-propagate.
1840  */
1841
1842 static int
1843 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
1844 {
1845   Pool *pool = solv->pool;
1846   Rule *r;
1847   Id p, d;
1848   int l, why;
1849
1850   if (decision)
1851     {
1852       level++;
1853       if (decision > 0)
1854         solv->decisionmap[decision] = level;
1855       else
1856         solv->decisionmap[-decision] = -level;
1857       queue_push(&solv->decisionq, decision);
1858       queue_push(&solv->decisionq_why, 0);
1859     }
1860   for (;;)
1861     {
1862       r = propagate(solv, level);
1863       if (!r)
1864         break;
1865       if (level == 1)
1866         return analyze_unsolvable(solv, r, disablerules);
1867       POOL_DEBUG(SAT_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1868       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1869       assert(l > 0 && l < level);
1870       POOL_DEBUG(SAT_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1871       level = l;
1872       revert(solv, level);
1873       r = addrule(solv, p, d);       /* p requires d */
1874       assert(r);
1875       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1876       queue_push(&solv->learnt_why, why);
1877       if (d)
1878         {
1879           /* at least 2 literals, needs watches */
1880           watch2onhighest(solv, r);
1881           addwatches(solv, r);
1882         }
1883       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1884       queue_push(&solv->decisionq, p);
1885       queue_push(&solv->decisionq_why, r - solv->rules);
1886       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1887         {
1888           POOL_DEBUG(SAT_DEBUG_ANALYZE, "decision: ");
1889           printruleelement(solv, SAT_DEBUG_ANALYZE, 0, p);
1890           POOL_DEBUG(SAT_DEBUG_ANALYZE, "new rule: ");
1891           printrule(solv, SAT_DEBUG_ANALYZE, r);
1892         }
1893     }
1894   return level;
1895 }
1896
1897
1898 /*
1899  * install best package from the queue. We add an extra package, inst, if
1900  * provided. See comment in weak install section.
1901  */
1902 static int
1903 selectandinstall(Solver *solv, int level, Queue *dq, Id inst, int disablerules)
1904 {
1905   Pool *pool = solv->pool;
1906   Id p;
1907   int i;
1908
1909   if (dq->count > 1 || inst)
1910     policy_filter_unwanted(solv, dq, inst, POLICY_MODE_CHOOSE);
1911
1912   i = 0;
1913   if (dq->count > 1)
1914     {
1915       /* choose the supplemented one */
1916       for (i = 0; i < dq->count; i++)
1917         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1918           break;
1919       if (i == dq->count)
1920         {
1921           for (i = 1; i < dq->count; i++)
1922             queue_push(&solv->branches, dq->elements[i]);
1923           queue_push(&solv->branches, -level);
1924           i = 0;
1925         }
1926     }
1927   p = dq->elements[i];
1928
1929   POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
1930
1931   return setpropagatelearn(solv, level, p, disablerules);
1932 }
1933
1934
1935 /*-----------------------------------------------------------------*/
1936 /* Main solver interface */
1937
1938
1939 /*
1940  * solver_create
1941  * create solver structure
1942  *
1943  * pool: all available solvables
1944  * installed: installed Solvables
1945  *
1946  *
1947  * Upon solving, rules are created to flag the Solvables
1948  * of the 'installed' Repo as installed.
1949  */
1950
1951 Solver *
1952 solver_create(Pool *pool, Repo *installed)
1953 {
1954   Solver *solv;
1955   solv = (Solver *)sat_calloc(1, sizeof(Solver));
1956   solv->pool = pool;
1957   solv->installed = installed;
1958
1959   queue_init(&solv->ruletojob);
1960   queue_init(&solv->decisionq);
1961   queue_init(&solv->decisionq_why);
1962   queue_init(&solv->problems);
1963   queue_init(&solv->suggestions);
1964   queue_init(&solv->learnt_why);
1965   queue_init(&solv->learnt_pool);
1966   queue_init(&solv->branches);
1967
1968   map_init(&solv->recommendsmap, pool->nsolvables);
1969   map_init(&solv->suggestsmap, pool->nsolvables);
1970   map_init(&solv->noupdate, installed ? installed->end - installed->start : 0);
1971   solv->recommends_index = 0;
1972
1973   solv->decisionmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
1974   solv->rules = (Rule *)sat_malloc((solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
1975   memset(solv->rules, 0, sizeof(Rule));
1976   solv->nrules = 1;
1977
1978   return solv;
1979 }
1980
1981
1982 /*
1983  * solver_free
1984  */
1985
1986 void
1987 solver_free(Solver *solv)
1988 {
1989   queue_free(&solv->ruletojob);
1990   queue_free(&solv->decisionq);
1991   queue_free(&solv->decisionq_why);
1992   queue_free(&solv->learnt_why);
1993   queue_free(&solv->learnt_pool);
1994   queue_free(&solv->problems);
1995   queue_free(&solv->suggestions);
1996   queue_free(&solv->branches);
1997
1998   map_free(&solv->recommendsmap);
1999   map_free(&solv->suggestsmap);
2000   map_free(&solv->noupdate);
2001   sat_free(solv->decisionmap);
2002   sat_free(solv->rules);
2003   sat_free(solv->watches);
2004   sat_free(solv->weaksystemrules);
2005   sat_free(solv->obsoletes);
2006   sat_free(solv->obsoletes_data);
2007   sat_free(solv);
2008 }
2009
2010
2011 /*-------------------------------------------------------*/
2012
2013 /*
2014  * run_solver
2015  * 
2016  * all rules have been set up, now actually run the solver
2017  *
2018  */
2019
2020 static void
2021 run_solver(Solver *solv, int disablerules, int doweak)
2022 {
2023   Queue dq;
2024   int systemlevel;
2025   int level, olevel;
2026   Rule *r;
2027   int i, j, n;
2028   Solvable *s;
2029   Pool *pool = solv->pool;
2030   Id p, *dp;
2031
2032   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
2033     {
2034       POOL_DEBUG (SAT_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
2035       for (i = 0; i < solv->nrules; i++)
2036         printrule(solv, SAT_DEBUG_RULE_CREATION, solv->rules + i);
2037     }
2038
2039   /* create watches chains */
2040   makewatches(solv);
2041
2042   POOL_DEBUG(SAT_DEBUG_STATS, "initial decisions: %d\n", solv->decisionq.count);
2043   
2044   IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2045     printdecisions(solv);
2046
2047   /* start SAT algorithm */
2048   level = 1;
2049   systemlevel = level + 1;
2050   POOL_DEBUG(SAT_DEBUG_STATS, "solving...\n");
2051
2052   queue_init(&dq);
2053   for (;;)
2054     {
2055       /*
2056        * propagate
2057        */
2058       
2059       if (level == 1)
2060         {
2061           POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
2062           if ((r = propagate(solv, level)) != 0)
2063             {
2064               if (analyze_unsolvable(solv, r, disablerules))
2065                 continue;
2066               queue_free(&dq);
2067               return;
2068             }
2069         }
2070
2071       /*
2072        * installed packages
2073        */
2074       
2075       if (level < systemlevel && solv->installed && solv->installed->nsolvables)
2076         {
2077           if (!solv->updatesystem)
2078             {
2079               /* try to keep as many packages as possible */
2080               POOL_DEBUG(SAT_DEBUG_STATS, "installing system packages\n");
2081               for (i = solv->installed->start, n = 0; ; i++)
2082                 {
2083                   if (n == solv->installed->nsolvables)
2084                     break;
2085                   if (i == solv->installed->end)
2086                     i = solv->installed->start;
2087                   s = pool->solvables + i;
2088                   if (s->repo != solv->installed)
2089                     continue;
2090                   n++;
2091                   if (solv->decisionmap[i] != 0)
2092                     continue;
2093                   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
2094                   olevel = level;
2095                   level = setpropagatelearn(solv, level, i, disablerules);
2096                   if (level == 0)
2097                     {
2098                       queue_free(&dq);
2099                       return;
2100                     }
2101                   if (level <= olevel)
2102                     n = 0;
2103                 }
2104             }
2105           if (solv->weaksystemrules)
2106             {
2107               POOL_DEBUG(SAT_DEBUG_STATS, "installing weak system packages\n");
2108               for (i = solv->installed->start; i < solv->installed->end; i++)
2109                 {
2110                   if (pool->solvables[i].repo != solv->installed)
2111                     continue;
2112                   if (solv->decisionmap[i] > 0 || (solv->decisionmap[i] < 0 && solv->weaksystemrules[i - solv->installed->start] == 0))
2113                     continue;
2114                   /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
2115                   if (MAPTST(&solv->noupdate, i - solv->installed->start))
2116                     continue;
2117                   queue_empty(&dq);
2118                   if (solv->weaksystemrules[i - solv->installed->start])
2119                     {
2120                       dp = pool->whatprovidesdata + solv->weaksystemrules[i - solv->installed->start];
2121                       while ((p = *dp++) != 0)
2122                         {
2123                           if (solv->decisionmap[p] > 0)
2124                             break;
2125                           if (solv->decisionmap[p] == 0)
2126                             queue_push(&dq, p);
2127                         }
2128                       if (p)
2129                         continue;       /* update package already installed */
2130                     }
2131                   if (!dq.count && solv->decisionmap[i] != 0)
2132                     continue;
2133                   olevel = level;
2134                   /* FIXME: i is handled a bit different because we do not want
2135                    * to have it pruned just because it is not recommened.
2136                    * we should not prune installed packages instead */
2137                   level = selectandinstall(solv, level, &dq, (solv->decisionmap[i] ? 0 : i), disablerules);
2138                   if (level == 0)
2139                     {
2140                       queue_free(&dq);
2141                       return;
2142                     }
2143                   if (level <= olevel)
2144                     break;
2145                 }
2146               if (i < solv->installed->end)
2147                 continue;
2148             }
2149           systemlevel = level;
2150         }
2151
2152       /*
2153        * decide
2154        */
2155       
2156       POOL_DEBUG(SAT_DEBUG_STATS, "deciding unresolved rules\n");
2157       for (i = 1, n = 1; ; i++, n++)
2158         {
2159           if (n == solv->nrules)
2160             break;
2161           if (i == solv->nrules)
2162             i = 1;
2163           r = solv->rules + i;
2164           if (!r->w1)
2165             continue;
2166           queue_empty(&dq);
2167           if (r->d == 0)
2168             {
2169               /* binary or unary rule */
2170               /* need two positive undecided literals */
2171               if (r->p < 0 || r->w2 <= 0)
2172                 continue;
2173               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2174                 continue;
2175               queue_push(&dq, r->p);
2176               queue_push(&dq, r->w2);
2177             }
2178           else
2179             {
2180               /* make sure that
2181                * all negative literals are installed
2182                * no positive literal is installed
2183                * i.e. the rule is not fulfilled and we
2184                * just need to decide on the positive literals
2185                */
2186               if (r->p < 0)
2187                 {
2188                   if (solv->decisionmap[-r->p] <= 0)
2189                     continue;
2190                 }
2191               else
2192                 {
2193                   if (solv->decisionmap[r->p] > 0)
2194                     continue;
2195                   if (solv->decisionmap[r->p] == 0)
2196                     queue_push(&dq, r->p);
2197                 }
2198               dp = pool->whatprovidesdata + r->d;
2199               while ((p = *dp++) != 0)
2200                 {
2201                   if (p < 0)
2202                     {
2203                       if (solv->decisionmap[-p] <= 0)
2204                         break;
2205                     }
2206                   else
2207                     {
2208                       if (solv->decisionmap[p] > 0)
2209                         break;
2210                       if (solv->decisionmap[p] == 0)
2211                         queue_push(&dq, p);
2212                     }
2213                 }
2214               if (p)
2215                 continue;
2216             }
2217           /* dq.count < 2 cannot happen as this means that
2218            * the rule is unit */
2219           assert(dq.count > 1);
2220           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
2221             {
2222               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "unfulfilled ");
2223               printrule(solv, SAT_DEBUG_PROPAGATE, r);
2224             }
2225
2226           olevel = level;
2227           level = selectandinstall(solv, level, &dq, 0, disablerules);
2228           if (level == 0)
2229             {
2230               queue_free(&dq);
2231               return;
2232             }
2233           if (level < systemlevel)
2234             break;
2235           n = 0;
2236         } /* for(), decide */
2237
2238       if (n != solv->nrules)    /* continue if level < systemlevel */
2239         continue;
2240       
2241       if (doweak && !solv->problems.count)
2242         {
2243           int qcount;
2244
2245           POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended packages\n");
2246           if (!REGARD_RECOMMENDS_OF_INSTALLED_ITEMS)
2247             {
2248               for (i = 0; i < solv->decisionq.count; i++)
2249                 {
2250                   p = solv->decisionq.elements[i];
2251                   if (p > 0 && pool->solvables[p].repo == solv->installed)
2252                     solv->decisionmap[p] = -solv->decisionmap[p];
2253                 }
2254             }
2255           queue_empty(&dq);
2256           for (i = 1; i < pool->nsolvables; i++)
2257             {
2258               if (solv->decisionmap[i] < 0)
2259                 continue;
2260               if (solv->decisionmap[i] > 0)
2261                 {
2262                   Id *recp, rec, *pp, p;
2263                   s = pool->solvables + i;
2264                   /* installed, check for recommends */
2265                   /* XXX need to special case AND ? */
2266                   if (s->recommends)
2267                     {
2268                       recp = s->repo->idarraydata + s->recommends;
2269                       while ((rec = *recp++) != 0)
2270                         {
2271                           qcount = dq.count;
2272                           FOR_PROVIDES(p, pp, rec)
2273                             {
2274                               if (solv->decisionmap[p] > 0)
2275                                 {
2276                                   dq.count = qcount;
2277                                   break;
2278                                 }
2279                               else if (solv->decisionmap[p] == 0)
2280                                 {
2281                                   queue_pushunique(&dq, p);
2282                                 }
2283                             }
2284                         }
2285                     }
2286                 }
2287               else
2288                 {
2289                   s = pool->solvables + i;
2290                   if (!s->supplements && !s->freshens)
2291                     continue;
2292                   if (!pool_installable(pool, s))
2293                     continue;
2294                   if (solver_is_supplementing(solv, s))
2295                     queue_pushunique(&dq, i);
2296                 }
2297             }
2298           if (!REGARD_RECOMMENDS_OF_INSTALLED_ITEMS)
2299             {
2300               for (i = 0; i < solv->decisionq.count; i++)
2301                 {
2302                   p = solv->decisionq.elements[i];
2303                   if (p > 0 && pool->solvables[p].repo == solv->installed)
2304                     solv->decisionmap[p] = -solv->decisionmap[p];
2305                 }
2306             }
2307           if (dq.count)
2308             {
2309               if (dq.count > 1)
2310                 policy_filter_unwanted(solv, &dq, 0, POLICY_MODE_RECOMMEND);
2311               p = dq.elements[0];
2312               POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
2313               level = setpropagatelearn(solv, level, p, 0);
2314               continue;
2315             }
2316         }
2317
2318      if (solv->solution_callback)
2319         {
2320           solv->solution_callback(solv, solv->solution_callback_data);
2321           if (solv->branches.count)
2322             {
2323               int i = solv->branches.count - 1;
2324               int l = -solv->branches.elements[i];
2325               for (; i > 0; i--)
2326                 if (solv->branches.elements[i - 1] < 0)
2327                   break;
2328               p = solv->branches.elements[i];
2329               POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
2330               queue_empty(&dq);
2331               for (j = i + 1; j < solv->branches.count; j++)
2332                 queue_push(&dq, solv->branches.elements[j]);
2333               solv->branches.count = i;
2334               level = l;
2335               revert(solv, level);
2336               if (dq.count > 1)
2337                 for (j = 0; j < dq.count; j++)
2338                   queue_push(&solv->branches, dq.elements[j]);
2339               olevel = level;
2340               level = setpropagatelearn(solv, level, p, disablerules);
2341               if (level == 0)
2342                 {
2343                   queue_free(&dq);
2344                   return;
2345                 }
2346               continue;
2347             }
2348           /* all branches done, we're finally finished */
2349           break;
2350         }
2351
2352       /* minimization step */
2353      if (solv->branches.count)
2354         {
2355           int l = 0, lasti = -1, lastl = -1;
2356           p = 0;
2357           for (i = solv->branches.count - 1; i >= 0; i--)
2358             {
2359               p = solv->branches.elements[i];
2360               if (p < 0)
2361                 l = -p;
2362               else if (p > 0 && solv->decisionmap[p] > l + 1)
2363                 {
2364                   lasti = i;
2365                   lastl = l;
2366                 }
2367             }
2368           if (lasti >= 0)
2369             {
2370               /* kill old solvable so that we do not loop */
2371               p = solv->branches.elements[lasti];
2372               solv->branches.elements[lasti] = 0;
2373               POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], l, solvable2str(pool, pool->solvables + p));
2374
2375               level = lastl;
2376               revert(solv, level);
2377               olevel = level;
2378               level = setpropagatelearn(solv, level, p, disablerules);
2379               if (level == 0)
2380                 {
2381                   queue_free(&dq);
2382                   return;
2383                 }
2384               continue;
2385             }
2386         }
2387       break;
2388     }
2389   queue_free(&dq);
2390 }
2391
2392   
2393 /*
2394  * refine_suggestion
2395  * at this point, all rules that led to conflicts are disabled.
2396  * we re-enable all rules of a problem set but rule "sug", then
2397  * continue to disable more rules until there as again a solution.
2398  */
2399   
2400 /* FIXME: think about conflicting assertions */
2401
2402 static void
2403 refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
2404 {
2405   Pool *pool = solv->pool;
2406   Rule *r;
2407   int i, j;
2408   Id v;
2409   Queue disabled;
2410   int disabledcnt;
2411
2412   IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
2413     {
2414       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
2415       for (i = 0; problem[i]; i++)
2416         {
2417           if (problem[i] == sug)
2418             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
2419           printproblem(solv, problem[i]);
2420         }
2421     }
2422   queue_init(&disabled);
2423   queue_empty(refined);
2424   queue_push(refined, sug);
2425
2426   /* re-enable all problem rules with the exception of "sug" */
2427   revert(solv, 1);
2428   reset_solver(solv);
2429
2430   for (i = 0; problem[i]; i++)
2431     if (problem[i] != sug)
2432       enableproblem(solv, problem[i]);
2433
2434   if (sug < 0)
2435     disableupdaterules(solv, job, -(sug + 1));
2436
2437   for (;;)
2438     {
2439       /* re-enable as many weak rules as possible */
2440       for (i = solv->weakrules; i < solv->learntrules; i++)
2441         {
2442           r = solv->rules + i;
2443           if (!r->w1)
2444             enablerule(solv, r);
2445         }
2446
2447       queue_empty(&solv->problems);
2448       revert(solv, 1);          /* XXX move to reset_solver? */
2449       reset_solver(solv);
2450
2451       run_solver(solv, 0, 0);
2452       if (!solv->problems.count)
2453         {
2454           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
2455           IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2456             printdecisions(solv);
2457           break;                /* great, no more problems */
2458         }
2459       disabledcnt = disabled.count;
2460       /* skip over proof index */
2461       for (i = 1; i < solv->problems.count - 1; i++)
2462         {
2463           /* ignore solutions in refined */
2464           v = solv->problems.elements[i];
2465           if (v == 0)
2466             break;      /* end of problem reached */
2467           for (j = 0; problem[j]; j++)
2468             if (problem[j] != sug && problem[j] == v)
2469               break;
2470           if (problem[j])
2471             continue;
2472           queue_push(&disabled, v);
2473         }
2474       if (disabled.count == disabledcnt)
2475         {
2476           /* no solution found, this was an invalid suggestion! */
2477           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
2478           refined->count = 0;
2479           break;
2480         }
2481       if (disabled.count == disabledcnt + 1)
2482         {
2483           /* just one suggestion, add it to refined list */
2484           v = disabled.elements[disabledcnt];
2485           queue_push(refined, v);
2486           disableproblem(solv, v);
2487           if (v < 0)
2488             disableupdaterules(solv, job, -(v + 1));
2489         }
2490       else
2491         {
2492           /* more than one solution, disable all */
2493           /* do not push anything on refine list */
2494           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
2495             {
2496               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
2497               for (i = disabledcnt; i < disabled.count; i++)
2498                 printproblem(solv, disabled.elements[i]);
2499             }
2500           for (i = disabledcnt; i < disabled.count; i++)
2501             disableproblem(solv, disabled.elements[i]);
2502         }
2503     }
2504   /* all done, get us back into the same state as before */
2505   /* enable refined rules again */
2506   for (i = 0; i < disabled.count; i++)
2507     enableproblem(solv, disabled.elements[i]);
2508   /* disable problem rules again */
2509   for (i = 0; problem[i]; i++)
2510     disableproblem(solv, problem[i]);
2511   disableupdaterules(solv, job, -1);
2512   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
2513 }
2514
2515 static void
2516 problems_to_solutions(Solver *solv, Queue *job)
2517 {
2518   Pool *pool = solv->pool;
2519   Queue problems;
2520   Queue solution;
2521   Queue solutions;
2522   Id *problem;
2523   Id why;
2524   int i, j;
2525
2526   if (!solv->problems.count)
2527     return;
2528   queue_clone(&problems, &solv->problems);
2529   queue_init(&solution);
2530   queue_init(&solutions);
2531   /* copy over proof index */
2532   queue_push(&solutions, problems.elements[0]);
2533   problem = problems.elements + 1;
2534   for (i = 1; i < problems.count; i++)
2535     {
2536       Id v = problems.elements[i];
2537       if (v == 0)
2538         {
2539           /* mark end of this problem */
2540           queue_push(&solutions, 0);
2541           queue_push(&solutions, 0);
2542           if (i + 1 == problems.count)
2543             break;
2544           /* copy over proof of next problem */
2545           queue_push(&solutions, problems.elements[i + 1]);
2546           i++;
2547           problem = problems.elements + i + 1;
2548           continue;
2549         }
2550       refine_suggestion(solv, job, problem, v, &solution);
2551       if (!solution.count)
2552         continue;       /* this solution didn't work out */
2553
2554       for (j = 0; j < solution.count; j++)
2555         {
2556           why = solution.elements[j];
2557           /* must be either job descriptor or system rule */
2558           assert(why < 0 || (why >= solv->systemrules && why < solv->weakrules));
2559 #if 0
2560           printproblem(solv, why);
2561 #endif
2562           if (why < 0)
2563             {
2564               /* job descriptor */
2565               queue_push(&solutions, 0);
2566               queue_push(&solutions, -why);
2567             }
2568           else
2569             {
2570               /* system rule, find replacement package */
2571               Id p, rp = 0;
2572               p = solv->installed->start + (why - solv->systemrules);
2573               if (solv->weaksystemrules && solv->weaksystemrules[why - solv->systemrules])
2574                 {
2575                   Id *dp = pool->whatprovidesdata + solv->weaksystemrules[why - solv->systemrules];
2576                   for (; *dp; dp++)
2577                     {
2578                       if (*dp >= solv->installed->start && *dp < solv->installed->start + solv->installed->nsolvables)
2579                         continue;
2580                       if (solv->decisionmap[*dp] > 0)
2581                         {
2582                           rp = *dp;
2583                           break;
2584                         }
2585                     }
2586                 }
2587               queue_push(&solutions, p);
2588               queue_push(&solutions, rp);
2589             }
2590         }
2591       /* mark end of this solution */
2592       queue_push(&solutions, 0);
2593       queue_push(&solutions, 0);
2594     }
2595   queue_free(&solution);
2596   queue_free(&problems);
2597   /* copy queue over to solutions */
2598   queue_free(&solv->problems);
2599   queue_clone(&solv->problems, &solutions);
2600
2601   /* bring solver back into problem state */
2602   revert(solv, 1);              /* XXX move to reset_solver? */
2603   reset_solver(solv);
2604
2605   assert(solv->problems.count == solutions.count);
2606   queue_free(&solutions);
2607 }
2608
2609 Id
2610 solver_next_problem(Solver *solv, Id problem)
2611 {
2612   Id *pp;
2613   if (problem == 0)
2614     return solv->problems.count ? 1 : 0;
2615   pp = solv->problems.elements + problem;
2616   while (pp[0] || pp[1])
2617     {
2618       /* solution */
2619       pp += 2;
2620       while (pp[0] || pp[1])
2621         pp += 2;
2622       pp += 2;
2623     }
2624   pp += 2;
2625   problem = pp - solv->problems.elements;
2626   if (problem >= solv->problems.count)
2627     return 0;
2628   return problem + 1;
2629 }
2630
2631 Id
2632 solver_next_solution(Solver *solv, Id problem, Id solution)
2633 {
2634   Id *pp;
2635   if (solution == 0)
2636     {
2637       solution = problem;
2638       pp = solv->problems.elements + solution;
2639       return pp[0] || pp[1] ? solution : 0;
2640     }
2641   pp = solv->problems.elements + solution;
2642   while (pp[0] || pp[1])
2643     pp += 2;
2644   pp += 2;
2645   solution = pp - solv->problems.elements;
2646   return pp[0] || pp[1] ? solution : 0;
2647 }
2648
2649 Id
2650 solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
2651 {
2652   Id *pp;
2653   element = element ? element + 2 : solution;
2654   pp = solv->problems.elements + element;
2655   if (!(pp[0] || pp[1]))
2656     return 0;
2657   *p = pp[0];
2658   *rp = pp[1];
2659   return element;
2660 }
2661
2662
2663 /*
2664  * create obsoletesmap from solver decisions
2665  * required for decision handling
2666  */
2667
2668 Id *
2669 create_obsoletesmap(Solver *solv)
2670 {
2671   Pool *pool = solv->pool;
2672   Repo *installed = solv->installed;
2673   Id p, *obsoletesmap = NULL;
2674   int i;
2675   Solvable *s;
2676
2677   obsoletesmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
2678   if (installed)
2679     {
2680       for (i = 0; i < solv->decisionq.count; i++)
2681         {
2682           Id *pp, n;
2683
2684           n = solv->decisionq.elements[i];
2685           if (n < 0)
2686             continue;
2687           if (n == SYSTEMSOLVABLE)
2688             continue;
2689           s = pool->solvables + n;
2690           if (s->repo == installed)             /* obsoletes don't count for already installed packages */
2691             continue;
2692           FOR_PROVIDES(p, pp, s->name)
2693             if (s->name == pool->solvables[p].name)
2694               {
2695                 if (pool->solvables[p].repo == installed && !obsoletesmap[p])
2696                   {
2697                     obsoletesmap[p] = n;
2698                     obsoletesmap[n]++;
2699                   }
2700               }
2701         }
2702       for (i = 0; i < solv->decisionq.count; i++)
2703         {
2704           Id obs, *obsp;
2705           Id *pp, n;
2706
2707           n = solv->decisionq.elements[i];
2708           if (n < 0)
2709             continue;
2710           if (n == SYSTEMSOLVABLE)
2711             continue;
2712           s = pool->solvables + n;
2713           if (s->repo == installed)             /* obsoletes don't count for already installed packages */
2714             continue;
2715           if (!s->obsoletes)
2716             continue;
2717           obsp = s->repo->idarraydata + s->obsoletes;
2718           while ((obs = *obsp++) != 0)
2719             FOR_PROVIDES(p, pp, obs)
2720               {
2721                 if (pool->solvables[p].repo == installed && !obsoletesmap[p])
2722                   {
2723                     obsoletesmap[p] = n;
2724                     obsoletesmap[n]++;
2725                   }
2726               }
2727         }
2728     }
2729   return obsoletesmap;
2730 }
2731
2732 /*
2733  * printdecisions
2734  */
2735   
2736
2737 void
2738 printdecisions(Solver *solv)
2739 {
2740   Pool *pool = solv->pool;
2741   Repo *installed = solv->installed;
2742   Id p, *obsoletesmap = create_obsoletesmap( solv );
2743   int i;
2744   Solvable *s;
2745
2746   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions -----\n");  
2747
2748   /* print solvables to be erased */
2749
2750   if (installed)
2751     {
2752       FOR_REPO_SOLVABLES(installed, p, s)
2753         {
2754           if (solv->decisionmap[p] >= 0)
2755             continue;
2756           if (obsoletesmap[p])
2757             continue;
2758           POOL_DEBUG(SAT_DEBUG_RESULT, "erase   %s\n", solvable2str(pool, s));
2759         }
2760     }
2761
2762   /* print solvables to be installed */
2763
2764   for (i = 0; i < solv->decisionq.count; i++)
2765     {
2766       int j;
2767       p = solv->decisionq.elements[i];
2768       if (p < 0)
2769         {
2770             IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2771             {   
2772               p = -p;
2773               s = pool->solvables + p;      
2774               POOL_DEBUG(SAT_DEBUG_SCHUBI, "level of %s is %d\n", solvable2str(pool, s), p);
2775             }
2776             continue;
2777         }
2778       if (p == SYSTEMSOLVABLE)
2779         {
2780             POOL_DEBUG(SAT_DEBUG_SCHUBI, "SYSTEMSOLVABLE\n");
2781             continue;
2782         }
2783       s = pool->solvables + p;
2784       if (installed && s->repo == installed)
2785         continue;
2786
2787       if (!obsoletesmap[p])
2788         {
2789           POOL_DEBUG(SAT_DEBUG_RESULT, "install %s", solvable2str(pool, s));
2790         }
2791       else
2792         {
2793           POOL_DEBUG(SAT_DEBUG_RESULT, "update  %s", solvable2str(pool, s));
2794           POOL_DEBUG(SAT_DEBUG_RESULT, "  (obsoletes");
2795           for (j = installed->start; j < installed->end; j++)
2796             if (obsoletesmap[j] == p)
2797               POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + j));
2798           POOL_DEBUG(SAT_DEBUG_RESULT, ")");
2799         }
2800       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
2801     }
2802
2803   sat_free(obsoletesmap);
2804
2805   if (solv->suggestions.count)
2806     {
2807       POOL_DEBUG(SAT_DEBUG_RESULT, "\nsuggested packages:\n");
2808       for (i = 0; i < solv->suggestions.count; i++)
2809         {
2810           s = pool->solvables + solv->suggestions.elements[i];
2811           POOL_DEBUG(SAT_DEBUG_RESULT, "- %s\n", solvable2str(pool, s));
2812         }
2813     }
2814   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions end -----\n");    
2815 }
2816
2817 /* this is basically the reverse of addrpmrulesforsolvable */
2818 SolverProbleminfo
2819 solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
2820 {
2821   Pool *pool = solv->pool;
2822   Repo *installed = solv->installed;
2823   Rule *r;
2824   Solvable *s;
2825   int dontfix = 0;
2826   Id p, *pp, req, *reqp, con, *conp, obs, *obsp, *dp;
2827   
2828   assert(rid < solv->weakrules);
2829   if (rid >= solv->systemrules)
2830     {
2831       *depp = 0;
2832       *sourcep = solv->installed->start + (rid - solv->systemrules);
2833       *targetp = 0;
2834       return SOLVER_PROBLEM_UPDATE_RULE;
2835     }
2836   if (rid >= solv->jobrules)
2837     {
2838      
2839       r = solv->rules + rid;
2840       p = solv->ruletojob.elements[rid - solv->jobrules];
2841       *depp = job->elements[p + 1];
2842       *sourcep = p;
2843       *targetp = job->elements[p];
2844       if (r->d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
2845         return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
2846       return SOLVER_PROBLEM_JOB_RULE;
2847     }
2848   if (rid < 0)
2849     {
2850       /* a rpm rule assertion */
2851       assert(rid != -SYSTEMSOLVABLE);
2852       s = pool->solvables - rid;
2853       if (installed && !solv->fixsystem && s->repo == installed)
2854         dontfix = 1;
2855       assert(!dontfix); /* dontfix packages never have a neg assertion */
2856       /* see why the package is not installable */
2857       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
2858         return SOLVER_PROBLEM_NOT_INSTALLABLE;
2859       /* check requires */
2860       assert(s->requires);
2861       reqp = s->repo->idarraydata + s->requires;
2862       while ((req = *reqp++) != 0)
2863         {
2864           if (req == SOLVABLE_PREREQMARKER)
2865             continue;
2866           dp = pool_whatprovides(pool, req);
2867           if (*dp == 0)
2868             break;
2869         }
2870       assert(req);
2871       *depp = req;
2872       *sourcep = -rid;
2873       *targetp = 0;
2874       return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP;
2875     }
2876   r = solv->rules + rid;
2877   assert(r->p < 0);
2878   if (r->d == 0 && r->w2 == 0)
2879     {
2880       /* an assertion. we don't store them as rpm rules, so
2881        * can't happen */
2882       assert(0);
2883     }
2884   s = pool->solvables - r->p;
2885   if (installed && !solv->fixsystem && s->repo == installed)
2886     dontfix = 1;
2887   if (r->d == 0 && r->w2 < 0)
2888     {
2889       /* a package conflict */
2890       Solvable *s2 = pool->solvables - r->w2;
2891       int dontfix2 = 0;
2892
2893       if (installed && !solv->fixsystem && s2->repo == installed)
2894         dontfix2 = 1;
2895
2896       /* if both packages have the same name and at least one of them
2897        * is not installed, they conflict */
2898       if (s->name == s2->name && (!installed || (s->repo != installed || s2->repo != installed)))
2899         {
2900           *depp = 0;
2901           *sourcep = -r->p;
2902           *targetp = -r->w2;
2903           return SOLVER_PROBLEM_SAME_NAME;
2904         }
2905
2906       /* check conflicts in both directions */
2907       if (s->conflicts)
2908         {
2909           conp = s->repo->idarraydata + s->conflicts;
2910           while ((con = *conp++) != 0)
2911             {
2912               FOR_PROVIDES(p, pp, con) 
2913                 {
2914                   if (dontfix && pool->solvables[p].repo == installed)
2915                     continue;
2916                   if (p != -r->w2)
2917                     continue;
2918                   *depp = con;
2919                   *sourcep = -r->p;
2920                   *targetp = p;
2921                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
2922                 }
2923             }
2924         }
2925       if (s2->conflicts)
2926         {
2927           conp = s2->repo->idarraydata + s2->conflicts;
2928           while ((con = *conp++) != 0)
2929             {
2930               FOR_PROVIDES(p, pp, con) 
2931                 {
2932                   if (dontfix2 && pool->solvables[p].repo == installed)
2933                     continue;
2934                   if (p != -r->p)
2935                     continue;
2936                   *depp = con;
2937                   *sourcep = -r->w2;
2938                   *targetp = p;
2939                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
2940                 }
2941             }
2942         }
2943       /* check obsoletes in both directions */
2944       if ((!installed || s->repo != installed) && s->obsoletes)
2945         {
2946           obsp = s->repo->idarraydata + s->obsoletes;
2947           while ((obs = *obsp++) != 0)
2948             {
2949               FOR_PROVIDES(p, pp, obs)
2950                 {
2951                   if (p != -r->w2)
2952                     continue;
2953                   *depp = obs;
2954                   *sourcep = -r->p;
2955                   *targetp = p;
2956                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
2957                 }
2958             }
2959         }
2960       if ((!installed || s2->repo != installed) && s2->obsoletes)
2961         {
2962           obsp = s2->repo->idarraydata + s2->obsoletes;
2963           while ((obs = *obsp++) != 0)
2964             {
2965               FOR_PROVIDES(p, pp, obs)
2966                 {
2967                   if (p != -r->p)
2968                     continue;
2969                   *depp = obs;
2970                   *sourcep = -r->w2;
2971                   *targetp = p;
2972                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
2973                 }
2974             }
2975         }
2976       /* all cases checked, can't happen */
2977       assert(0);
2978     }
2979   /* simple requires */
2980   assert(s->requires);
2981   reqp = s->repo->idarraydata + s->requires;
2982   while ((req = *reqp++) != 0)
2983     {
2984       if (req == SOLVABLE_PREREQMARKER)
2985         continue;
2986       dp = pool_whatprovides(pool, req);
2987       if (r->d == 0)
2988         {
2989           if (*dp == r->w2 && dp[1] == 0)
2990             break;
2991         }
2992       else if (dp - pool->whatprovidesdata == r->d)
2993         break;
2994     }
2995   assert(req);
2996   *depp = req;
2997   *sourcep = -r->p;
2998   *targetp = 0;
2999   return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE;
3000 }
3001
3002 static void
3003 findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
3004 {
3005   Id rid;
3006   Id lreqr, lconr, lsysr, ljobr;
3007   Rule *r;
3008   int reqassert = 0;
3009
3010   lreqr = lconr = lsysr = ljobr = 0;
3011   while ((rid = solv->learnt_pool.elements[idx++]) != 0)
3012     {
3013       if (rid >= solv->learntrules)
3014         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
3015       else if (rid >= solv->systemrules)
3016         {
3017           if (!*sysrp)
3018             *sysrp = rid;
3019         }
3020       else if (rid >= solv->jobrules)
3021         {
3022           if (!*jobrp)
3023             *jobrp = rid;
3024         }
3025       else if (rid >= 0)
3026         {
3027           r = solv->rules + rid;
3028           if (!r->d && r->w2 < 0)
3029             {
3030               if (!*conrp)
3031                 *conrp = rid;
3032             }
3033           else
3034             {
3035               if (!*reqrp)
3036                 *reqrp = rid;
3037             }
3038         }
3039       else
3040         {
3041           /* assertion, counts as require rule */
3042           /* ignore system solvable as we need useful info */
3043           if (rid == -SYSTEMSOLVABLE)
3044             continue;
3045           if (!*reqrp || !reqassert)
3046             {
3047               *reqrp = rid;
3048               reqassert = 1;
3049             }
3050         }
3051     }
3052   if (!*reqrp && lreqr)
3053     *reqrp = lreqr;
3054   if (!*conrp && lconr)
3055     *conrp = lconr;
3056   if (!*jobrp && ljobr)
3057     *jobrp = ljobr;
3058   if (!*sysrp && lsysr)
3059     *sysrp = lsysr;
3060 }
3061
3062 Id
3063 solver_findproblemrule(Solver *solv, Id problem)
3064 {
3065   Id reqr, conr, sysr, jobr;
3066   Id idx = solv->problems.elements[problem - 1];
3067   reqr = conr = sysr = jobr = 0;
3068   findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
3069   if (reqr)
3070     return reqr;
3071   if (conr)
3072     return conr;
3073   if (sysr)
3074     return sysr;
3075   if (jobr)
3076     return jobr;
3077   assert(0);
3078 }
3079
3080 void
3081 printprobleminfo(Solver *solv, Queue *job, Id problem)
3082 {
3083   Pool *pool = solv->pool;
3084   Id probr;
3085   Id dep, source, target;
3086   Solvable *s, *s2;
3087
3088   probr = solver_findproblemrule(solv, problem);
3089   switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
3090     {
3091     case SOLVER_PROBLEM_UPDATE_RULE:
3092       s = pool_id2solvable(pool, source);
3093       POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
3094       return;
3095     case SOLVER_PROBLEM_JOB_RULE:
3096       POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n");
3097       return;
3098     case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
3099       POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides requested %s\n", dep2str(pool, dep));
3100       return;
3101     case SOLVER_PROBLEM_NOT_INSTALLABLE:
3102       s = pool_id2solvable(pool, source);
3103       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s));
3104       return;
3105     case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
3106       s = pool_id2solvable(pool, source);
3107       POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
3108       return;
3109     case SOLVER_PROBLEM_SAME_NAME:
3110       s = pool_id2solvable(pool, source);
3111       s2 = pool_id2solvable(pool, target);
3112       POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
3113       return;
3114     case SOLVER_PROBLEM_PACKAGE_CONFLICT:
3115       s = pool_id2solvable(pool, source);
3116       s2 = pool_id2solvable(pool, target);
3117       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
3118       return;
3119     case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
3120       s = pool_id2solvable(pool, source);
3121       s2 = pool_id2solvable(pool, target);
3122       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
3123       return;
3124     case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
3125       s = pool_id2solvable(pool, source);
3126       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
3127       return;
3128     }
3129 }
3130
3131 void
3132 printsolutions(Solver *solv, Queue *job)
3133 {
3134   Pool *pool = solv->pool;
3135   int pcnt;
3136   Id p, rp, what;
3137   Id problem, solution, element;
3138   Solvable *s, *sd;
3139
3140   POOL_DEBUG(SAT_DEBUG_RESULT, "Encountered problems! Here are the solutions:\n\n");
3141   pcnt = 1;
3142   problem = 0;
3143   while ((problem = solver_next_problem(solv, problem)) != 0)
3144     {
3145       POOL_DEBUG(SAT_DEBUG_RESULT, "Problem %d:\n", pcnt++);
3146       POOL_DEBUG(SAT_DEBUG_RESULT, "====================================\n");
3147       printprobleminfo(solv, job, problem);
3148       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
3149       solution = 0;
3150       while ((solution = solver_next_solution(solv, problem, solution)) != 0)
3151         {
3152           element = 0;
3153           while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
3154             {
3155               if (p == 0)
3156                 {
3157                   /* job, rp is index into job queue */
3158                   what = job->elements[rp];
3159                   switch (job->elements[rp - 1])
3160                     {
3161                     case SOLVER_INSTALL_SOLVABLE:
3162                       s = pool->solvables + what;
3163                       if (solv->installed && s->repo == solv->installed)
3164                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, s));
3165                       else
3166                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solvable2str(pool, s));
3167                       break;
3168                     case SOLVER_ERASE_SOLVABLE:
3169                       s = pool->solvables + what;
3170                       if (solv->installed && s->repo == solv->installed)
3171                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solvable2str(pool, s));
3172                       else
3173                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, s));
3174                       break;
3175                     case SOLVER_INSTALL_SOLVABLE_NAME:
3176                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", id2str(pool, what));
3177                       break;
3178                     case SOLVER_ERASE_SOLVABLE_NAME:
3179                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", id2str(pool, what));
3180                       break;
3181                     case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3182                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable providing %s\n", dep2str(pool, what));
3183                       break;
3184                     case SOLVER_ERASE_SOLVABLE_PROVIDES:
3185                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables providing %s\n", dep2str(pool, what));
3186                       break;
3187                     case SOLVER_INSTALL_SOLVABLE_UPDATE:
3188                       s = pool->solvables + what;
3189                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solvable2str(pool, s));
3190                       break;
3191                     default:
3192                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do something different\n");
3193                       break;
3194                     }
3195                 }
3196               else
3197                 {
3198                   /* policy, replace p with rp */
3199                   s = pool->solvables + p;
3200                   sd = rp ? pool->solvables + rp : 0;
3201                   if (sd)
3202                     {
3203                       int gotone = 0;
3204                       if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
3205                         {
3206                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3207                           gotone = 1;
3208                         }
3209                       if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(pool, s, sd))
3210                         {
3211                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3212                           gotone = 1;
3213                         }
3214                       if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(pool, s, sd))
3215                         {
3216                           if (sd->vendor)
3217                             POOL_DEBUG(SAT_DEBUG_RESULT, "- allow vendor change from '%s' (%s) to '%s' (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), id2str(pool, sd->vendor), solvable2str(pool, sd));
3218                           else
3219                             POOL_DEBUG(SAT_DEBUG_RESULT, "- allow vendor change from '%s' (%s) to no vendor (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), solvable2str(pool, sd));
3220                           gotone = 1;
3221                         }
3222                       if (!gotone)
3223                         POOL_DEBUG(SAT_DEBUG_RESULT, "- allow replacement of %s with %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3224                     }
3225                   else
3226                     {
3227                       POOL_DEBUG(SAT_DEBUG_RESULT, "- allow deinstallation of %s\n", solvable2str(pool, s));
3228                     }
3229
3230                 }
3231             }
3232           POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
3233         }
3234     }
3235 }
3236
3237
3238 /* for each installed solvable find which packages with *different* names
3239  * obsolete the solvable.
3240  * this index is used in policy_findupdatepackages if noupdateprovide is set.
3241  */
3242
3243 static void
3244 create_obsolete_index(Solver *solv)
3245 {
3246   Pool *pool = solv->pool;
3247   Solvable *s;
3248   Repo *installed = solv->installed;
3249   Id p, *pp, obs, *obsp, *obsoletes, *obsoletes_data;
3250   int i, n;
3251
3252   if (!installed || !installed->nsolvables)
3253     return;
3254   /* create reverse obsoletes map for installed solvables */
3255   solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
3256   for (i = 1; i < pool->nsolvables; i++)
3257     {
3258       s = pool->solvables + i;
3259       if (s->repo == installed)
3260         continue;
3261       if (!s->obsoletes)
3262         continue;
3263       if (!pool_installable(pool, s))
3264         continue;
3265       obsp = s->repo->idarraydata + s->obsoletes;
3266       while ((obs = *obsp++) != 0)
3267         FOR_PROVIDES(p, pp, obs)
3268           {
3269             if (pool->solvables[p].repo != installed)
3270               continue;
3271             if (pool->solvables[p].name == s->name)
3272               continue;
3273             obsoletes[p - installed->start]++;
3274           }
3275     }
3276   n = 0;
3277   for (i = 0; i < installed->nsolvables; i++)
3278     if (obsoletes[i])
3279       {
3280         n += obsoletes[i] + 1;
3281         obsoletes[i] = n;
3282       }
3283   solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
3284   POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
3285   for (i = pool->nsolvables - 1; i > 0; i--)
3286     {
3287       s = pool->solvables + i;
3288       if (s->repo == installed)
3289         continue;
3290       if (!s->obsoletes)
3291         continue;
3292       if (!pool_installable(pool, s))
3293         continue;
3294       obsp = s->repo->idarraydata + s->obsoletes;
3295       while ((obs = *obsp++) != 0)
3296         FOR_PROVIDES(p, pp, obs)
3297           {
3298             if (pool->solvables[p].repo != installed)
3299               continue;
3300             if (pool->solvables[p].name == s->name)
3301               continue;
3302             p -= installed->start;
3303             if (obsoletes_data[obsoletes[p]] != i)
3304               obsoletes_data[--obsoletes[p]] = i;
3305           }
3306     }
3307 }
3308
3309
3310 /*-----------------------------------------------------------------*/
3311 /* main() */
3312
3313 /*
3314  *
3315  * solve job queue
3316  *
3317  */
3318
3319 void
3320 solver_solve(Solver *solv, Queue *job)
3321 {
3322   Pool *pool = solv->pool;
3323   Repo *installed = solv->installed;
3324   int i;
3325   int oldnrules;
3326   Map addedmap;                /* '1' == have rpm-rules for solvable */
3327   Id how, what, p, *pp, d;
3328   Queue q;
3329   Solvable *s;
3330
3331   /* create whatprovides if not already there */
3332   if (!pool->whatprovides)
3333     pool_createwhatprovides(pool);
3334
3335   /* create obsolete index if needed */
3336   if (solv->noupdateprovide)
3337     create_obsolete_index(solv);
3338
3339   /*
3340    * create basic rule set of all involved packages
3341    * use addedmap bitmap to make sure we don't create rules twice
3342    * 
3343    */
3344
3345   map_init(&addedmap, pool->nsolvables);
3346   queue_init(&q);
3347   
3348   /*
3349    * always install our system solvable
3350    */
3351   MAPSET(&addedmap, SYSTEMSOLVABLE);
3352   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
3353   queue_push(&solv->decisionq_why, 0);
3354   solv->decisionmap[SYSTEMSOLVABLE] = 1;
3355
3356   /*
3357    * create rules for all package that could be involved with the solving
3358    * so called: rpm rules
3359    * 
3360    */
3361   if (installed)
3362     {
3363       oldnrules = solv->nrules;
3364       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
3365       FOR_REPO_SOLVABLES(installed, p, s)
3366         addrpmrulesforsolvable(solv, s, &addedmap);
3367       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3368       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
3369       oldnrules = solv->nrules;
3370       FOR_REPO_SOLVABLES(installed, p, s)
3371         addrpmrulesforupdaters(solv, s, &addedmap, 1);
3372       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3373     }
3374
3375   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for packages involved with a job ***\n");
3376   oldnrules = solv->nrules;
3377   for (i = 0; i < job->count; i += 2)
3378     {
3379       how = job->elements[i];
3380       what = job->elements[i + 1];
3381
3382       switch(how)
3383         {
3384         case SOLVER_INSTALL_SOLVABLE:
3385           addrpmrulesforsolvable(solv, pool->solvables + what, &addedmap);
3386           break;
3387         case SOLVER_INSTALL_SOLVABLE_NAME:
3388         case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3389           FOR_PROVIDES(p, pp, what)
3390             {
3391               /* if by name, ensure that the name matches */
3392               if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
3393                 continue;
3394               addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3395             }
3396           break;
3397         case SOLVER_INSTALL_SOLVABLE_UPDATE:
3398           /* dont allow downgrade */
3399           addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
3400           break;
3401         }
3402     }
3403   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3404
3405   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
3406
3407   oldnrules = solv->nrules;
3408   addrpmrulesforweak(solv, &addedmap);
3409   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3410
3411   IF_POOLDEBUG (SAT_DEBUG_STATS)
3412     {
3413       int possible = 0, installable = 0;
3414       for (i = 1; i < pool->nsolvables; i++)
3415         {
3416           if (pool_installable(pool, pool->solvables + i))
3417             installable++;
3418           if (MAPTST(&addedmap, i))
3419             possible++;
3420         }
3421       POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving (rules has been generated for)\n", possible, installable);
3422     }
3423
3424   /*
3425    * first pass done, we now have all the rpm rules we need.
3426    * unify existing rules before going over all job rules and
3427    * policy rules.
3428    * at this point the system is always solvable,
3429    * as an empty system (remove all packages) is a valid solution
3430    */
3431   
3432   unifyrules(solv);     /* remove duplicate rpm rules */
3433   solv->directdecisions = solv->decisionq.count;
3434
3435   POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
3436   IF_POOLDEBUG (SAT_DEBUG_SCHUBI) 
3437     printdecisions (solv);
3438
3439   /*
3440    * now add all job rules
3441    */
3442
3443   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add JOB rules ***\n");  
3444   
3445   solv->jobrules = solv->nrules;
3446
3447   for (i = 0; i < job->count; i += 2)
3448     {
3449       oldnrules = solv->nrules;
3450
3451       how = job->elements[i];
3452       what = job->elements[i + 1];
3453       switch(how)
3454         {
3455         case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
3456           s = pool->solvables + what;
3457           POOL_DEBUG(SAT_DEBUG_JOB, "job: install solvable %s\n", solvable2str(pool, s));
3458           addrule(solv, what, 0);                       /* install by Id */
3459           queue_push(&solv->ruletojob, i);
3460           break;
3461         case SOLVER_ERASE_SOLVABLE:
3462           s = pool->solvables + what;
3463           POOL_DEBUG(SAT_DEBUG_JOB, "job: erase solvable %s\n", solvable2str(pool, s));
3464           addrule(solv, -what, 0);                      /* remove by Id */
3465           queue_push(&solv->ruletojob, i);
3466           break;
3467         case SOLVER_INSTALL_SOLVABLE_NAME:              /* install by capability */
3468         case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3469           if (how == SOLVER_INSTALL_SOLVABLE_NAME)
3470             POOL_DEBUG(SAT_DEBUG_JOB, "job: install name %s\n", id2str(pool, what));
3471           if (how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
3472             POOL_DEBUG(SAT_DEBUG_JOB, "job: install provides %s\n", dep2str(pool, what));
3473           queue_empty(&q);
3474           FOR_PROVIDES(p, pp, what)
3475             {
3476               /* if by name, ensure that the name matches */
3477               if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
3478                 continue;
3479               queue_push(&q, p);
3480             }
3481           if (!q.count) 
3482             {
3483               /* no provider, make this an impossible rule */
3484               queue_push(&q, -SYSTEMSOLVABLE);
3485             }
3486
3487           p = queue_shift(&q);         /* get first provider */
3488           if (!q.count)
3489             d = 0;                     /* single provider ? -> make assertion */
3490           else
3491             d = pool_queuetowhatprovides(pool, &q);   /* get all providers */
3492           addrule(solv, p, d);         /* add 'requires' rule */
3493           queue_push(&solv->ruletojob, i);
3494           break;
3495         case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
3496         case SOLVER_ERASE_SOLVABLE_PROVIDES:
3497           if (how == SOLVER_ERASE_SOLVABLE_NAME)
3498             POOL_DEBUG(SAT_DEBUG_JOB, "job: erase name %s\n", id2str(pool, what));
3499           if (how == SOLVER_ERASE_SOLVABLE_PROVIDES)
3500             POOL_DEBUG(SAT_DEBUG_JOB, "job: erase provides %s\n", dep2str(pool, what));
3501           FOR_PROVIDES(p, pp, what)
3502             {
3503               /* if by name, ensure that the name matches */
3504               if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
3505                 continue;
3506               addrule(solv, -p, 0);  /* add 'remove' rule */
3507               queue_push(&solv->ruletojob, i);
3508             }
3509           break;
3510         case SOLVER_INSTALL_SOLVABLE_UPDATE:              /* find update for solvable */
3511           s = pool->solvables + what;
3512           POOL_DEBUG(SAT_DEBUG_JOB, "job: update %s\n", solvable2str(pool, s));
3513           addupdaterule(solv, s, 0);
3514           queue_push(&solv->ruletojob, i);
3515           break;
3516         }
3517       IF_POOLDEBUG (SAT_DEBUG_JOB)
3518         {
3519           int j;
3520           if (solv->nrules == oldnrules)
3521             POOL_DEBUG(SAT_DEBUG_JOB, " - no rule created");
3522           for (j = oldnrules; j < solv->nrules; j++)
3523             {
3524               POOL_DEBUG(SAT_DEBUG_JOB, " - job ");
3525               printrule(solv, SAT_DEBUG_JOB, solv->rules + j);
3526             }
3527         }
3528     }
3529   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3530
3531   /*
3532    * now add system rules
3533    * 
3534    */
3535
3536   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add system rules ***\n");
3537   
3538   
3539   solv->systemrules = solv->nrules;
3540
3541   /*
3542    * create rules for updating installed solvables
3543    * 
3544    */
3545   
3546   if (installed && !solv->allowuninstall)
3547     {                                  /* loop over all installed solvables */
3548       /* we create all update rules, but disable some later on depending on the job */
3549       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3550         if (s->repo == installed)
3551           addupdaterule(solv, s, 0); /* allowall = 0 */
3552         else
3553           addupdaterule(solv, 0, 0);    /* create dummy rule;  allowall = 0  */
3554       /* consistency check: we added a rule for _every_ system solvable */
3555       assert(solv->nrules - solv->systemrules == installed->end - installed->start);
3556     }
3557
3558   /* create special weak system rules */
3559   /* those are used later on to keep a version of the installed packages in
3560      best effort mode */
3561   if (installed && installed->nsolvables)
3562     {
3563       solv->weaksystemrules = sat_calloc(installed->end - installed->start, sizeof(Id));
3564       FOR_REPO_SOLVABLES(installed, p, s)
3565         {
3566           policy_findupdatepackages(solv, s, &q, 1);
3567           if (q.count)
3568             solv->weaksystemrules[p - installed->start] = pool_queuetowhatprovides(pool, &q);
3569         }
3570     }
3571
3572   /* free unneeded memory */
3573   map_free(&addedmap);
3574   queue_free(&q);
3575
3576   solv->weakrules = solv->nrules;
3577
3578   /* try real hard to keep packages installed */
3579   if (0)
3580     {
3581       FOR_REPO_SOLVABLES(installed, p, s)
3582         {
3583           /* FIXME: can't work with refine_suggestion! */
3584           /* need to always add the rule but disable it */
3585           if (MAPTST(&solv->noupdate, p - installed->start))
3586             continue;
3587           d = solv->weaksystemrules[p - installed->start];
3588           addrule(solv, p, d);
3589         }
3590     }
3591
3592   /* all new rules are learnt after this point */
3593   solv->learntrules = solv->nrules;
3594
3595   /*
3596    * solve !
3597    * 
3598    */
3599   
3600   disableupdaterules(solv, job, -1);
3601   makeruledecisions(solv);
3602
3603   POOL_DEBUG(SAT_DEBUG_STATS, "problems so far: %d\n", solv->problems.count);
3604
3605   run_solver(solv, 1, 1);
3606
3607   /* find suggested packages */
3608   if (!solv->problems.count)
3609     {
3610       Id sug, *sugp, p, *pp;
3611
3612       /* create map of all suggests that are still open */
3613       solv->recommends_index = -1;
3614       MAPZERO(&solv->suggestsmap);
3615       for (i = 0; i < solv->decisionq.count; i++)
3616         {
3617           p = solv->decisionq.elements[i];
3618           if (p < 0)
3619             continue;
3620           s = pool->solvables + p;
3621           if (s->suggests)
3622             {
3623               sugp = s->repo->idarraydata + s->suggests;
3624               while ((sug = *sugp++) != 0)
3625                 {
3626                   FOR_PROVIDES(p, pp, sug)
3627                     if (solv->decisionmap[p] > 0)
3628                       break;
3629                   if (p)
3630                     continue;   /* already fulfilled */
3631                   FOR_PROVIDES(p, pp, sug)
3632                     MAPSET(&solv->suggestsmap, p);
3633                 }
3634             }
3635         }
3636       for (i = 1; i < pool->nsolvables; i++)
3637         {
3638           if (solv->decisionmap[i] != 0)
3639             continue;
3640           s = pool->solvables + i;
3641           if (!MAPTST(&solv->suggestsmap, i))
3642             {
3643               if (!s->enhances)
3644                 continue;
3645               if (!pool_installable(pool, s))
3646                 continue;
3647               if (!solver_is_enhancing(solv, s))
3648                 continue;
3649             }
3650           queue_push(&solv->suggestions, i);
3651         }
3652       policy_filter_unwanted(solv, &solv->suggestions, 0, POLICY_MODE_SUGGEST);
3653     }
3654
3655   if (solv->problems.count)
3656     problems_to_solutions(solv, job);
3657 }
3658