- fix support for splitprovides
[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           printWatches(solv, SAT_DEBUG_SCHUBI);
1329         }
1330
1331       for (rp = watches + pkg; *rp; rp = nrp)
1332         {
1333           r = solv->rules + *rp;
1334           
1335           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1336             {
1337               POOL_DEBUG(SAT_DEBUG_PROPAGATE,"  watch triggered ");
1338               printrule(solv, SAT_DEBUG_PROPAGATE, r);
1339             }
1340           
1341           if (pkg == r->w1)
1342             {
1343               ow = r->w2; /* regard the second watchpoint to come to a solution */
1344               nrp = &r->n1;
1345             }
1346           else
1347             {
1348               ow = r->w1; /* regard the first watchpoint to come to a solution */
1349               nrp = &r->n2;
1350             }
1351           /* if clause is TRUE, nothing to do */
1352           if (DECISIONMAP_TRUE(ow))
1353             continue;
1354
1355           if (r->d)
1356             {
1357               /* not a binary clause, check if we need to move our watch */
1358               /* search for a literal that is not ow and not false */
1359               /* (true is also ok, in that case the rule is fulfilled) */
1360               if (r->p && r->p != ow && !DECISIONMAP_TRUE(-r->p))
1361                 p = r->p;
1362               else
1363                 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
1364                   if (p != ow && !DECISIONMAP_TRUE(-p))
1365                     break;
1366               if (p)
1367                 {
1368                   /* p is free to watch, move watch to p */
1369                   IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1370                     {
1371                       if (p > 0)
1372                         POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
1373                       else
1374                         POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
1375                     }
1376                   *rp = *nrp;
1377                   nrp = rp;
1378                   if (pkg == r->w1)
1379                     {
1380                       r->w1 = p;
1381                       r->n1 = watches[p];
1382                     }
1383                   else
1384                     {
1385                       r->w2 = p;
1386                       r->n2 = watches[p];
1387                     }
1388                   watches[p] = r - solv->rules;
1389                   continue;
1390                 }
1391             }
1392           /* unit clause found, set other watch to TRUE */
1393           if (DECISIONMAP_TRUE(-ow))
1394             return r;           /* eek, a conflict! */
1395           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1396             {
1397               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "   unit ");
1398               printrule(solv, SAT_DEBUG_PROPAGATE, r);
1399             }
1400           if (ow > 0)
1401             decisionmap[ow] = level;
1402           else
1403             decisionmap[-ow] = -level;
1404           queue_push(&solv->decisionq, ow);
1405           queue_push(&solv->decisionq_why, r - solv->rules);
1406           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
1407             {
1408               Solvable *s = pool->solvables + (ow > 0 ? ow : -ow);
1409               if (ow > 0)
1410                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvable2str(pool, s));
1411               else
1412                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvable2str(pool, s));
1413             }
1414         }
1415     }
1416   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate end-----\n");
1417   
1418   return 0;     /* all is well */
1419 }
1420
1421
1422 /*-----------------------------------------------------------------*/
1423 /* Analysis */
1424
1425 /*
1426  * analyze
1427  *   and learn
1428  */
1429
1430 static int
1431 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
1432 {
1433   Pool *pool = solv->pool;
1434   Queue r;
1435   int rlevel = 1;
1436   Map seen;             /* global? */
1437   Id v, vv, *dp, why;
1438   int l, i, idx;
1439   int num = 0, l1num = 0;
1440   int learnt_why = solv->learnt_pool.count;
1441   Id *decisionmap = solv->decisionmap;
1442  
1443   queue_init(&r);
1444
1445   POOL_DEBUG(SAT_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
1446   map_init(&seen, pool->nsolvables);
1447   idx = solv->decisionq.count;
1448   for (;;)
1449     {
1450       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1451         printruleclass(solv, SAT_DEBUG_ANALYZE, c);
1452       queue_push(&solv->learnt_pool, c - solv->rules);
1453       dp = c->d ? pool->whatprovidesdata + c->d : 0;
1454       /* go through all literals of the rule */
1455       for (i = -1; ; i++)
1456         {
1457           if (i == -1)
1458             v = c->p;
1459           else if (c->d == 0)
1460             v = i ? 0 : c->w2;
1461           else
1462             v = *dp++;
1463           if (v == 0)
1464             break;
1465
1466           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1467             continue;
1468           vv = v > 0 ? v : -v;
1469           if (MAPTST(&seen, vv))
1470             continue;
1471           l = solv->decisionmap[vv];
1472           if (l < 0)
1473             l = -l;
1474           if (l == 1)
1475             {
1476               /* a level 1 literal, mark it for later */
1477               MAPSET(&seen, vv);        /* mark for scanning in level 1 phase */
1478               l1num++;
1479               continue;
1480             }
1481           MAPSET(&seen, vv);
1482           if (l == level)
1483             num++;                      /* need to do this one as well */
1484           else
1485             {
1486               queue_push(&r, v);
1487               if (l > rlevel)
1488                 rlevel = l;
1489             }
1490         }
1491       assert(num > 0);
1492       for (;;)
1493         {
1494           v = solv->decisionq.elements[--idx];
1495           vv = v > 0 ? v : -v;
1496           if (MAPTST(&seen, vv))
1497             break;
1498         }
1499       c = solv->rules + solv->decisionq_why.elements[idx];
1500       MAPCLR(&seen, vv);
1501       if (--num == 0)
1502         break;
1503     }
1504   *pr = -v;     /* so that v doesn't get lost */
1505
1506   /* add involved level 1 rules */
1507   if (l1num)
1508     {
1509       POOL_DEBUG(SAT_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
1510       idx++;
1511       while (idx)
1512         {
1513           v = solv->decisionq.elements[--idx];
1514           vv = v > 0 ? v : -v;
1515           if (!MAPTST(&seen, vv))
1516             continue;
1517           why = solv->decisionq_why.elements[idx];
1518           if (!why)
1519             {
1520               queue_push(&solv->learnt_pool, -vv); 
1521               IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1522                 {
1523                   POOL_DEBUG(SAT_DEBUG_ANALYZE, "RPM ASSERT Rule:\n");
1524                   printruleelement(solv, SAT_DEBUG_ANALYZE, 0, v);
1525                 }
1526               continue;
1527             }
1528           queue_push(&solv->learnt_pool, why);
1529           c = solv->rules + why;
1530           IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1531             printruleclass(solv, SAT_DEBUG_ANALYZE, c);
1532           for (i = -1; ; i++)
1533             {
1534               if (i == -1)
1535                 v = c->p;
1536               else if (c->d == 0)
1537                 v = i ? 0 : c->w2;
1538               else
1539                 v = *dp++;
1540               if (v == 0)
1541                 break;
1542               if (DECISIONMAP_TRUE(v))  /* the one true literal */
1543                 continue;
1544               vv = v > 0 ? v : -v;
1545               l = solv->decisionmap[vv];
1546               if (l != 1 && l != -1)
1547                 continue;
1548               MAPSET(&seen, vv);
1549             }
1550         }
1551     }
1552   map_free(&seen);
1553
1554   if (r.count == 0)
1555     *dr = 0;
1556   else if (r.count == 1 && r.elements[0] < 0)
1557     *dr = r.elements[0];
1558   else
1559     *dr = pool_queuetowhatprovides(pool, &r);
1560   IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1561     {
1562       POOL_DEBUG(SAT_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
1563       printruleelement(solv, SAT_DEBUG_ANALYZE, 0, *pr);
1564       for (i = 0; i < r.count; i++)
1565         printruleelement(solv, SAT_DEBUG_ANALYZE, 0, r.elements[i]);
1566     }
1567   /* push end marker on learnt reasons stack */
1568   queue_push(&solv->learnt_pool, 0);
1569   if (whyp)
1570     *whyp = learnt_why;
1571   return rlevel;
1572 }
1573
1574
1575 /*
1576  * reset_solver
1577  * reset the solver decisions to right after the rpm rules.
1578  * called after rules have been enabled/disabled
1579  */
1580
1581 static void
1582 reset_solver(Solver *solv)
1583 {
1584   Pool *pool = solv->pool;
1585   int i;
1586   Id v;
1587
1588   /* rewind decisions to direct rpm rule assertions */
1589   for (i = solv->decisionq.count - 1; i >= solv->directdecisions; i--)
1590     {
1591       v = solv->decisionq.elements[i];
1592       solv->decisionmap[v > 0 ? v : -v] = 0;
1593     }
1594
1595   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions done reduced from %d to %d\n", solv->decisionq.count, solv->directdecisions);
1596
1597   solv->decisionq_why.count = solv->directdecisions;
1598   solv->decisionq.count = solv->directdecisions;
1599   solv->recommends_index = -1;
1600   solv->propagate_index = 0;
1601
1602   /* adapt learnt rule status to new set of enabled/disabled rules */
1603   enabledisablelearntrules(solv);
1604
1605   /* redo all job/system decisions */
1606   makeruledecisions(solv);
1607   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
1608
1609   /* recreate watch chains */
1610   makewatches(solv);
1611 }
1612
1613
1614 /*
1615  * analyze_unsolvable_rule
1616  */
1617
1618 static void
1619 analyze_unsolvable_rule(Solver *solv, Rule *r)
1620 {
1621   Pool *pool = solv->pool;
1622   int i;
1623   Id why = r - solv->rules;
1624   IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
1625     printruleclass(solv, SAT_DEBUG_UNSOLVABLE, r);
1626   if (solv->learntrules && why >= solv->learntrules)
1627     {
1628       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1629         if (solv->learnt_pool.elements[i] > 0)
1630           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i]);
1631       return;
1632     }
1633   /* do not add rpm rules to problem */
1634   if (why < solv->jobrules)
1635     return;
1636   /* turn rule into problem */
1637   if (why >= solv->jobrules && why < solv->systemrules)
1638     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1639   /* return if problem already countains our rule */
1640   if (solv->problems.count)
1641     {
1642       for (i = solv->problems.count - 1; i >= 0; i--)
1643         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1644           break;
1645         else if (solv->problems.elements[i] == why)
1646           return;
1647     }
1648   queue_push(&solv->problems, why);
1649 }
1650
1651
1652 /*
1653  * analyze_unsolvable
1654  *
1655  * return: 1 - disabled some rules, try again
1656  *         0 - hopeless
1657  */
1658
1659 static int
1660 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1661 {
1662   Pool *pool = solv->pool;
1663   Rule *r;
1664   Map seen;             /* global to speed things up? */
1665   Id v, vv, *dp, why;
1666   int l, i, idx;
1667   Id *decisionmap = solv->decisionmap;
1668   int oldproblemcount;
1669   int oldlearntpoolcount;
1670   int lastweak;
1671
1672   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1673   oldproblemcount = solv->problems.count;
1674   oldlearntpoolcount = solv->learnt_pool.count;
1675
1676   /* make room for proof index */
1677   /* must update it later, as analyze_unsolvable_rule would confuse
1678    * it with a rule index if we put the real value in already */
1679   queue_push(&solv->problems, 0);
1680
1681   r = cr;
1682   map_init(&seen, pool->nsolvables);
1683   queue_push(&solv->learnt_pool, r - solv->rules);
1684   analyze_unsolvable_rule(solv, r);
1685   dp = r->d ? pool->whatprovidesdata + r->d : 0;
1686   for (i = -1; ; i++)
1687     {
1688       if (i == -1)
1689         v = r->p;
1690       else if (r->d == 0)
1691         v = i ? 0 : r->w2;
1692       else
1693         v = *dp++;
1694       if (v == 0)
1695         break;
1696       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1697           continue;
1698       vv = v > 0 ? v : -v;
1699       l = solv->decisionmap[vv];
1700       if (l < 0)
1701         l = -l;
1702       MAPSET(&seen, vv);
1703     }
1704   idx = solv->decisionq.count;
1705   while (idx > 0)
1706     {
1707       v = solv->decisionq.elements[--idx];
1708       vv = v > 0 ? v : -v;
1709       if (!MAPTST(&seen, vv))
1710         continue;
1711       why = solv->decisionq_why.elements[idx];
1712       if (!why)
1713         {
1714           /* level 1 and no why, must be an rpm assertion */
1715           IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
1716             {
1717               POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "RPM ");
1718               printruleelement(solv, SAT_DEBUG_UNSOLVABLE, 0, v);
1719             }
1720           /* this is the only positive rpm assertion */
1721           if (v == SYSTEMSOLVABLE)
1722             v = -v;
1723           assert(v < 0);
1724           queue_push(&solv->learnt_pool, v);
1725           continue;
1726         }
1727       queue_push(&solv->learnt_pool, why);
1728       r = solv->rules + why;
1729       analyze_unsolvable_rule(solv, r);
1730       dp = r->d ? pool->whatprovidesdata + r->d : 0;
1731       for (i = -1; ; i++)
1732         {
1733           if (i == -1)
1734             v = r->p;
1735           else if (r->d == 0)
1736             v = i ? 0 : r->w2;
1737           else
1738             v = *dp++;
1739           if (v == 0)
1740             break;
1741           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1742               continue;
1743           vv = v > 0 ? v : -v;
1744           l = solv->decisionmap[vv];
1745           if (l < 0)
1746             l = -l;
1747           MAPSET(&seen, vv);
1748         }
1749     }
1750   map_free(&seen);
1751   queue_push(&solv->problems, 0);       /* mark end of this problem */
1752
1753   lastweak = 0;
1754   if (solv->weakrules != solv->learntrules)
1755     {
1756       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1757         {
1758           why = solv->problems.elements[i];
1759           if (why < solv->weakrules || why >= solv->learntrules)
1760             continue;
1761           if (!lastweak || lastweak < why)
1762             lastweak = why;
1763         }
1764     }
1765   if (lastweak)
1766     {
1767       /* disable last weak rule */
1768       solv->problems.count = oldproblemcount;
1769       solv->learnt_pool.count = oldlearntpoolcount;
1770       r = solv->rules + lastweak;
1771       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling weak ");
1772       printrule(solv, SAT_DEBUG_UNSOLVABLE, r);
1773       disablerule(solv, r);
1774       reset_solver(solv);
1775       return 1;
1776     }
1777
1778   /* finish proof */
1779   queue_push(&solv->learnt_pool, 0);
1780   solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1781
1782   if (disablerules)
1783     {
1784       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1785         disableproblem(solv, solv->problems.elements[i]);
1786       reset_solver(solv);
1787       return 1;
1788     }
1789   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1790   return 0;
1791 }
1792
1793
1794 /*-----------------------------------------------------------------*/
1795 /* Decision revert */
1796
1797 /*
1798  * revert
1799  * revert decision at level
1800  */
1801
1802 static void
1803 revert(Solver *solv, int level)
1804 {
1805   Pool *pool = solv->pool;
1806   Id v, vv;
1807   while (solv->decisionq.count)
1808     {
1809       v = solv->decisionq.elements[solv->decisionq.count - 1];
1810       vv = v > 0 ? v : -v;
1811       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1812         break;
1813       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1814       solv->decisionmap[vv] = 0;
1815       solv->decisionq.count--;
1816       solv->decisionq_why.count--;
1817       solv->propagate_index = solv->decisionq.count;
1818     }
1819   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1820     {
1821       solv->branches.count--;
1822       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1823         solv->branches.count--;
1824     }
1825   solv->recommends_index = -1;
1826 }
1827
1828
1829 /*
1830  * watch2onhighest - put watch2 on literal with highest level
1831  */
1832
1833 static inline void
1834 watch2onhighest(Solver *solv, Rule *r)
1835 {
1836   int l, wl = 0;
1837   Id v, *dp;
1838
1839   if (!r->d)
1840     return;     /* binary rule, both watches are set */
1841   dp = solv->pool->whatprovidesdata + r->d;
1842   while ((v = *dp++) != 0)
1843     {
1844       l = solv->decisionmap[v < 0 ? -v : v];
1845       if (l < 0)
1846         l = -l;
1847       if (l > wl)
1848         {
1849           r->w2 = dp[-1];
1850           wl = l;
1851         }
1852     }
1853 }
1854
1855
1856 /*
1857  * setpropagatelearn
1858  *
1859  * add free decision to decisionq, increase level and
1860  * propagate decision, return if no conflict.
1861  * in conflict case, analyze conflict rule, add resulting
1862  * rule to learnt rule set, make decision from learnt
1863  * rule (always unit) and re-propagate.
1864  *
1865  * returns the new solver level or 0 if unsolvable
1866  *
1867  */
1868
1869 static int
1870 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
1871 {
1872   Pool *pool = solv->pool;
1873   Rule *r;
1874   Id p, d;
1875   int l, why;
1876
1877   if (decision)
1878     {
1879       level++;
1880       if (decision > 0)
1881         solv->decisionmap[decision] = level;
1882       else
1883         solv->decisionmap[-decision] = -level;
1884       queue_push(&solv->decisionq, decision);
1885       queue_push(&solv->decisionq_why, 0);
1886     }
1887   for (;;)
1888     {
1889       r = propagate(solv, level);
1890       if (!r)
1891         break;
1892       if (level == 1)
1893         return analyze_unsolvable(solv, r, disablerules);
1894       POOL_DEBUG(SAT_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1895       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1896       assert(l > 0 && l < level);
1897       POOL_DEBUG(SAT_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1898       level = l;
1899       revert(solv, level);
1900       r = addrule(solv, p, d);       /* p requires d */
1901       assert(r);
1902       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1903       queue_push(&solv->learnt_why, why);
1904       if (d)
1905         {
1906           /* at least 2 literals, needs watches */
1907           watch2onhighest(solv, r);
1908           addwatches(solv, r);
1909         }
1910       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1911       queue_push(&solv->decisionq, p);
1912       queue_push(&solv->decisionq_why, r - solv->rules);
1913       IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
1914         {
1915           POOL_DEBUG(SAT_DEBUG_ANALYZE, "decision: ");
1916           printruleelement(solv, SAT_DEBUG_ANALYZE, 0, p);
1917           POOL_DEBUG(SAT_DEBUG_ANALYZE, "new rule: ");
1918           printrule(solv, SAT_DEBUG_ANALYZE, r);
1919         }
1920     }
1921   return level;
1922 }
1923
1924
1925 /*
1926  * install best package from the queue. We add an extra package, inst, if
1927  * provided. See comment in weak install section.
1928  *
1929  * returns the new solver level or 0 if unsolvable
1930  *
1931  */
1932 static int
1933 selectandinstall(Solver *solv, int level, Queue *dq, Id inst, int disablerules)
1934 {
1935   Pool *pool = solv->pool;
1936   Id p;
1937   int i;
1938
1939   if (dq->count > 1 || inst)
1940     policy_filter_unwanted(solv, dq, inst, POLICY_MODE_CHOOSE);
1941
1942   i = 0;
1943   if (dq->count > 1)
1944     {
1945       /* choose the supplemented one */
1946       for (i = 0; i < dq->count; i++)
1947         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1948           break;
1949       if (i == dq->count)
1950         {
1951           for (i = 1; i < dq->count; i++)
1952             queue_push(&solv->branches, dq->elements[i]);
1953           queue_push(&solv->branches, -level);
1954           i = 0;
1955         }
1956     }
1957   p = dq->elements[i];
1958
1959   POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
1960
1961   return setpropagatelearn(solv, level, p, disablerules);
1962 }
1963
1964
1965 /*-----------------------------------------------------------------*/
1966 /* Main solver interface */
1967
1968
1969 /*
1970  * solver_create
1971  * create solver structure
1972  *
1973  * pool: all available solvables
1974  * installed: installed Solvables
1975  *
1976  *
1977  * Upon solving, rules are created to flag the Solvables
1978  * of the 'installed' Repo as installed.
1979  */
1980
1981 Solver *
1982 solver_create(Pool *pool, Repo *installed)
1983 {
1984   Solver *solv;
1985   solv = (Solver *)sat_calloc(1, sizeof(Solver));
1986   solv->pool = pool;
1987   solv->installed = installed;
1988
1989   queue_init(&solv->ruletojob);
1990   queue_init(&solv->decisionq);
1991   queue_init(&solv->decisionq_why);
1992   queue_init(&solv->problems);
1993   queue_init(&solv->suggestions);
1994   queue_init(&solv->learnt_why);
1995   queue_init(&solv->learnt_pool);
1996   queue_init(&solv->branches);
1997
1998   map_init(&solv->recommendsmap, pool->nsolvables);
1999   map_init(&solv->suggestsmap, pool->nsolvables);
2000   map_init(&solv->noupdate, installed ? installed->end - installed->start : 0);
2001   solv->recommends_index = 0;
2002
2003   solv->decisionmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
2004   solv->rules = (Rule *)sat_malloc((solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
2005   memset(solv->rules, 0, sizeof(Rule));
2006   solv->nrules = 1;
2007
2008   return solv;
2009 }
2010
2011
2012 /*
2013  * solver_free
2014  */
2015
2016 void
2017 solver_free(Solver *solv)
2018 {
2019   queue_free(&solv->ruletojob);
2020   queue_free(&solv->decisionq);
2021   queue_free(&solv->decisionq_why);
2022   queue_free(&solv->learnt_why);
2023   queue_free(&solv->learnt_pool);
2024   queue_free(&solv->problems);
2025   queue_free(&solv->suggestions);
2026   queue_free(&solv->branches);
2027
2028   map_free(&solv->recommendsmap);
2029   map_free(&solv->suggestsmap);
2030   map_free(&solv->noupdate);
2031
2032   sat_free(solv->decisionmap);
2033   sat_free(solv->rules);
2034   sat_free(solv->watches);
2035   sat_free(solv->weaksystemrules);
2036   sat_free(solv->obsoletes);
2037   sat_free(solv->obsoletes_data);
2038   sat_free(solv);
2039 }
2040
2041
2042 /*-------------------------------------------------------*/
2043
2044 /*
2045  * run_solver
2046  * 
2047  * all rules have been set up, now actually run the solver
2048  *
2049  */
2050
2051 static void
2052 run_solver(Solver *solv, int disablerules, int doweak)
2053 {
2054   Queue dq;
2055   int systemlevel;
2056   int level, olevel;
2057   Rule *r;
2058   int i, j, n;
2059   Solvable *s;
2060   Pool *pool = solv->pool;
2061   Id p, *dp;
2062
2063   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
2064     {
2065       POOL_DEBUG (SAT_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
2066       for (i = 0; i < solv->nrules; i++)
2067         printrule(solv, SAT_DEBUG_RULE_CREATION, solv->rules + i);
2068     }
2069
2070   POOL_DEBUG(SAT_DEBUG_STATS, "initial decisions: %d\n", solv->decisionq.count);
2071   
2072   IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2073     printdecisions(solv);
2074
2075   /* start SAT algorithm */
2076   level = 1;
2077   systemlevel = level + 1;
2078   POOL_DEBUG(SAT_DEBUG_STATS, "solving...\n");
2079
2080   queue_init(&dq);
2081   for (;;)
2082     {
2083       /*
2084        * propagate
2085        */
2086       
2087       if (level == 1)
2088         {
2089           POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
2090           if ((r = propagate(solv, level)) != 0)
2091             {
2092               if (analyze_unsolvable(solv, r, disablerules))
2093                 continue;
2094               queue_free(&dq);
2095               return;
2096             }
2097         }
2098
2099       /*
2100        * installed packages
2101        */
2102       
2103       if (level < systemlevel && solv->installed && solv->installed->nsolvables)
2104         {
2105           if (!solv->updatesystem)
2106             {
2107               /* try to keep as many packages as possible */
2108               POOL_DEBUG(SAT_DEBUG_STATS, "installing system packages\n");
2109               for (i = solv->installed->start, n = 0; ; i++)
2110                 {
2111                   if (n == solv->installed->nsolvables)
2112                     break;
2113                   if (i == solv->installed->end)
2114                     i = solv->installed->start;
2115                   s = pool->solvables + i;
2116                   if (s->repo != solv->installed)
2117                     continue;
2118                   n++;
2119                   if (solv->decisionmap[i] != 0)
2120                     continue;
2121                   POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
2122                   olevel = level;
2123                   level = setpropagatelearn(solv, level, i, disablerules);
2124                   if (level == 0)
2125                     {
2126                       queue_free(&dq);
2127                       return;
2128                     }
2129                   if (level <= olevel)
2130                     n = 0;
2131                 }
2132             }
2133           if (solv->weaksystemrules)
2134             {
2135               POOL_DEBUG(SAT_DEBUG_STATS, "installing weak system packages\n");
2136               for (i = solv->installed->start; i < solv->installed->end; i++)
2137                 {
2138                   if (pool->solvables[i].repo != solv->installed)
2139                     continue;
2140                   if (solv->decisionmap[i] > 0 || (solv->decisionmap[i] < 0 && solv->weaksystemrules[i - solv->installed->start] == 0))
2141                     continue;
2142                   /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
2143                   if (MAPTST(&solv->noupdate, i - solv->installed->start))
2144                     continue;
2145                   queue_empty(&dq);
2146                   if (solv->weaksystemrules[i - solv->installed->start])
2147                     {
2148                       dp = pool->whatprovidesdata + solv->weaksystemrules[i - solv->installed->start];
2149                       while ((p = *dp++) != 0)
2150                         {
2151                           if (solv->decisionmap[p] > 0)
2152                             break;
2153                           if (solv->decisionmap[p] == 0)
2154                             queue_push(&dq, p);
2155                         }
2156                       if (p)
2157                         continue;       /* update package already installed */
2158                     }
2159                   if (!dq.count && solv->decisionmap[i] != 0)
2160                     continue;
2161                   olevel = level;
2162                   /* FIXME: i is handled a bit different because we do not want
2163                    * to have it pruned just because it is not recommened.
2164                    * we should not prune installed packages instead */
2165                   level = selectandinstall(solv, level, &dq, (solv->decisionmap[i] ? 0 : i), disablerules);
2166                   if (level == 0)
2167                     {
2168                       queue_free(&dq);
2169                       return;
2170                     }
2171                   if (level <= olevel)
2172                     break;
2173                 }
2174               if (i < solv->installed->end)
2175                 continue;
2176             }
2177           systemlevel = level;
2178         }
2179
2180       /*
2181        * decide
2182        */
2183       
2184       POOL_DEBUG(SAT_DEBUG_STATS, "deciding unresolved rules\n");
2185       for (i = 1, n = 1; ; i++, n++)
2186         {
2187           if (n == solv->nrules)
2188             break;
2189           if (i == solv->nrules)
2190             i = 1;
2191           r = solv->rules + i;
2192           if (!r->w1)   /* ignore disabled rules */
2193             continue;
2194           queue_empty(&dq);
2195           if (r->d == 0)
2196             {
2197               /* binary or unary rule */
2198               /* need two positive undecided literals */
2199               if (r->p < 0 || r->w2 <= 0)
2200                 continue;
2201               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2202                 continue;
2203               queue_push(&dq, r->p);
2204               queue_push(&dq, r->w2);
2205             }
2206           else
2207             {
2208               /* make sure that
2209                * all negative literals are installed
2210                * no positive literal is installed
2211                * i.e. the rule is not fulfilled and we
2212                * just need to decide on the positive literals
2213                */
2214               if (r->p < 0)
2215                 {
2216                   if (solv->decisionmap[-r->p] <= 0)
2217                     continue;
2218                 }
2219               else
2220                 {
2221                   if (solv->decisionmap[r->p] > 0)
2222                     continue;
2223                   if (solv->decisionmap[r->p] == 0)
2224                     queue_push(&dq, r->p);
2225                 }
2226               dp = pool->whatprovidesdata + r->d;
2227               while ((p = *dp++) != 0)
2228                 {
2229                   if (p < 0)
2230                     {
2231                       if (solv->decisionmap[-p] <= 0)
2232                         break;
2233                     }
2234                   else
2235                     {
2236                       if (solv->decisionmap[p] > 0)
2237                         break;
2238                       if (solv->decisionmap[p] == 0)
2239                         queue_push(&dq, p);
2240                     }
2241                 }
2242               if (p)
2243                 continue;
2244             }
2245           /* dq.count < 2 cannot happen as this means that
2246            * the rule is unit */
2247           assert(dq.count > 1);
2248           IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
2249             {
2250               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "unfulfilled ");
2251               printrule(solv, SAT_DEBUG_PROPAGATE, r);
2252             }
2253
2254           olevel = level;
2255           level = selectandinstall(solv, level, &dq, 0, disablerules);
2256           if (level == 0)
2257             {
2258               queue_free(&dq);
2259               return;
2260             }
2261           if (level < systemlevel)
2262             break;
2263           n = 0;
2264         } /* for(), decide */
2265
2266       if (n != solv->nrules)    /* continue if level < systemlevel */
2267         continue;
2268       
2269       if (doweak && !solv->problems.count)
2270         {
2271           int qcount;
2272
2273           POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended packages\n");
2274           if (!REGARD_RECOMMENDS_OF_INSTALLED_ITEMS)
2275             {
2276               for (i = 0; i < solv->decisionq.count; i++)
2277                 {
2278                   p = solv->decisionq.elements[i];
2279                   if (p > 0 && pool->solvables[p].repo == solv->installed)
2280                     solv->decisionmap[p] = -solv->decisionmap[p];
2281                 }
2282             }
2283           queue_empty(&dq);
2284           for (i = 1; i < pool->nsolvables; i++)
2285             {
2286               if (solv->decisionmap[i] < 0)
2287                 continue;
2288               if (solv->decisionmap[i] > 0)
2289                 {
2290                   Id *recp, rec, *pp, p;
2291                   s = pool->solvables + i;
2292                   /* installed, check for recommends */
2293                   /* XXX need to special case AND ? */
2294                   if (s->recommends)
2295                     {
2296                       recp = s->repo->idarraydata + s->recommends;
2297                       while ((rec = *recp++) != 0)
2298                         {
2299                           qcount = dq.count;
2300                           FOR_PROVIDES(p, pp, rec)
2301                             {
2302                               if (solv->decisionmap[p] > 0)
2303                                 {
2304                                   dq.count = qcount;
2305                                   break;
2306                                 }
2307                               else if (solv->decisionmap[p] == 0)
2308                                 {
2309                                   queue_pushunique(&dq, p);
2310                                 }
2311                             }
2312                         }
2313                     }
2314                 }
2315               else
2316                 {
2317                   s = pool->solvables + i;
2318                   if (!s->supplements && !s->freshens)
2319                     continue;
2320                   if (!pool_installable(pool, s))
2321                     continue;
2322                   if (solver_is_supplementing(solv, s))
2323                     queue_pushunique(&dq, i);
2324                 }
2325             }
2326           if (!REGARD_RECOMMENDS_OF_INSTALLED_ITEMS)
2327             {
2328               for (i = 0; i < solv->decisionq.count; i++)
2329                 {
2330                   p = solv->decisionq.elements[i];
2331                   if (p > 0 && pool->solvables[p].repo == solv->installed)
2332                     solv->decisionmap[p] = -solv->decisionmap[p];
2333                 }
2334             }
2335           if (dq.count)
2336             {
2337               if (dq.count > 1)
2338                 policy_filter_unwanted(solv, &dq, 0, POLICY_MODE_RECOMMEND);
2339               p = dq.elements[0];
2340               POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
2341               level = setpropagatelearn(solv, level, p, 0);
2342               continue;
2343             }
2344         }
2345
2346      if (solv->solution_callback)
2347         {
2348           solv->solution_callback(solv, solv->solution_callback_data);
2349           if (solv->branches.count)
2350             {
2351               int i = solv->branches.count - 1;
2352               int l = -solv->branches.elements[i];
2353               for (; i > 0; i--)
2354                 if (solv->branches.elements[i - 1] < 0)
2355                   break;
2356               p = solv->branches.elements[i];
2357               POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
2358               queue_empty(&dq);
2359               for (j = i + 1; j < solv->branches.count; j++)
2360                 queue_push(&dq, solv->branches.elements[j]);
2361               solv->branches.count = i;
2362               level = l;
2363               revert(solv, level);
2364               if (dq.count > 1)
2365                 for (j = 0; j < dq.count; j++)
2366                   queue_push(&solv->branches, dq.elements[j]);
2367               olevel = level;
2368               level = setpropagatelearn(solv, level, p, disablerules);
2369               if (level == 0)
2370                 {
2371                   queue_free(&dq);
2372                   return;
2373                 }
2374               continue;
2375             }
2376           /* all branches done, we're finally finished */
2377           break;
2378         }
2379
2380       /* minimization step */
2381      if (solv->branches.count)
2382         {
2383           int l = 0, lasti = -1, lastl = -1;
2384           p = 0;
2385           for (i = solv->branches.count - 1; i >= 0; i--)
2386             {
2387               p = solv->branches.elements[i];
2388               if (p < 0)
2389                 l = -p;
2390               else if (p > 0 && solv->decisionmap[p] > l + 1)
2391                 {
2392                   lasti = i;
2393                   lastl = l;
2394                 }
2395             }
2396           if (lasti >= 0)
2397             {
2398               /* kill old solvable so that we do not loop */
2399               p = solv->branches.elements[lasti];
2400               solv->branches.elements[lasti] = 0;
2401               POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], l, solvable2str(pool, pool->solvables + p));
2402
2403               level = lastl;
2404               revert(solv, level);
2405               olevel = level;
2406               level = setpropagatelearn(solv, level, p, disablerules);
2407               if (level == 0)
2408                 {
2409                   queue_free(&dq);
2410                   return;
2411                 }
2412               continue;
2413             }
2414         }
2415       break;
2416     }
2417   queue_free(&dq);
2418 }
2419
2420   
2421 /*
2422  * refine_suggestion
2423  * at this point, all rules that led to conflicts are disabled.
2424  * we re-enable all rules of a problem set but rule "sug", then
2425  * continue to disable more rules until there as again a solution.
2426  */
2427   
2428 /* FIXME: think about conflicting assertions */
2429
2430 static void
2431 refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
2432 {
2433   Pool *pool = solv->pool;
2434   Rule *r;
2435   int i, j;
2436   Id v;
2437   Queue disabled;
2438   int disabledcnt;
2439
2440   IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
2441     {
2442       POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
2443       for (i = 0; problem[i]; i++)
2444         {
2445           if (problem[i] == sug)
2446             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
2447           printproblem(solv, problem[i]);
2448         }
2449     }
2450   queue_init(&disabled);
2451   queue_empty(refined);
2452   queue_push(refined, sug);
2453
2454   /* re-enable all problem rules with the exception of "sug" */
2455   revert(solv, 1);
2456   reset_solver(solv);
2457
2458   for (i = 0; problem[i]; i++)
2459     if (problem[i] != sug)
2460       enableproblem(solv, problem[i]);
2461
2462   if (sug < 0)
2463     disableupdaterules(solv, job, -(sug + 1));
2464
2465   for (;;)
2466     {
2467       /* re-enable as many weak rules as possible */
2468       for (i = solv->weakrules; i < solv->learntrules; i++)
2469         {
2470           r = solv->rules + i;
2471           if (!r->w1)
2472             enablerule(solv, r);
2473         }
2474
2475       queue_empty(&solv->problems);
2476       revert(solv, 1);          /* XXX move to reset_solver? */
2477       reset_solver(solv);
2478
2479       if (!solv->problems.count)
2480         run_solver(solv, 0, 0);
2481
2482       if (!solv->problems.count)
2483         {
2484           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
2485           IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2486             printdecisions(solv);
2487           break;                /* great, no more problems */
2488         }
2489       disabledcnt = disabled.count;
2490       /* start with 1 to skip over proof index */
2491       for (i = 1; i < solv->problems.count - 1; i++)
2492         {
2493           /* ignore solutions in refined */
2494           v = solv->problems.elements[i];
2495           if (v == 0)
2496             break;      /* end of problem reached */
2497           for (j = 0; problem[j]; j++)
2498             if (problem[j] != sug && problem[j] == v)
2499               break;
2500           if (problem[j])
2501             continue;
2502           queue_push(&disabled, v);
2503         }
2504       if (disabled.count == disabledcnt)
2505         {
2506           /* no solution found, this was an invalid suggestion! */
2507           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
2508           refined->count = 0;
2509           break;
2510         }
2511       if (disabled.count == disabledcnt + 1)
2512         {
2513           /* just one suggestion, add it to refined list */
2514           v = disabled.elements[disabledcnt];
2515           queue_push(refined, v);
2516           disableproblem(solv, v);
2517           if (v < 0)
2518             disableupdaterules(solv, job, -(v + 1));
2519         }
2520       else
2521         {
2522           /* more than one solution, disable all */
2523           /* do not push anything on refine list */
2524           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
2525             {
2526               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
2527               for (i = disabledcnt; i < disabled.count; i++)
2528                 printproblem(solv, disabled.elements[i]);
2529             }
2530           for (i = disabledcnt; i < disabled.count; i++)
2531             disableproblem(solv, disabled.elements[i]);
2532         }
2533     }
2534   /* all done, get us back into the same state as before */
2535   /* enable refined rules again */
2536   for (i = 0; i < disabled.count; i++)
2537     enableproblem(solv, disabled.elements[i]);
2538   /* disable problem rules again */
2539   for (i = 0; problem[i]; i++)
2540     disableproblem(solv, problem[i]);
2541   disableupdaterules(solv, job, -1);
2542   POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
2543 }
2544
2545 static void
2546 problems_to_solutions(Solver *solv, Queue *job)
2547 {
2548   Pool *pool = solv->pool;
2549   Queue problems;
2550   Queue solution;
2551   Queue solutions;
2552   Id *problem;
2553   Id why;
2554   int i, j;
2555
2556   if (!solv->problems.count)
2557     return;
2558   queue_clone(&problems, &solv->problems);
2559   queue_init(&solution);
2560   queue_init(&solutions);
2561   /* copy over proof index */
2562   queue_push(&solutions, problems.elements[0]);
2563   problem = problems.elements + 1;
2564   for (i = 1; i < problems.count; i++)
2565     {
2566       Id v = problems.elements[i];
2567       if (v == 0)
2568         {
2569           /* mark end of this problem */
2570           queue_push(&solutions, 0);
2571           queue_push(&solutions, 0);
2572           if (i + 1 == problems.count)
2573             break;
2574           /* copy over proof of next problem */
2575           queue_push(&solutions, problems.elements[i + 1]);
2576           i++;
2577           problem = problems.elements + i + 1;
2578           continue;
2579         }
2580       refine_suggestion(solv, job, problem, v, &solution);
2581       if (!solution.count)
2582         continue;       /* this solution didn't work out */
2583
2584       for (j = 0; j < solution.count; j++)
2585         {
2586           why = solution.elements[j];
2587           /* must be either job descriptor or system rule */
2588           assert(why < 0 || (why >= solv->systemrules && why < solv->weakrules));
2589 #if 0
2590           printproblem(solv, why);
2591 #endif
2592           if (why < 0)
2593             {
2594               /* job descriptor */
2595               queue_push(&solutions, 0);
2596               queue_push(&solutions, -why);
2597             }
2598           else
2599             {
2600               /* system rule, find replacement package */
2601               Id p, rp = 0;
2602               p = solv->installed->start + (why - solv->systemrules);
2603               if (solv->weaksystemrules && solv->weaksystemrules[why - solv->systemrules])
2604                 {
2605                   Id *dp = pool->whatprovidesdata + solv->weaksystemrules[why - solv->systemrules];
2606                   for (; *dp; dp++)
2607                     {
2608                       if (*dp >= solv->installed->start && *dp < solv->installed->start + solv->installed->nsolvables)
2609                         continue;
2610                       if (solv->decisionmap[*dp] > 0)
2611                         {
2612                           rp = *dp;
2613                           break;
2614                         }
2615                     }
2616                 }
2617               queue_push(&solutions, p);
2618               queue_push(&solutions, rp);
2619             }
2620         }
2621       /* mark end of this solution */
2622       queue_push(&solutions, 0);
2623       queue_push(&solutions, 0);
2624     }
2625   queue_free(&solution);
2626   queue_free(&problems);
2627   /* copy queue over to solutions */
2628   queue_free(&solv->problems);
2629   queue_clone(&solv->problems, &solutions);
2630
2631   /* bring solver back into problem state */
2632   revert(solv, 1);              /* XXX move to reset_solver? */
2633   reset_solver(solv);
2634
2635   assert(solv->problems.count == solutions.count);
2636   queue_free(&solutions);
2637 }
2638
2639 Id
2640 solver_next_problem(Solver *solv, Id problem)
2641 {
2642   Id *pp;
2643   if (problem == 0)
2644     return solv->problems.count ? 1 : 0;
2645   pp = solv->problems.elements + problem;
2646   while (pp[0] || pp[1])
2647     {
2648       /* solution */
2649       pp += 2;
2650       while (pp[0] || pp[1])
2651         pp += 2;
2652       pp += 2;
2653     }
2654   pp += 2;
2655   problem = pp - solv->problems.elements;
2656   if (problem >= solv->problems.count)
2657     return 0;
2658   return problem + 1;
2659 }
2660
2661 Id
2662 solver_next_solution(Solver *solv, Id problem, Id solution)
2663 {
2664   Id *pp;
2665   if (solution == 0)
2666     {
2667       solution = problem;
2668       pp = solv->problems.elements + solution;
2669       return pp[0] || pp[1] ? solution : 0;
2670     }
2671   pp = solv->problems.elements + solution;
2672   while (pp[0] || pp[1])
2673     pp += 2;
2674   pp += 2;
2675   solution = pp - solv->problems.elements;
2676   return pp[0] || pp[1] ? solution : 0;
2677 }
2678
2679 Id
2680 solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
2681 {
2682   Id *pp;
2683   element = element ? element + 2 : solution;
2684   pp = solv->problems.elements + element;
2685   if (!(pp[0] || pp[1]))
2686     return 0;
2687   *p = pp[0];
2688   *rp = pp[1];
2689   return element;
2690 }
2691
2692
2693 /*
2694  * create obsoletesmap from solver decisions
2695  * required for decision handling
2696  */
2697
2698 Id *
2699 create_obsoletesmap(Solver *solv)
2700 {
2701   Pool *pool = solv->pool;
2702   Repo *installed = solv->installed;
2703   Id p, *obsoletesmap = NULL;
2704   int i;
2705   Solvable *s;
2706
2707   obsoletesmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
2708   if (installed)
2709     {
2710       for (i = 0; i < solv->decisionq.count; i++)
2711         {
2712           Id *pp, n;
2713
2714           n = solv->decisionq.elements[i];
2715           if (n < 0)
2716             continue;
2717           if (n == SYSTEMSOLVABLE)
2718             continue;
2719           s = pool->solvables + n;
2720           if (s->repo == installed)             /* obsoletes don't count for already installed packages */
2721             continue;
2722           FOR_PROVIDES(p, pp, s->name)
2723             if (s->name == pool->solvables[p].name)
2724               {
2725                 if (pool->solvables[p].repo == installed && !obsoletesmap[p])
2726                   {
2727                     obsoletesmap[p] = n;
2728                     obsoletesmap[n]++;
2729                   }
2730               }
2731         }
2732       for (i = 0; i < solv->decisionq.count; i++)
2733         {
2734           Id obs, *obsp;
2735           Id *pp, n;
2736
2737           n = solv->decisionq.elements[i];
2738           if (n < 0)
2739             continue;
2740           if (n == SYSTEMSOLVABLE)
2741             continue;
2742           s = pool->solvables + n;
2743           if (s->repo == installed)             /* obsoletes don't count for already installed packages */
2744             continue;
2745           if (!s->obsoletes)
2746             continue;
2747           obsp = s->repo->idarraydata + s->obsoletes;
2748           while ((obs = *obsp++) != 0)
2749             FOR_PROVIDES(p, pp, obs)
2750               {
2751                 if (pool->solvables[p].repo == installed && !obsoletesmap[p])
2752                   {
2753                     obsoletesmap[p] = n;
2754                     obsoletesmap[n]++;
2755                   }
2756               }
2757         }
2758     }
2759   return obsoletesmap;
2760 }
2761
2762 /*
2763  * printdecisions
2764  */
2765   
2766
2767 void
2768 printdecisions(Solver *solv)
2769 {
2770   Pool *pool = solv->pool;
2771   Repo *installed = solv->installed;
2772   Id p, *obsoletesmap = create_obsoletesmap( solv );
2773   int i;
2774   Solvable *s;
2775
2776   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions -----\n");  
2777
2778   /* print solvables to be erased */
2779
2780   if (installed)
2781     {
2782       FOR_REPO_SOLVABLES(installed, p, s)
2783         {
2784           if (solv->decisionmap[p] >= 0)
2785             continue;
2786           if (obsoletesmap[p])
2787             continue;
2788           POOL_DEBUG(SAT_DEBUG_RESULT, "erase   %s\n", solvable2str(pool, s));
2789         }
2790     }
2791
2792   /* print solvables to be installed */
2793
2794   for (i = 0; i < solv->decisionq.count; i++)
2795     {
2796       int j;
2797       p = solv->decisionq.elements[i];
2798       if (p < 0)
2799         {
2800             IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
2801             {   
2802               p = -p;
2803               s = pool->solvables + p;      
2804               POOL_DEBUG(SAT_DEBUG_SCHUBI, "level of %s is %d\n", solvable2str(pool, s), p);
2805             }
2806             continue;
2807         }
2808       if (p == SYSTEMSOLVABLE)
2809         {
2810             POOL_DEBUG(SAT_DEBUG_SCHUBI, "SYSTEMSOLVABLE\n");
2811             continue;
2812         }
2813       s = pool->solvables + p;
2814       if (installed && s->repo == installed)
2815         continue;
2816
2817       if (!obsoletesmap[p])
2818         {
2819           POOL_DEBUG(SAT_DEBUG_RESULT, "install %s", solvable2str(pool, s));
2820         }
2821       else
2822         {
2823           POOL_DEBUG(SAT_DEBUG_RESULT, "update  %s", solvable2str(pool, s));
2824           POOL_DEBUG(SAT_DEBUG_RESULT, "  (obsoletes");
2825           for (j = installed->start; j < installed->end; j++)
2826             if (obsoletesmap[j] == p)
2827               POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + j));
2828           POOL_DEBUG(SAT_DEBUG_RESULT, ")");
2829         }
2830       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
2831     }
2832
2833   sat_free(obsoletesmap);
2834
2835   if (solv->suggestions.count)
2836     {
2837       POOL_DEBUG(SAT_DEBUG_RESULT, "\nsuggested packages:\n");
2838       for (i = 0; i < solv->suggestions.count; i++)
2839         {
2840           s = pool->solvables + solv->suggestions.elements[i];
2841           POOL_DEBUG(SAT_DEBUG_RESULT, "- %s\n", solvable2str(pool, s));
2842         }
2843     }
2844   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions end -----\n");    
2845 }
2846
2847 /* this is basically the reverse of addrpmrulesforsolvable */
2848 SolverProbleminfo
2849 solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
2850 {
2851   Pool *pool = solv->pool;
2852   Repo *installed = solv->installed;
2853   Rule *r;
2854   Solvable *s;
2855   int dontfix = 0;
2856   Id p, *pp, req, *reqp, con, *conp, obs, *obsp, *dp;
2857   
2858   assert(rid < solv->weakrules);
2859   if (rid >= solv->systemrules)
2860     {
2861       *depp = 0;
2862       *sourcep = solv->installed->start + (rid - solv->systemrules);
2863       *targetp = 0;
2864       return SOLVER_PROBLEM_UPDATE_RULE;
2865     }
2866   if (rid >= solv->jobrules)
2867     {
2868      
2869       r = solv->rules + rid;
2870       p = solv->ruletojob.elements[rid - solv->jobrules];
2871       *depp = job->elements[p + 1];
2872       *sourcep = p;
2873       *targetp = job->elements[p];
2874       if (r->d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
2875         return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
2876       return SOLVER_PROBLEM_JOB_RULE;
2877     }
2878   if (rid < 0)
2879     {
2880       /* a rpm rule assertion */
2881       assert(rid != -SYSTEMSOLVABLE);
2882       s = pool->solvables - rid;
2883       if (installed && !solv->fixsystem && s->repo == installed)
2884         dontfix = 1;
2885       assert(!dontfix); /* dontfix packages never have a neg assertion */
2886       /* see why the package is not installable */
2887       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
2888         return SOLVER_PROBLEM_NOT_INSTALLABLE;
2889       /* check requires */
2890       assert(s->requires);
2891       reqp = s->repo->idarraydata + s->requires;
2892       while ((req = *reqp++) != 0)
2893         {
2894           if (req == SOLVABLE_PREREQMARKER)
2895             continue;
2896           dp = pool_whatprovides(pool, req);
2897           if (*dp == 0)
2898             break;
2899         }
2900       assert(req);
2901       *depp = req;
2902       *sourcep = -rid;
2903       *targetp = 0;
2904       return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP;
2905     }
2906   r = solv->rules + rid;
2907   assert(r->p < 0);
2908   if (r->d == 0 && r->w2 == 0)
2909     {
2910       /* an assertion. we don't store them as rpm rules, so
2911        * can't happen */
2912       assert(0);
2913     }
2914   s = pool->solvables - r->p;
2915   if (installed && !solv->fixsystem && s->repo == installed)
2916     dontfix = 1;
2917   if (r->d == 0 && r->w2 < 0)
2918     {
2919       /* a package conflict */
2920       Solvable *s2 = pool->solvables - r->w2;
2921       int dontfix2 = 0;
2922
2923       if (installed && !solv->fixsystem && s2->repo == installed)
2924         dontfix2 = 1;
2925
2926       /* if both packages have the same name and at least one of them
2927        * is not installed, they conflict */
2928       if (s->name == s2->name && (!installed || (s->repo != installed || s2->repo != installed)))
2929         {
2930           *depp = 0;
2931           *sourcep = -r->p;
2932           *targetp = -r->w2;
2933           return SOLVER_PROBLEM_SAME_NAME;
2934         }
2935
2936       /* check conflicts in both directions */
2937       if (s->conflicts)
2938         {
2939           conp = s->repo->idarraydata + s->conflicts;
2940           while ((con = *conp++) != 0)
2941             {
2942               FOR_PROVIDES(p, pp, con) 
2943                 {
2944                   if (dontfix && pool->solvables[p].repo == installed)
2945                     continue;
2946                   if (p != -r->w2)
2947                     continue;
2948                   *depp = con;
2949                   *sourcep = -r->p;
2950                   *targetp = p;
2951                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
2952                 }
2953             }
2954         }
2955       if (s2->conflicts)
2956         {
2957           conp = s2->repo->idarraydata + s2->conflicts;
2958           while ((con = *conp++) != 0)
2959             {
2960               FOR_PROVIDES(p, pp, con) 
2961                 {
2962                   if (dontfix2 && pool->solvables[p].repo == installed)
2963                     continue;
2964                   if (p != -r->p)
2965                     continue;
2966                   *depp = con;
2967                   *sourcep = -r->w2;
2968                   *targetp = p;
2969                   return SOLVER_PROBLEM_PACKAGE_CONFLICT;
2970                 }
2971             }
2972         }
2973       /* check obsoletes in both directions */
2974       if ((!installed || s->repo != installed) && s->obsoletes)
2975         {
2976           obsp = s->repo->idarraydata + s->obsoletes;
2977           while ((obs = *obsp++) != 0)
2978             {
2979               FOR_PROVIDES(p, pp, obs)
2980                 {
2981                   if (p != -r->w2)
2982                     continue;
2983                   *depp = obs;
2984                   *sourcep = -r->p;
2985                   *targetp = p;
2986                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
2987                 }
2988             }
2989         }
2990       if ((!installed || s2->repo != installed) && s2->obsoletes)
2991         {
2992           obsp = s2->repo->idarraydata + s2->obsoletes;
2993           while ((obs = *obsp++) != 0)
2994             {
2995               FOR_PROVIDES(p, pp, obs)
2996                 {
2997                   if (p != -r->p)
2998                     continue;
2999                   *depp = obs;
3000                   *sourcep = -r->w2;
3001                   *targetp = p;
3002                   return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
3003                 }
3004             }
3005         }
3006       /* all cases checked, can't happen */
3007       assert(0);
3008     }
3009   /* simple requires */
3010   assert(s->requires);
3011   reqp = s->repo->idarraydata + s->requires;
3012   while ((req = *reqp++) != 0)
3013     {
3014       if (req == SOLVABLE_PREREQMARKER)
3015         continue;
3016       dp = pool_whatprovides(pool, req);
3017       if (r->d == 0)
3018         {
3019           if (*dp == r->w2 && dp[1] == 0)
3020             break;
3021         }
3022       else if (dp - pool->whatprovidesdata == r->d)
3023         break;
3024     }
3025   assert(req);
3026   *depp = req;
3027   *sourcep = -r->p;
3028   *targetp = 0;
3029   return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE;
3030 }
3031
3032 static void
3033 findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
3034 {
3035   Id rid;
3036   Id lreqr, lconr, lsysr, ljobr;
3037   Rule *r;
3038   int reqassert = 0;
3039
3040   lreqr = lconr = lsysr = ljobr = 0;
3041   while ((rid = solv->learnt_pool.elements[idx++]) != 0)
3042     {
3043       if (rid >= solv->learntrules)
3044         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
3045       else if (rid >= solv->systemrules)
3046         {
3047           if (!*sysrp)
3048             *sysrp = rid;
3049         }
3050       else if (rid >= solv->jobrules)
3051         {
3052           if (!*jobrp)
3053             *jobrp = rid;
3054         }
3055       else if (rid >= 0)
3056         {
3057           r = solv->rules + rid;
3058           if (!r->d && r->w2 < 0)
3059             {
3060               if (!*conrp)
3061                 *conrp = rid;
3062             }
3063           else
3064             {
3065               if (!*reqrp)
3066                 *reqrp = rid;
3067             }
3068         }
3069       else
3070         {
3071           /* assertion, counts as require rule */
3072           /* ignore system solvable as we need useful info */
3073           if (rid == -SYSTEMSOLVABLE)
3074             continue;
3075           if (!*reqrp || !reqassert)
3076             {
3077               *reqrp = rid;
3078               reqassert = 1;
3079             }
3080         }
3081     }
3082   if (!*reqrp && lreqr)
3083     *reqrp = lreqr;
3084   if (!*conrp && lconr)
3085     *conrp = lconr;
3086   if (!*jobrp && ljobr)
3087     *jobrp = ljobr;
3088   if (!*sysrp && lsysr)
3089     *sysrp = lsysr;
3090 }
3091
3092 Id
3093 solver_findproblemrule(Solver *solv, Id problem)
3094 {
3095   Id reqr, conr, sysr, jobr;
3096   Id idx = solv->problems.elements[problem - 1];
3097   reqr = conr = sysr = jobr = 0;
3098   findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
3099   if (reqr)
3100     return reqr;
3101   if (conr)
3102     return conr;
3103   if (sysr)
3104     return sysr;
3105   if (jobr)
3106     return jobr;
3107   assert(0);
3108 }
3109
3110 void
3111 printprobleminfo(Solver *solv, Queue *job, Id problem)
3112 {
3113   Pool *pool = solv->pool;
3114   Id probr;
3115   Id dep, source, target;
3116   Solvable *s, *s2;
3117
3118   probr = solver_findproblemrule(solv, problem);
3119   switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
3120     {
3121     case SOLVER_PROBLEM_UPDATE_RULE:
3122       s = pool_id2solvable(pool, source);
3123       POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
3124       return;
3125     case SOLVER_PROBLEM_JOB_RULE:
3126       POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n");
3127       return;
3128     case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
3129       POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides requested %s\n", dep2str(pool, dep));
3130       return;
3131     case SOLVER_PROBLEM_NOT_INSTALLABLE:
3132       s = pool_id2solvable(pool, source);
3133       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s));
3134       return;
3135     case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
3136       s = pool_id2solvable(pool, source);
3137       POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
3138       return;
3139     case SOLVER_PROBLEM_SAME_NAME:
3140       s = pool_id2solvable(pool, source);
3141       s2 = pool_id2solvable(pool, target);
3142       POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
3143       return;
3144     case SOLVER_PROBLEM_PACKAGE_CONFLICT:
3145       s = pool_id2solvable(pool, source);
3146       s2 = pool_id2solvable(pool, target);
3147       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
3148       return;
3149     case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
3150       s = pool_id2solvable(pool, source);
3151       s2 = pool_id2solvable(pool, target);
3152       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
3153       return;
3154     case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
3155       s = pool_id2solvable(pool, source);
3156       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
3157       return;
3158     }
3159 }
3160
3161 void
3162 printsolutions(Solver *solv, Queue *job)
3163 {
3164   Pool *pool = solv->pool;
3165   int pcnt;
3166   Id p, rp, what;
3167   Id problem, solution, element;
3168   Solvable *s, *sd;
3169
3170   POOL_DEBUG(SAT_DEBUG_RESULT, "Encountered problems! Here are the solutions:\n\n");
3171   pcnt = 1;
3172   problem = 0;
3173   while ((problem = solver_next_problem(solv, problem)) != 0)
3174     {
3175       POOL_DEBUG(SAT_DEBUG_RESULT, "Problem %d:\n", pcnt++);
3176       POOL_DEBUG(SAT_DEBUG_RESULT, "====================================\n");
3177       printprobleminfo(solv, job, problem);
3178       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
3179       solution = 0;
3180       while ((solution = solver_next_solution(solv, problem, solution)) != 0)
3181         {
3182           element = 0;
3183           while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
3184             {
3185               if (p == 0)
3186                 {
3187                   /* job, rp is index into job queue */
3188                   what = job->elements[rp];
3189                   switch (job->elements[rp - 1])
3190                     {
3191                     case SOLVER_INSTALL_SOLVABLE:
3192                       s = pool->solvables + what;
3193                       if (solv->installed && s->repo == solv->installed)
3194                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, s));
3195                       else
3196                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solvable2str(pool, s));
3197                       break;
3198                     case SOLVER_ERASE_SOLVABLE:
3199                       s = pool->solvables + what;
3200                       if (solv->installed && s->repo == solv->installed)
3201                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solvable2str(pool, s));
3202                       else
3203                         POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, s));
3204                       break;
3205                     case SOLVER_INSTALL_SOLVABLE_NAME:
3206                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", id2str(pool, what));
3207                       break;
3208                     case SOLVER_ERASE_SOLVABLE_NAME:
3209                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", id2str(pool, what));
3210                       break;
3211                     case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3212                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable providing %s\n", dep2str(pool, what));
3213                       break;
3214                     case SOLVER_ERASE_SOLVABLE_PROVIDES:
3215                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables providing %s\n", dep2str(pool, what));
3216                       break;
3217                     case SOLVER_INSTALL_SOLVABLE_UPDATE:
3218                       s = pool->solvables + what;
3219                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solvable2str(pool, s));
3220                       break;
3221                     default:
3222                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do something different\n");
3223                       break;
3224                     }
3225                 }
3226               else
3227                 {
3228                   /* policy, replace p with rp */
3229                   s = pool->solvables + p;
3230                   sd = rp ? pool->solvables + rp : 0;
3231                   if (sd)
3232                     {
3233                       int gotone = 0;
3234                       if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
3235                         {
3236                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3237                           gotone = 1;
3238                         }
3239                       if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(pool, s, sd))
3240                         {
3241                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3242                           gotone = 1;
3243                         }
3244                       if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(pool, s, sd))
3245                         {
3246                           if (sd->vendor)
3247                             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));
3248                           else
3249                             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));
3250                           gotone = 1;
3251                         }
3252                       if (!gotone)
3253                         POOL_DEBUG(SAT_DEBUG_RESULT, "- allow replacement of %s with %s\n", solvable2str(pool, s), solvable2str(pool, sd));
3254                     }
3255                   else
3256                     {
3257                       POOL_DEBUG(SAT_DEBUG_RESULT, "- allow deinstallation of %s\n", solvable2str(pool, s));
3258                     }
3259
3260                 }
3261             }
3262           POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
3263         }
3264     }
3265 }
3266
3267
3268 /* for each installed solvable find which packages with *different* names
3269  * obsolete the solvable.
3270  * this index is used in policy_findupdatepackages if noupdateprovide is set.
3271  */
3272
3273 static void
3274 create_obsolete_index(Solver *solv)
3275 {
3276   Pool *pool = solv->pool;
3277   Solvable *s;
3278   Repo *installed = solv->installed;
3279   Id p, *pp, obs, *obsp, *obsoletes, *obsoletes_data;
3280   int i, n;
3281
3282   if (!installed || !installed->nsolvables)
3283     return;
3284   /* create reverse obsoletes map for installed solvables */
3285   solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
3286   for (i = 1; i < pool->nsolvables; i++)
3287     {
3288       s = pool->solvables + i;
3289       if (s->repo == installed)
3290         continue;
3291       if (!s->obsoletes)
3292         continue;
3293       if (!pool_installable(pool, s))
3294         continue;
3295       obsp = s->repo->idarraydata + s->obsoletes;
3296       while ((obs = *obsp++) != 0)
3297         FOR_PROVIDES(p, pp, obs)
3298           {
3299             if (pool->solvables[p].repo != installed)
3300               continue;
3301             if (pool->solvables[p].name == s->name)
3302               continue;
3303             obsoletes[p - installed->start]++;
3304           }
3305     }
3306   n = 0;
3307   for (i = 0; i < installed->nsolvables; i++)
3308     if (obsoletes[i])
3309       {
3310         n += obsoletes[i] + 1;
3311         obsoletes[i] = n;
3312       }
3313   solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
3314   POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
3315   for (i = pool->nsolvables - 1; i > 0; i--)
3316     {
3317       s = pool->solvables + i;
3318       if (s->repo == installed)
3319         continue;
3320       if (!s->obsoletes)
3321         continue;
3322       if (!pool_installable(pool, s))
3323         continue;
3324       obsp = s->repo->idarraydata + s->obsoletes;
3325       while ((obs = *obsp++) != 0)
3326         FOR_PROVIDES(p, pp, obs)
3327           {
3328             if (pool->solvables[p].repo != installed)
3329               continue;
3330             if (pool->solvables[p].name == s->name)
3331               continue;
3332             p -= installed->start;
3333             if (obsoletes_data[obsoletes[p]] != i)
3334               obsoletes_data[--obsoletes[p]] = i;
3335           }
3336     }
3337 }
3338
3339
3340 /*-----------------------------------------------------------------*/
3341 /* main() */
3342
3343 /*
3344  *
3345  * solve job queue
3346  *
3347  */
3348
3349 void
3350 solver_solve(Solver *solv, Queue *job)
3351 {
3352   Pool *pool = solv->pool;
3353   Repo *installed = solv->installed;
3354   int i;
3355   int oldnrules;
3356   Map addedmap;                /* '1' == have rpm-rules for solvable */
3357   Id how, what, p, *pp, d;
3358   Queue q;
3359   Solvable *s;
3360
3361   /* create whatprovides if not already there */
3362   if (!pool->whatprovides)
3363     pool_createwhatprovides(pool);
3364
3365   /* create obsolete index if needed */
3366   if (solv->noupdateprovide)
3367     create_obsolete_index(solv);
3368
3369   /*
3370    * create basic rule set of all involved packages
3371    * use addedmap bitmap to make sure we don't create rules twice
3372    * 
3373    */
3374
3375   map_init(&addedmap, pool->nsolvables);
3376   queue_init(&q);
3377   
3378   /*
3379    * always install our system solvable
3380    */
3381   MAPSET(&addedmap, SYSTEMSOLVABLE);
3382   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
3383   queue_push(&solv->decisionq_why, 0);
3384   solv->decisionmap[SYSTEMSOLVABLE] = 1;
3385
3386   /*
3387    * create rules for all package that could be involved with the solving
3388    * so called: rpm rules
3389    * 
3390    */
3391   if (installed)
3392     {
3393       oldnrules = solv->nrules;
3394       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
3395       FOR_REPO_SOLVABLES(installed, p, s)
3396         addrpmrulesforsolvable(solv, s, &addedmap);
3397       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3398       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
3399       oldnrules = solv->nrules;
3400       FOR_REPO_SOLVABLES(installed, p, s)
3401         addrpmrulesforupdaters(solv, s, &addedmap, 1);
3402       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3403     }
3404
3405   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for packages involved with a job ***\n");
3406   oldnrules = solv->nrules;
3407   for (i = 0; i < job->count; i += 2)
3408     {
3409       how = job->elements[i];
3410       what = job->elements[i + 1];
3411
3412       switch(how)
3413         {
3414         case SOLVER_INSTALL_SOLVABLE:
3415           addrpmrulesforsolvable(solv, pool->solvables + what, &addedmap);
3416           break;
3417         case SOLVER_INSTALL_SOLVABLE_NAME:
3418         case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3419           FOR_PROVIDES(p, pp, what)
3420             {
3421               /* if by name, ensure that the name matches */
3422               if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
3423                 continue;
3424               addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3425             }
3426           break;
3427         case SOLVER_INSTALL_SOLVABLE_UPDATE:
3428           /* dont allow downgrade */
3429           addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
3430           break;
3431         }
3432     }
3433   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3434
3435   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
3436
3437   oldnrules = solv->nrules;
3438   addrpmrulesforweak(solv, &addedmap);
3439   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3440
3441   IF_POOLDEBUG (SAT_DEBUG_STATS)
3442     {
3443       int possible = 0, installable = 0;
3444       for (i = 1; i < pool->nsolvables; i++)
3445         {
3446           if (pool_installable(pool, pool->solvables + i))
3447             installable++;
3448           if (MAPTST(&addedmap, i))
3449             possible++;
3450         }
3451       POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving (rules has been generated for)\n", possible, installable);
3452     }
3453
3454   /*
3455    * first pass done, we now have all the rpm rules we need.
3456    * unify existing rules before going over all job rules and
3457    * policy rules.
3458    * at this point the system is always solvable,
3459    * as an empty system (remove all packages) is a valid solution
3460    */
3461   
3462   unifyrules(solv);     /* remove duplicate rpm rules */
3463   solv->directdecisions = solv->decisionq.count;
3464
3465   POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
3466   IF_POOLDEBUG (SAT_DEBUG_SCHUBI) 
3467     printdecisions (solv);
3468
3469   /*
3470    * now add all job rules
3471    */
3472
3473   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add JOB rules ***\n");  
3474   
3475   solv->jobrules = solv->nrules;
3476
3477   for (i = 0; i < job->count; i += 2)
3478     {
3479       oldnrules = solv->nrules;
3480
3481       how = job->elements[i];
3482       what = job->elements[i + 1];
3483       switch(how)
3484         {
3485         case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
3486           s = pool->solvables + what;
3487           POOL_DEBUG(SAT_DEBUG_JOB, "job: install solvable %s\n", solvable2str(pool, s));
3488           addrule(solv, what, 0);                       /* install by Id */
3489           queue_push(&solv->ruletojob, i);
3490           break;
3491         case SOLVER_ERASE_SOLVABLE:
3492           s = pool->solvables + what;
3493           POOL_DEBUG(SAT_DEBUG_JOB, "job: erase solvable %s\n", solvable2str(pool, s));
3494           addrule(solv, -what, 0);                      /* remove by Id */
3495           queue_push(&solv->ruletojob, i);
3496           break;
3497         case SOLVER_INSTALL_SOLVABLE_NAME:              /* install by capability */
3498         case SOLVER_INSTALL_SOLVABLE_PROVIDES:
3499           if (how == SOLVER_INSTALL_SOLVABLE_NAME)
3500             POOL_DEBUG(SAT_DEBUG_JOB, "job: install name %s\n", id2str(pool, what));
3501           if (how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
3502             POOL_DEBUG(SAT_DEBUG_JOB, "job: install provides %s\n", dep2str(pool, what));
3503           queue_empty(&q);
3504           FOR_PROVIDES(p, pp, what)
3505             {
3506               /* if by name, ensure that the name matches */
3507               if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
3508                 continue;
3509               queue_push(&q, p);
3510             }
3511           if (!q.count) 
3512             {
3513               /* no provider, make this an impossible rule */
3514               queue_push(&q, -SYSTEMSOLVABLE);
3515             }
3516
3517           p = queue_shift(&q);         /* get first provider */
3518           if (!q.count)
3519             d = 0;                     /* single provider ? -> make assertion */
3520           else
3521             d = pool_queuetowhatprovides(pool, &q);   /* get all providers */
3522           addrule(solv, p, d);         /* add 'requires' rule */
3523           queue_push(&solv->ruletojob, i);
3524           break;
3525         case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
3526         case SOLVER_ERASE_SOLVABLE_PROVIDES:
3527           if (how == SOLVER_ERASE_SOLVABLE_NAME)
3528             POOL_DEBUG(SAT_DEBUG_JOB, "job: erase name %s\n", id2str(pool, what));
3529           if (how == SOLVER_ERASE_SOLVABLE_PROVIDES)
3530             POOL_DEBUG(SAT_DEBUG_JOB, "job: erase provides %s\n", dep2str(pool, what));
3531           FOR_PROVIDES(p, pp, what)
3532             {
3533               /* if by name, ensure that the name matches */
3534               if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
3535                 continue;
3536               addrule(solv, -p, 0);  /* add 'remove' rule */
3537               queue_push(&solv->ruletojob, i);
3538             }
3539           break;
3540         case SOLVER_INSTALL_SOLVABLE_UPDATE:              /* find update for solvable */
3541           s = pool->solvables + what;
3542           POOL_DEBUG(SAT_DEBUG_JOB, "job: update %s\n", solvable2str(pool, s));
3543           addupdaterule(solv, s, 0);
3544           queue_push(&solv->ruletojob, i);
3545           break;
3546         }
3547       IF_POOLDEBUG (SAT_DEBUG_JOB)
3548         {
3549           int j;
3550           if (solv->nrules == oldnrules)
3551             POOL_DEBUG(SAT_DEBUG_JOB, " - no rule created");
3552           for (j = oldnrules; j < solv->nrules; j++)
3553             {
3554               POOL_DEBUG(SAT_DEBUG_JOB, " - job ");
3555               printrule(solv, SAT_DEBUG_JOB, solv->rules + j);
3556             }
3557         }
3558     }
3559   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3560
3561   /*
3562    * now add system rules
3563    * 
3564    */
3565
3566   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add system rules ***\n");
3567   
3568   
3569   solv->systemrules = solv->nrules;
3570
3571   /*
3572    * create rules for updating installed solvables
3573    * 
3574    */
3575   
3576   if (installed && !solv->allowuninstall)
3577     {                                  /* loop over all installed solvables */
3578       /* we create all update rules, but disable some later on depending on the job */
3579       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3580         if (s->repo == installed)
3581           addupdaterule(solv, s, 0); /* allowall = 0 */
3582         else
3583           addupdaterule(solv, 0, 0);    /* create dummy rule;  allowall = 0  */
3584       /* consistency check: we added a rule for _every_ system solvable */
3585       assert(solv->nrules - solv->systemrules == installed->end - installed->start);
3586     }
3587
3588   /* create special weak system rules */
3589   /* those are used later on to keep a version of the installed packages in
3590      best effort mode */
3591   if (installed && installed->nsolvables)
3592     {
3593       solv->weaksystemrules = sat_calloc(installed->end - installed->start, sizeof(Id));
3594       FOR_REPO_SOLVABLES(installed, p, s)
3595         {
3596           policy_findupdatepackages(solv, s, &q, 1);
3597           if (q.count)
3598             solv->weaksystemrules[p - installed->start] = pool_queuetowhatprovides(pool, &q);
3599         }
3600     }
3601
3602   /* free unneeded memory */
3603   map_free(&addedmap);
3604   queue_free(&q);
3605
3606   solv->weakrules = solv->nrules;
3607
3608   /* try real hard to keep packages installed */
3609   if (0)
3610     {
3611       FOR_REPO_SOLVABLES(installed, p, s)
3612         {
3613           /* FIXME: can't work with refine_suggestion! */
3614           /* need to always add the rule but disable it */
3615           if (MAPTST(&solv->noupdate, p - installed->start))
3616             continue;
3617           d = solv->weaksystemrules[p - installed->start];
3618           addrule(solv, p, d);
3619         }
3620     }
3621
3622   /* all new rules are learnt after this point */
3623   solv->learntrules = solv->nrules;
3624
3625   /* disable system rules that conflict with our job */
3626   disableupdaterules(solv, job, -1);
3627
3628   /* make decisions based on job/system assertions */
3629   makeruledecisions(solv);
3630
3631   /* create watches chains */
3632   makewatches(solv);
3633
3634   POOL_DEBUG(SAT_DEBUG_STATS, "problems so far: %d\n", solv->problems.count);
3635
3636   /* solve! */
3637   run_solver(solv, 1, 1);
3638
3639   /* find suggested packages */
3640   if (!solv->problems.count)
3641     {
3642       Id sug, *sugp, p, *pp;
3643
3644       /* create map of all suggests that are still open */
3645       solv->recommends_index = -1;
3646       MAPZERO(&solv->suggestsmap);
3647       for (i = 0; i < solv->decisionq.count; i++)
3648         {
3649           p = solv->decisionq.elements[i];
3650           if (p < 0)
3651             continue;
3652           s = pool->solvables + p;
3653           if (s->suggests)
3654             {
3655               sugp = s->repo->idarraydata + s->suggests;
3656               while ((sug = *sugp++) != 0)
3657                 {
3658                   FOR_PROVIDES(p, pp, sug)
3659                     if (solv->decisionmap[p] > 0)
3660                       break;
3661                   if (p)
3662                     continue;   /* already fulfilled */
3663                   FOR_PROVIDES(p, pp, sug)
3664                     MAPSET(&solv->suggestsmap, p);
3665                 }
3666             }
3667         }
3668       for (i = 1; i < pool->nsolvables; i++)
3669         {
3670           if (solv->decisionmap[i] != 0)
3671             continue;
3672           s = pool->solvables + i;
3673           if (!MAPTST(&solv->suggestsmap, i))
3674             {
3675               if (!s->enhances)
3676                 continue;
3677               if (!pool_installable(pool, s))
3678                 continue;
3679               if (!solver_is_enhancing(solv, s))
3680                 continue;
3681             }
3682           queue_push(&solv->suggestions, i);
3683         }
3684       policy_filter_unwanted(solv, &solv->suggestions, 0, POLICY_MODE_SUGGEST);
3685     }
3686
3687   if (solv->problems.count)
3688     problems_to_solutions(solv, job);
3689 }
3690