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