xref: /haiku/src/libs/libsolv/solv/solver.c (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
1 /*
2  * Copyright (c) 2007-2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7 
8 /*
9  * solver.c
10  *
11  * SAT based dependency solver
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <assert.h>
19 
20 #include "solver.h"
21 #include "solver_private.h"
22 #include "bitmap.h"
23 #include "pool.h"
24 #include "util.h"
25 #include "policy.h"
26 #include "poolarch.h"
27 #include "solverdebug.h"
28 
29 #define RULES_BLOCK 63
30 
31 /********************************************************************
32  *
33  * dependency check helpers
34  *
35  */
36 
37 /*-------------------------------------------------------------------
38  * handle split provides
39  *
40  * a splitprovides dep looks like
41  *     namespace:splitprovides(pkg REL_WITH path)
42  * and is only true if pkg is installed and contains the specified path.
43  * we also make sure that pkg is selected for an update, otherwise the
44  * update would always be forced onto the user.
45  */
46 int
47 solver_splitprovides(Solver *solv, Id dep)
48 {
49   Pool *pool = solv->pool;
50   Id p, pp;
51   Reldep *rd;
52   Solvable *s;
53 
54   if (!solv->dosplitprovides || !solv->installed || (!solv->updatemap_all && !solv->updatemap.size))
55     return 0;
56   if (!ISRELDEP(dep))
57     return 0;
58   rd = GETRELDEP(pool, dep);
59   if (rd->flags != REL_WITH)
60     return 0;
61   FOR_PROVIDES(p, pp, dep)
62     {
63       /* here we have packages that provide the correct name and contain the path,
64        * now do extra filtering */
65       s = pool->solvables + p;
66       if (s->repo == solv->installed && s->name == rd->name &&
67           (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
68 	return 1;
69     }
70   return 0;
71 }
72 
73 
74 /*-------------------------------------------------------------------
75  * solver_dep_installed
76  */
77 
78 int
79 solver_dep_installed(Solver *solv, Id dep)
80 {
81 #if 0
82   Pool *pool = solv->pool;
83   Id p, pp;
84 
85   if (ISRELDEP(dep))
86     {
87       Reldep *rd = GETRELDEP(pool, dep);
88       if (rd->flags == REL_AND)
89 	{
90 	  if (!solver_dep_installed(solv, rd->name))
91 	    return 0;
92 	  return solver_dep_installed(solv, rd->evr);
93 	}
94       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
95 	return solver_dep_installed(solv, rd->evr);
96     }
97   FOR_PROVIDES(p, pp, dep)
98     {
99       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
100 	return 1;
101     }
102 #endif
103   return 0;
104 }
105 
106 /* mirrors solver_dep_installed, but returns 2 if a
107  * dependency listed in solv->installsuppdepq was involved */
108 static int
109 solver_check_installsuppdepq_dep(Solver *solv, Id dep)
110 {
111   Pool *pool = solv->pool;
112   Id p, pp;
113   Queue *q;
114 
115   if (ISRELDEP(dep))
116     {
117       Reldep *rd = GETRELDEP(pool, dep);
118       if (rd->flags == REL_AND)
119         {
120 	  int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
121           if (!r1)
122             return 0;
123 	  r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
124 	  if (!r2)
125 	    return 0;
126           return r1 == 2 || r2 == 2 ? 2 : 1;
127         }
128       if (rd->flags == REL_OR)
129 	{
130 	  int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
131 	  r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
132 	  if (!r1 && !r2)
133 	    return 0;
134           return r1 == 2 || r2 == 2 ? 2 : 1;
135 	}
136       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
137         return solver_splitprovides(solv, rd->evr);
138       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
139         return solver_dep_installed(solv, rd->evr);
140       if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
141 	{
142 	  int i;
143 	  for (i = 0; i < q->count; i++)
144 	    if (q->elements[i] == dep || q->elements[i] == rd->name)
145 	      return 2;
146 	}
147     }
148   FOR_PROVIDES(p, pp, dep)
149     if (solv->decisionmap[p] > 0)
150       return 1;
151   return 0;
152 }
153 
154 static int
155 solver_check_installsuppdepq(Solver *solv, Solvable *s)
156 {
157   Id sup, *supp;
158   supp = s->repo->idarraydata + s->supplements;
159   while ((sup = *supp++) != 0)
160     if (solver_check_installsuppdepq_dep(solv, sup) == 2)
161       return 1;
162   return 0;
163 }
164 
165 static Id
166 autouninstall(Solver *solv, Id *problem)
167 {
168   Pool *pool = solv->pool;
169   int i;
170   int lastfeature = 0, lastupdate = 0;
171   Id v;
172   Id extraflags = -1;
173 
174   for (i = 0; (v = problem[i]) != 0; i++)
175     {
176       if (v < 0)
177 	extraflags &= solv->job.elements[-v - 1];
178       if (v >= solv->featurerules && v < solv->featurerules_end)
179 	if (v > lastfeature)
180 	  lastfeature = v;
181       if (v >= solv->updaterules && v < solv->updaterules_end)
182 	{
183 	  /* check if identical to feature rule */
184 	  Id p = solv->rules[v].p;
185 	  Rule *r;
186 	  if (p <= 0)
187 	    continue;
188 	  r = solv->rules + solv->featurerules + (p - solv->installed->start);
189 	  if (!r->p)
190 	    {
191 	      /* update rule == feature rule */
192 	      if (v > lastfeature)
193 		lastfeature = v;
194 	      continue;
195 	    }
196 	  if (v > lastupdate)
197 	    lastupdate = v;
198 	}
199     }
200   if (!lastupdate && !lastfeature)
201     return 0;
202   v = lastupdate ? lastupdate : lastfeature;
203   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
204   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
205   solver_disableproblem(solv, v);
206   if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
207     {
208       /* add the package to the updatepkgs list, this will automatically turn
209        * on cleandeps mode */
210       Id p = solv->rules[v].p;
211       if (!solv->cleandeps_updatepkgs)
212 	{
213 	  solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
214 	  queue_init(solv->cleandeps_updatepkgs);
215 	}
216       if (p > 0)
217 	{
218 	  int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
219           queue_pushunique(solv->cleandeps_updatepkgs, p);
220 	  if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
221 	    solver_disablepolicyrules(solv);
222 	}
223     }
224   return v;
225 }
226 
227 /************************************************************************/
228 
229 /*
230  * enable/disable learnt rules
231  *
232  * we have enabled or disabled some of our rules. We now reenable all
233  * of our learnt rules except the ones that were learnt from rules that
234  * are now disabled.
235  */
236 static void
237 enabledisablelearntrules(Solver *solv)
238 {
239   Pool *pool = solv->pool;
240   Rule *r;
241   Id why, *whyp;
242   int i;
243 
244   POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
245   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
246     {
247       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
248       while ((why = *whyp++) != 0)
249 	{
250 	  assert(why > 0 && why < i);
251 	  if (solv->rules[why].d < 0)
252 	    break;
253 	}
254       /* why != 0: we found a disabled rule, disable the learnt rule */
255       if (why && r->d >= 0)
256 	{
257 	  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
258 	    {
259 	      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
260 	      solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
261 	    }
262           solver_disablerule(solv, r);
263 	}
264       else if (!why && r->d < 0)
265 	{
266 	  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
267 	    {
268 	      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
269 	      solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
270 	    }
271           solver_enablerule(solv, r);
272 	}
273     }
274 }
275 
276 
277 /*
278  * make assertion rules into decisions
279  *
280  * Go through rules and add direct assertions to the decisionqueue.
281  * If we find a conflict, disable rules and add them to problem queue.
282  */
283 
284 static void
285 makeruledecisions(Solver *solv)
286 {
287   Pool *pool = solv->pool;
288   int i, ri, ii;
289   Rule *r, *rr;
290   Id v, vv;
291   int decisionstart;
292   int record_proof = 1;
293   int oldproblemcount;
294   int havedisabled = 0;
295 
296   /* The system solvable is always installed first */
297   assert(solv->decisionq.count == 0);
298   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
299   queue_push(&solv->decisionq_why, 0);
300   solv->decisionmap[SYSTEMSOLVABLE] = 1;	/* installed at level '1' */
301 
302   decisionstart = solv->decisionq.count;
303   for (;;)
304     {
305       /* if we needed to re-run, back up decisions to decisionstart */
306       while (solv->decisionq.count > decisionstart)
307 	{
308 	  v = solv->decisionq.elements[--solv->decisionq.count];
309 	  --solv->decisionq_why.count;
310 	  vv = v > 0 ? v : -v;
311 	  solv->decisionmap[vv] = 0;
312 	}
313 
314       /* note that the ruleassertions queue is ordered */
315       for (ii = 0; ii < solv->ruleassertions.count; ii++)
316 	{
317 	  ri = solv->ruleassertions.elements[ii];
318 	  r = solv->rules + ri;
319 
320           if (havedisabled && ri >= solv->learntrules)
321 	    {
322 	      /* just started with learnt rule assertions. If we have disabled
323                * some rules, adapt the learnt rule status */
324 	      enabledisablelearntrules(solv);
325 	      havedisabled = 0;
326 	    }
327 
328 	  if (r->d < 0 || !r->p || r->w2)	/* disabled, dummy or no assertion */
329 	    continue;
330 
331 	  /* do weak rules in phase 2 */
332 	  if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
333 	    continue;
334 
335 	  v = r->p;
336 	  vv = v > 0 ? v : -v;
337 
338 	  if (!solv->decisionmap[vv])          /* if not yet decided */
339 	    {
340 	      queue_push(&solv->decisionq, v);
341 	      queue_push(&solv->decisionq_why, r - solv->rules);
342 	      solv->decisionmap[vv] = v > 0 ? 1 : -1;
343 	      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
344 		{
345 		  Solvable *s = solv->pool->solvables + vv;
346 		  if (v < 0)
347 		    POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
348 		  else
349 		    POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
350 		}
351 	      continue;
352 	    }
353 
354 	  /* check against previous decision: is there a conflict? */
355 	  if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
356 	    continue;
357 	  if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
358 	    continue;
359 
360 	  /*
361 	   * found a conflict!
362 	   *
363 	   * The rule (r) we're currently processing says something
364 	   * different (v = r->p) than a previous decision (decisionmap[abs(v)])
365 	   * on this literal
366 	   */
367 
368 	  if (ri >= solv->learntrules)
369 	    {
370 	      /* conflict with a learnt rule */
371 	      /* can happen when packages cannot be installed for multiple reasons. */
372 	      /* we disable the learnt rule in this case */
373 	      /* (XXX: we should really call analyze_unsolvable_rule here!) */
374 	      solver_disablerule(solv, r);
375 	      continue;
376 	    }
377 
378 	  /*
379 	   * find the decision which is the "opposite" of the rule
380 	   */
381 	  for (i = 0; i < solv->decisionq.count; i++)
382 	    if (solv->decisionq.elements[i] == -v)
383 	      break;
384 	  assert(i < solv->decisionq.count);         /* assert that we found it */
385 	  oldproblemcount = solv->problems.count;
386 
387 	  /*
388 	   * conflict with system solvable ?
389 	   */
390 	  if (v == -SYSTEMSOLVABLE)
391 	    {
392 	      if (record_proof)
393 		{
394 		  queue_push(&solv->problems, solv->learnt_pool.count);
395 		  queue_push(&solv->learnt_pool, ri);
396 		  queue_push(&solv->learnt_pool, 0);
397 		}
398 	      else
399 		queue_push(&solv->problems, 0);
400 	      POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
401 	      if  (ri >= solv->jobrules && ri < solv->jobrules_end)
402 		v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
403 	      else
404 		v = ri;
405 	      queue_push(&solv->problems, v);
406 	      queue_push(&solv->problems, 0);
407 	      if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
408 		solv->problems.count = oldproblemcount;
409 	      solver_disableproblem(solv, v);
410 	      havedisabled = 1;
411 	      break;	/* start over */
412 	    }
413 
414 	  assert(solv->decisionq_why.elements[i] > 0);
415 
416 	  /*
417 	   * conflict with an rpm rule ?
418 	   */
419 	  if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
420 	    {
421 	      if (record_proof)
422 		{
423 		  queue_push(&solv->problems, solv->learnt_pool.count);
424 		  queue_push(&solv->learnt_pool, ri);
425 		  queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
426 		  queue_push(&solv->learnt_pool, 0);
427 		}
428 	      else
429 		queue_push(&solv->problems, 0);
430 	      assert(v > 0 || v == -SYSTEMSOLVABLE);
431 	      POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
432 	      if (ri >= solv->jobrules && ri < solv->jobrules_end)
433 		v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
434 	      else
435 		v = ri;
436 	      queue_push(&solv->problems, v);
437 	      queue_push(&solv->problems, 0);
438 	      if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
439 		solv->problems.count = oldproblemcount;
440 	      solver_disableproblem(solv, v);
441 	      havedisabled = 1;
442 	      break;	/* start over */
443 	    }
444 
445 	  /*
446 	   * conflict with another job or update/feature rule
447 	   */
448 
449 	  /* record proof */
450 	  if (record_proof)
451 	    {
452 	      queue_push(&solv->problems, solv->learnt_pool.count);
453 	      queue_push(&solv->learnt_pool, ri);
454 	      queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
455 	      queue_push(&solv->learnt_pool, 0);
456 	    }
457 	  else
458 	    queue_push(&solv->problems, 0);
459 
460 	  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
461 
462 	  /*
463 	   * push all of our rules (can only be feature or job rules)
464 	   * asserting this literal on the problem stack
465 	   */
466 	  for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
467 	    {
468 	      if (rr->d < 0                          /* disabled */
469 		  || rr->w2)                         /*  or no assertion */
470 		continue;
471 	      if (rr->p != vv                        /* not affecting the literal */
472 		  && rr->p != -vv)
473 		continue;
474 	      if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
475 		continue;
476 
477 	      POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
478 	      solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
479 
480 	      v = i;
481 	      if (i >= solv->jobrules && i < solv->jobrules_end)
482 		v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
483 	      queue_push(&solv->problems, v);
484 	    }
485 	  queue_push(&solv->problems, 0);
486 
487 	  if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
488 	    solv->problems.count = oldproblemcount;
489 
490 	  for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
491 	    solver_disableproblem(solv, solv->problems.elements[i]);
492 	  havedisabled = 1;
493 	  break;	/* start over */
494 	}
495       if (ii < solv->ruleassertions.count)
496 	continue;
497 
498       /*
499        * phase 2: now do the weak assertions
500        */
501       for (ii = 0; ii < solv->ruleassertions.count; ii++)
502 	{
503 	  ri = solv->ruleassertions.elements[ii];
504 	  r = solv->rules + ri;
505 	  if (r->d < 0 || r->w2)	                 /* disabled or no assertion */
506 	    continue;
507 	  if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
508 	    continue;
509 	  v = r->p;
510 	  vv = v > 0 ? v : -v;
511 
512 	  if (!solv->decisionmap[vv])          /* if not yet decided */
513 	    {
514 	      queue_push(&solv->decisionq, v);
515 	      queue_push(&solv->decisionq_why, r - solv->rules);
516 	      solv->decisionmap[vv] = v > 0 ? 1 : -1;
517 	      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
518 		{
519 		  Solvable *s = solv->pool->solvables + vv;
520 		  if (v < 0)
521 		    POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
522 		  else
523 		    POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
524 		}
525 	      continue;
526 	    }
527 	  /* check against previous decision: is there a conflict? */
528 	  if (v > 0 && solv->decisionmap[vv] > 0)
529 	    continue;
530 	  if (v < 0 && solv->decisionmap[vv] < 0)
531 	    continue;
532 
533 	  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
534 	  solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
535 
536 	  if (ri >= solv->jobrules && ri < solv->jobrules_end)
537 	    v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
538 	  else
539 	    v = ri;
540 	  solver_disableproblem(solv, v);
541 	  if (v < 0)
542 	    solver_reenablepolicyrules(solv, -v);
543 	  havedisabled = 1;
544 	  break;	/* start over */
545 	}
546       if (ii == solv->ruleassertions.count)
547 	break;	/* finished! */
548     }
549 }
550 
551 
552 /********************************************************************/
553 /* watches */
554 
555 
556 /*-------------------------------------------------------------------
557  * makewatches
558  *
559  * initial setup for all watches
560  */
561 
562 static void
563 makewatches(Solver *solv)
564 {
565   Rule *r;
566   int i;
567   int nsolvables = solv->pool->nsolvables;
568 
569   solv_free(solv->watches);
570 				       /* lower half for removals, upper half for installs */
571   solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
572 #if 1
573   /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
574   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
575 #else
576   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
577 #endif
578     {
579       if (!r->w2)		/* assertions do not need watches */
580 	continue;
581 
582       /* see addwatches_rule(solv, r) */
583       r->n1 = solv->watches[nsolvables + r->w1];
584       solv->watches[nsolvables + r->w1] = r - solv->rules;
585 
586       r->n2 = solv->watches[nsolvables + r->w2];
587       solv->watches[nsolvables + r->w2] = r - solv->rules;
588     }
589 }
590 
591 
592 /*-------------------------------------------------------------------
593  *
594  * add watches (for a new learned rule)
595  * sets up watches for a single rule
596  *
597  * see also makewatches() above.
598  */
599 
600 static inline void
601 addwatches_rule(Solver *solv, Rule *r)
602 {
603   int nsolvables = solv->pool->nsolvables;
604 
605   r->n1 = solv->watches[nsolvables + r->w1];
606   solv->watches[nsolvables + r->w1] = r - solv->rules;
607 
608   r->n2 = solv->watches[nsolvables + r->w2];
609   solv->watches[nsolvables + r->w2] = r - solv->rules;
610 }
611 
612 
613 /********************************************************************/
614 /*
615  * rule propagation
616  */
617 
618 
619 /* shortcuts to check if a literal (positive or negative) assignment
620  * evaluates to 'true' or 'false'
621  */
622 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
623 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
624 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
625 
626 /*-------------------------------------------------------------------
627  *
628  * propagate
629  *
630  * make decision and propagate to all rules
631  *
632  * Evaluate each term affected by the decision (linked through watches).
633  * If we find unit rules we make new decisions based on them.
634  *
635  * return : 0 = everything is OK
636  *          rule = conflict found in this rule
637  */
638 
639 static Rule *
640 propagate(Solver *solv, int level)
641 {
642   Pool *pool = solv->pool;
643   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
644   Rule *r;                    /* rule */
645   Id p, pkg, other_watch;
646   Id *dp;
647   Id *decisionmap = solv->decisionmap;
648 
649   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
650 
651   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
652 
653   /* foreach non-propagated decision */
654   while (solv->propagate_index < solv->decisionq.count)
655     {
656 	/*
657 	 * 'pkg' was just decided
658 	 * negate because our watches trigger if literal goes FALSE
659 	 */
660       pkg = -solv->decisionq.elements[solv->propagate_index++];
661 
662       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
663         {
664 	  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
665 	  solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
666         }
667 
668       /* foreach rule where 'pkg' is now FALSE */
669       for (rp = watches + pkg; *rp; rp = next_rp)
670 	{
671 	  r = solv->rules + *rp;
672 	  if (r->d < 0)
673 	    {
674 	      /* rule is disabled, goto next */
675 	      if (pkg == r->w1)
676 	        next_rp = &r->n1;
677 	      else
678 	        next_rp = &r->n2;
679 	      continue;
680 	    }
681 
682 	  IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
683 	    {
684 	      POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
685 	      solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
686 	    }
687 
688 	    /* 'pkg' was just decided (was set to FALSE)
689 	     *
690 	     *  now find other literal watch, check clause
691 	     *   and advance on linked list
692 	     */
693 	  if (pkg == r->w1)
694 	    {
695 	      other_watch = r->w2;
696 	      next_rp = &r->n1;
697 	    }
698 	  else
699 	    {
700 	      other_watch = r->w1;
701 	      next_rp = &r->n2;
702 	    }
703 
704 	    /*
705 	     * This term is already true (through the other literal)
706 	     * so we have nothing to do
707 	     */
708 	  if (DECISIONMAP_TRUE(other_watch))
709 	    continue;
710 
711 	    /*
712 	     * The other literal is FALSE or UNDEF
713 	     *
714 	     */
715 
716           if (r->d)
717 	    {
718 	      /* Not a binary clause, try to move our watch.
719 	       *
720 	       * Go over all literals and find one that is
721 	       *   not other_watch
722 	       *   and not FALSE
723 	       *
724 	       * (TRUE is also ok, in that case the rule is fulfilled)
725 	       */
726 	      if (r->p                                /* we have a 'p' */
727 		  && r->p != other_watch              /* which is not watched */
728 		  && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
729 		{
730 		  p = r->p;
731 		}
732 	      else                                    /* go find a 'd' to make 'true' */
733 		{
734 		  /* foreach p in 'd'
735 		     we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
736 		   */
737 		  for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
738 		    {
739 		      if (p != other_watch              /* which is not watched */
740 		          && !DECISIONMAP_FALSE(p))     /* and not FALSE */
741 		        break;
742 		    }
743 		}
744 
745 	      if (p)
746 		{
747 		  /*
748 		   * if we found some p that is UNDEF or TRUE, move
749 		   * watch to it
750 		   */
751 		  IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
752 		    {
753 		      if (p > 0)
754 			POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
755 		      else
756 			POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
757 		    }
758 
759 		  *rp = *next_rp;
760 		  next_rp = rp;
761 
762 		  if (pkg == r->w1)
763 		    {
764 		      r->w1 = p;
765 		      r->n1 = watches[p];
766 		    }
767 		  else
768 		    {
769 		      r->w2 = p;
770 		      r->n2 = watches[p];
771 		    }
772 		  watches[p] = r - solv->rules;
773 		  continue;
774 		}
775 	      /* search failed, thus all unwatched literals are FALSE */
776 
777 	    } /* not binary */
778 
779           /*
780 	   * unit clause found, set literal other_watch to TRUE
781 	   */
782 
783 	  if (DECISIONMAP_FALSE(other_watch))	   /* check if literal is FALSE */
784 	    return r;  		                   /* eek, a conflict! */
785 
786 	  IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
787 	    {
788 	      POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "   unit ");
789 	      solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
790 	    }
791 
792 	  if (other_watch > 0)
793             decisionmap[other_watch] = level;    /* install! */
794 	  else
795 	    decisionmap[-other_watch] = -level;  /* remove! */
796 
797 	  queue_push(&solv->decisionq, other_watch);
798 	  queue_push(&solv->decisionq_why, r - solv->rules);
799 
800 	  IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
801 	    {
802 	      if (other_watch > 0)
803 		POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
804 	      else
805 		POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
806 	    }
807 
808 	} /* foreach rule involving 'pkg' */
809 
810     } /* while we have non-decided decisions */
811 
812   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
813 
814   return 0;	/* all is well */
815 }
816 
817 
818 /********************************************************************/
819 /* Analysis */
820 
821 /*-------------------------------------------------------------------
822  *
823  * analyze
824  *   and learn
825  */
826 
827 static int
828 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
829 {
830   Pool *pool = solv->pool;
831   Queue r;
832   Id r_buf[4];
833   int rlevel = 1;
834   Map seen;		/* global? */
835   Id d, v, vv, *dp, why;
836   int l, i, idx;
837   int num = 0, l1num = 0;
838   int learnt_why = solv->learnt_pool.count;
839   Id *decisionmap = solv->decisionmap;
840 
841   queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
842 
843   POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
844   map_init(&seen, pool->nsolvables);
845   idx = solv->decisionq.count;
846   for (;;)
847     {
848       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
849 	solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
850       queue_push(&solv->learnt_pool, c - solv->rules);
851       d = c->d < 0 ? -c->d - 1 : c->d;
852       dp = d ? pool->whatprovidesdata + d : 0;
853       /* go through all literals of the rule */
854       for (i = -1; ; i++)
855 	{
856 	  if (i == -1)
857 	    v = c->p;
858 	  else if (d == 0)
859 	    v = i ? 0 : c->w2;
860 	  else
861 	    v = *dp++;
862 	  if (v == 0)
863 	    break;
864 
865 	  if (DECISIONMAP_TRUE(v))	/* the one true literal */
866 	    continue;
867 	  vv = v > 0 ? v : -v;
868 	  if (MAPTST(&seen, vv))
869 	    continue;
870 	  l = solv->decisionmap[vv];
871 	  if (l < 0)
872 	    l = -l;
873 	  MAPSET(&seen, vv);		/* mark that we also need to look at this literal */
874 	  if (l == 1)
875 	    l1num++;			/* need to do this one in level1 pass */
876 	  else if (l == level)
877 	    num++;			/* need to do this one as well */
878 	  else
879 	    {
880 	      queue_push(&r, v);	/* not level1 or conflict level, add to new rule */
881 	      if (l > rlevel)
882 		rlevel = l;
883 	    }
884 	}
885 l1retry:
886       if (!num && !--l1num)
887 	break;	/* all level 1 literals done */
888 
889       /* find the next literal to investigate */
890       /* (as num + l1num > 0, we know that we'll always find one) */
891       for (;;)
892 	{
893 	  assert(idx > 0);
894 	  v = solv->decisionq.elements[--idx];
895 	  vv = v > 0 ? v : -v;
896 	  if (MAPTST(&seen, vv))
897 	    break;
898 	}
899       MAPCLR(&seen, vv);
900 
901       if (num && --num == 0)
902 	{
903 	  *pr = -v;	/* so that v doesn't get lost */
904 	  if (!l1num)
905 	    break;
906 	  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
907 	  /* clear non-l1 bits from seen map */
908 	  for (i = 0; i < r.count; i++)
909 	    {
910 	      v = r.elements[i];
911 	      MAPCLR(&seen, v > 0 ? v : -v);
912 	    }
913 	  /* only level 1 marks left in seen map */
914 	  l1num++;	/* as l1retry decrements it */
915 	  goto l1retry;
916 	}
917 
918       why = solv->decisionq_why.elements[idx];
919       if (why <= 0)	/* just in case, maybe for SYSTEMSOLVABLE */
920 	goto l1retry;
921       c = solv->rules + why;
922     }
923   map_free(&seen);
924 
925   if (r.count == 0)
926     *dr = 0;
927   else if (r.count == 1 && r.elements[0] < 0)
928     *dr = r.elements[0];
929   else
930     *dr = pool_queuetowhatprovides(pool, &r);
931   IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
932     {
933       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
934       solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
935       for (i = 0; i < r.count; i++)
936         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
937     }
938   /* push end marker on learnt reasons stack */
939   queue_push(&solv->learnt_pool, 0);
940   if (whyp)
941     *whyp = learnt_why;
942   queue_free(&r);
943   solv->stats_learned++;
944   return rlevel;
945 }
946 
947 
948 /*-------------------------------------------------------------------
949  *
950  * solver_reset
951  *
952  * reset all solver decisions
953  * called after rules have been enabled/disabled
954  */
955 
956 void
957 solver_reset(Solver *solv)
958 {
959   Pool *pool = solv->pool;
960   int i;
961   Id v;
962 
963   /* rewind all decisions */
964   for (i = solv->decisionq.count - 1; i >= 0; i--)
965     {
966       v = solv->decisionq.elements[i];
967       solv->decisionmap[v > 0 ? v : -v] = 0;
968     }
969   queue_empty(&solv->decisionq_why);
970   queue_empty(&solv->decisionq);
971   solv->recommends_index = -1;
972   solv->propagate_index = 0;
973   queue_empty(&solv->branches);
974 
975   /* adapt learnt rule status to new set of enabled/disabled rules */
976   enabledisablelearntrules(solv);
977 
978   /* redo all assertion rule decisions */
979   makeruledecisions(solv);
980   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
981 }
982 
983 
984 /*-------------------------------------------------------------------
985  *
986  * analyze_unsolvable_rule
987  *
988  * recursion helper used by analyze_unsolvable
989  */
990 
991 static void
992 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
993 {
994   Pool *pool = solv->pool;
995   int i;
996   Id why = r - solv->rules;
997 
998   IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
999     solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
1000   if (solv->learntrules && why >= solv->learntrules)
1001     {
1002       if (MAPTST(rseen, why - solv->learntrules))
1003 	return;
1004       MAPSET(rseen, why - solv->learntrules);
1005       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1006 	if (solv->learnt_pool.elements[i] > 0)
1007 	  analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
1008       return;
1009     }
1010   if (MAPTST(&solv->weakrulemap, why))
1011     if (!*lastweakp || why > *lastweakp)
1012       *lastweakp = why;
1013   /* do not add rpm rules to problem */
1014   if (why < solv->rpmrules_end)
1015     return;
1016   /* turn rule into problem */
1017   if (why >= solv->jobrules && why < solv->jobrules_end)
1018     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1019   /* normalize dup/infarch rules */
1020   if (why > solv->infarchrules && why < solv->infarchrules_end)
1021     {
1022       Id name = pool->solvables[-solv->rules[why].p].name;
1023       while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
1024 	why--;
1025     }
1026   if (why > solv->duprules && why < solv->duprules_end)
1027     {
1028       Id name = pool->solvables[-solv->rules[why].p].name;
1029       while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
1030 	why--;
1031     }
1032 
1033   /* return if problem already countains our rule */
1034   if (solv->problems.count)
1035     {
1036       for (i = solv->problems.count - 1; i >= 0; i--)
1037 	if (solv->problems.elements[i] == 0)	/* end of last problem reached? */
1038 	  break;
1039 	else if (solv->problems.elements[i] == why)
1040 	  return;
1041     }
1042   queue_push(&solv->problems, why);
1043 }
1044 
1045 
1046 /*-------------------------------------------------------------------
1047  *
1048  * analyze_unsolvable
1049  *
1050  * We know that the problem is not solvable. Record all involved
1051  * rules (i.e. the "proof") into solv->learnt_pool.
1052  * Record the learnt pool index and all non-rpm rules into
1053  * solv->problems. (Our solutions to fix the problems are to
1054  * disable those rules.)
1055  *
1056  * If the proof contains at least one weak rule, we disable the
1057  * last of them.
1058  *
1059  * Otherwise we return 0 if disablerules is not set or disable
1060  * _all_ of the problem rules and return 1.
1061  *
1062  * return: 1 - disabled some rules, try again
1063  *         0 - hopeless
1064  */
1065 
1066 static int
1067 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1068 {
1069   Pool *pool = solv->pool;
1070   Rule *r;
1071   Map seen;		/* global to speed things up? */
1072   Map rseen;
1073   Id d, v, vv, *dp, why;
1074   int l, i, idx;
1075   Id *decisionmap = solv->decisionmap;
1076   int oldproblemcount;
1077   int oldlearntpoolcount;
1078   Id lastweak;
1079   int record_proof = 1;
1080 
1081   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1082   solv->stats_unsolvable++;
1083   oldproblemcount = solv->problems.count;
1084   oldlearntpoolcount = solv->learnt_pool.count;
1085 
1086   /* make room for proof index */
1087   /* must update it later, as analyze_unsolvable_rule would confuse
1088    * it with a rule index if we put the real value in already */
1089   queue_push(&solv->problems, 0);
1090 
1091   r = cr;
1092   map_init(&seen, pool->nsolvables);
1093   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1094   if (record_proof)
1095     queue_push(&solv->learnt_pool, r - solv->rules);
1096   lastweak = 0;
1097   analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1098   d = r->d < 0 ? -r->d - 1 : r->d;
1099   dp = d ? pool->whatprovidesdata + d : 0;
1100   for (i = -1; ; i++)
1101     {
1102       if (i == -1)
1103 	v = r->p;
1104       else if (d == 0)
1105 	v = i ? 0 : r->w2;
1106       else
1107 	v = *dp++;
1108       if (v == 0)
1109 	break;
1110       if (DECISIONMAP_TRUE(v))	/* the one true literal */
1111 	  continue;
1112       vv = v > 0 ? v : -v;
1113       l = solv->decisionmap[vv];
1114       if (l < 0)
1115 	l = -l;
1116       MAPSET(&seen, vv);
1117     }
1118   idx = solv->decisionq.count;
1119   while (idx > 0)
1120     {
1121       v = solv->decisionq.elements[--idx];
1122       vv = v > 0 ? v : -v;
1123       if (!MAPTST(&seen, vv))
1124 	continue;
1125       why = solv->decisionq_why.elements[idx];
1126       assert(why > 0);
1127       if (record_proof)
1128         queue_push(&solv->learnt_pool, why);
1129       r = solv->rules + why;
1130       analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1131       d = r->d < 0 ? -r->d - 1 : r->d;
1132       dp = d ? pool->whatprovidesdata + d : 0;
1133       for (i = -1; ; i++)
1134 	{
1135 	  if (i == -1)
1136 	    v = r->p;
1137 	  else if (d == 0)
1138 	    v = i ? 0 : r->w2;
1139 	  else
1140 	    v = *dp++;
1141 	  if (v == 0)
1142 	    break;
1143 	  if (DECISIONMAP_TRUE(v))	/* the one true literal */
1144 	      continue;
1145 	  vv = v > 0 ? v : -v;
1146 	  l = solv->decisionmap[vv];
1147 	  if (l < 0)
1148 	    l = -l;
1149 	  MAPSET(&seen, vv);
1150 	}
1151     }
1152   map_free(&seen);
1153   map_free(&rseen);
1154   queue_push(&solv->problems, 0);	/* mark end of this problem */
1155 
1156   if (lastweak)
1157     {
1158       /* disable last weak rule */
1159       solv->problems.count = oldproblemcount;
1160       solv->learnt_pool.count = oldlearntpoolcount;
1161       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
1162 	v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
1163       else
1164         v = lastweak;
1165       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
1166       solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
1167       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
1168 	solver_disablechoicerules(solv, solv->rules + lastweak);
1169       solver_disableproblem(solv, v);
1170       if (v < 0)
1171 	solver_reenablepolicyrules(solv, -v);
1172       solver_reset(solv);
1173       return 1;
1174     }
1175 
1176   if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
1177     {
1178       solv->problems.count = oldproblemcount;
1179       solv->learnt_pool.count = oldlearntpoolcount;
1180       solver_reset(solv);
1181       return 1;
1182     }
1183 
1184   /* finish proof */
1185   if (record_proof)
1186     {
1187       queue_push(&solv->learnt_pool, 0);
1188       solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1189     }
1190 
1191   /* + 2: index + trailing zero */
1192   if (disablerules && oldproblemcount + 2 < solv->problems.count)
1193     {
1194       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1195         solver_disableproblem(solv, solv->problems.elements[i]);
1196       /* XXX: might want to enable all weak rules again */
1197       solver_reset(solv);
1198       return 1;
1199     }
1200   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1201   return 0;
1202 }
1203 
1204 
1205 /********************************************************************/
1206 /* Decision revert */
1207 
1208 /*-------------------------------------------------------------------
1209  *
1210  * revert
1211  * revert decisionq to a level
1212  */
1213 
1214 static void
1215 revert(Solver *solv, int level)
1216 {
1217   Pool *pool = solv->pool;
1218   Id v, vv;
1219   while (solv->decisionq.count)
1220     {
1221       v = solv->decisionq.elements[solv->decisionq.count - 1];
1222       vv = v > 0 ? v : -v;
1223       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1224         break;
1225       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1226       solv->decisionmap[vv] = 0;
1227       solv->decisionq.count--;
1228       solv->decisionq_why.count--;
1229       solv->propagate_index = solv->decisionq.count;
1230     }
1231   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1232     {
1233       solv->branches.count--;
1234       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1235 	solv->branches.count--;
1236     }
1237   solv->recommends_index = -1;
1238 }
1239 
1240 
1241 /*-------------------------------------------------------------------
1242  *
1243  * watch2onhighest - put watch2 on literal with highest level
1244  */
1245 
1246 static inline void
1247 watch2onhighest(Solver *solv, Rule *r)
1248 {
1249   int l, wl = 0;
1250   Id d, v, *dp;
1251 
1252   d = r->d < 0 ? -r->d - 1 : r->d;
1253   if (!d)
1254     return;	/* binary rule, both watches are set */
1255   dp = solv->pool->whatprovidesdata + d;
1256   while ((v = *dp++) != 0)
1257     {
1258       l = solv->decisionmap[v < 0 ? -v : v];
1259       if (l < 0)
1260 	l = -l;
1261       if (l > wl)
1262 	{
1263 	  r->w2 = dp[-1];
1264 	  wl = l;
1265 	}
1266     }
1267 }
1268 
1269 
1270 /*-------------------------------------------------------------------
1271  *
1272  * setpropagatelearn
1273  *
1274  * add free decision (solvable to install) to decisionq
1275  * increase level and propagate decision
1276  * return if no conflict.
1277  *
1278  * in conflict case, analyze conflict rule, add resulting
1279  * rule to learnt rule set, make decision from learnt
1280  * rule (always unit) and re-propagate.
1281  *
1282  * returns the new solver level or 0 if unsolvable
1283  *
1284  */
1285 
1286 static int
1287 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
1288 {
1289   Pool *pool = solv->pool;
1290   Rule *r;
1291   Id p = 0, d = 0;
1292   int l, why;
1293 
1294   assert(ruleid >= 0);
1295   if (decision)
1296     {
1297       level++;
1298       if (decision > 0)
1299         solv->decisionmap[decision] = level;
1300       else
1301         solv->decisionmap[-decision] = -level;
1302       queue_push(&solv->decisionq, decision);
1303       queue_push(&solv->decisionq_why, -ruleid);	/* <= 0 -> free decision */
1304     }
1305   for (;;)
1306     {
1307       r = propagate(solv, level);
1308       if (!r)
1309 	break;
1310       if (level == 1)
1311 	return analyze_unsolvable(solv, r, disablerules);
1312       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1313       l = analyze(solv, level, r, &p, &d, &why);	/* learnt rule in p and d */
1314       assert(l > 0 && l < level);
1315       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1316       level = l;
1317       revert(solv, level);
1318       r = solver_addrule(solv, p, d);
1319       assert(r);
1320       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1321       queue_push(&solv->learnt_why, why);
1322       if (d)
1323 	{
1324 	  /* at least 2 literals, needs watches */
1325 	  watch2onhighest(solv, r);
1326 	  addwatches_rule(solv, r);
1327 	}
1328       else
1329 	{
1330 	  /* learnt rule is an assertion */
1331           queue_push(&solv->ruleassertions, r - solv->rules);
1332 	}
1333       /* the new rule is unit by design */
1334       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1335       queue_push(&solv->decisionq, p);
1336       queue_push(&solv->decisionq_why, r - solv->rules);
1337       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
1338 	{
1339 	  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
1340 	  solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
1341 	  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
1342 	  solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
1343 	}
1344     }
1345   return level;
1346 }
1347 
1348 
1349 /*-------------------------------------------------------------------
1350  *
1351  * select and install
1352  *
1353  * install best package from the queue. We add an extra package, inst, if
1354  * provided. See comment in weak install section.
1355  *
1356  * returns the new solver level or 0 if unsolvable
1357  *
1358  */
1359 
1360 static int
1361 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
1362 {
1363   Pool *pool = solv->pool;
1364   Id p;
1365   int i;
1366 
1367   if (dq->count > 1)
1368     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
1369   if (dq->count > 1)
1370     {
1371       /* XXX: didn't we already do that? */
1372       /* XXX: shouldn't we prefer installed packages? */
1373       /* XXX: move to policy.c? */
1374       /* choose the supplemented one */
1375       for (i = 0; i < dq->count; i++)
1376 	if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1377 	  {
1378 	    dq->elements[0] = dq->elements[i];
1379 	    dq->count = 1;
1380 	    break;
1381 	  }
1382     }
1383   if (dq->count > 1)
1384     {
1385       /* multiple candidates, open a branch */
1386       for (i = 1; i < dq->count; i++)
1387 	queue_push(&solv->branches, dq->elements[i]);
1388       queue_push(&solv->branches, -level);
1389     }
1390   p = dq->elements[0];
1391 
1392   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
1393 
1394   return setpropagatelearn(solv, level, p, disablerules, ruleid);
1395 }
1396 
1397 
1398 /********************************************************************/
1399 /* Main solver interface */
1400 
1401 
1402 /*-------------------------------------------------------------------
1403  *
1404  * solver_create
1405  * create solver structure
1406  *
1407  * pool: all available solvables
1408  * installed: installed Solvables
1409  *
1410  *
1411  * Upon solving, rules are created to flag the Solvables
1412  * of the 'installed' Repo as installed.
1413  */
1414 
1415 Solver *
1416 solver_create(Pool *pool)
1417 {
1418   Solver *solv;
1419   solv = (Solver *)solv_calloc(1, sizeof(Solver));
1420   solv->pool = pool;
1421   solv->installed = pool->installed;
1422 
1423   solv->allownamechange = 1;
1424 
1425   solv->dup_allowdowngrade = 1;
1426   solv->dup_allownamechange = 1;
1427   solv->dup_allowarchchange = 1;
1428   solv->dup_allowvendorchange = 1;
1429 
1430   queue_init(&solv->ruletojob);
1431   queue_init(&solv->decisionq);
1432   queue_init(&solv->decisionq_why);
1433   queue_init(&solv->problems);
1434   queue_init(&solv->orphaned);
1435   queue_init(&solv->learnt_why);
1436   queue_init(&solv->learnt_pool);
1437   queue_init(&solv->branches);
1438   queue_init(&solv->weakruleq);
1439   queue_init(&solv->ruleassertions);
1440   queue_init(&solv->addedmap_deduceq);
1441 
1442   queue_push(&solv->learnt_pool, 0);	/* so that 0 does not describe a proof */
1443 
1444   map_init(&solv->recommendsmap, pool->nsolvables);
1445   map_init(&solv->suggestsmap, pool->nsolvables);
1446   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
1447   solv->recommends_index = 0;
1448 
1449   solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
1450   solv->nrules = 1;
1451   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
1452   memset(solv->rules, 0, sizeof(Rule));
1453 
1454   return solv;
1455 }
1456 
1457 
1458 /*-------------------------------------------------------------------
1459  *
1460  * solver_free
1461  */
1462 
1463 void
1464 solver_free(Solver *solv)
1465 {
1466   queue_free(&solv->job);
1467   queue_free(&solv->ruletojob);
1468   queue_free(&solv->decisionq);
1469   queue_free(&solv->decisionq_why);
1470   queue_free(&solv->learnt_why);
1471   queue_free(&solv->learnt_pool);
1472   queue_free(&solv->problems);
1473   queue_free(&solv->solutions);
1474   queue_free(&solv->orphaned);
1475   queue_free(&solv->branches);
1476   queue_free(&solv->weakruleq);
1477   queue_free(&solv->ruleassertions);
1478   queue_free(&solv->addedmap_deduceq);
1479   if (solv->cleandeps_updatepkgs)
1480     {
1481       queue_free(solv->cleandeps_updatepkgs);
1482       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
1483     }
1484   if (solv->cleandeps_mistakes)
1485     {
1486       queue_free(solv->cleandeps_mistakes);
1487       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
1488     }
1489   if (solv->update_targets)
1490     {
1491       queue_free(solv->update_targets);
1492       solv->update_targets = solv_free(solv->update_targets);
1493     }
1494   if (solv->installsuppdepq)
1495     {
1496       queue_free(solv->installsuppdepq);
1497       solv->installsuppdepq = solv_free(solv->installsuppdepq);
1498     }
1499 
1500   map_free(&solv->recommendsmap);
1501   map_free(&solv->suggestsmap);
1502   map_free(&solv->noupdate);
1503   map_free(&solv->weakrulemap);
1504   map_free(&solv->multiversion);
1505 
1506   map_free(&solv->updatemap);
1507   map_free(&solv->bestupdatemap);
1508   map_free(&solv->fixmap);
1509   map_free(&solv->dupmap);
1510   map_free(&solv->dupinvolvedmap);
1511   map_free(&solv->droporphanedmap);
1512   map_free(&solv->cleandepsmap);
1513 
1514   solv_free(solv->decisionmap);
1515   solv_free(solv->rules);
1516   solv_free(solv->watches);
1517   solv_free(solv->obsoletes);
1518   solv_free(solv->obsoletes_data);
1519   solv_free(solv->multiversionupdaters);
1520   solv_free(solv->choicerules_ref);
1521   solv_free(solv->bestrules_pkg);
1522   solv_free(solv);
1523 }
1524 
1525 int
1526 solver_get_flag(Solver *solv, int flag)
1527 {
1528   switch (flag)
1529   {
1530   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1531     return solv->allowdowngrade;
1532   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1533     return solv->allownamechange;
1534   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1535     return solv->allowarchchange;
1536   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1537     return solv->allowvendorchange;
1538   case SOLVER_FLAG_ALLOW_UNINSTALL:
1539     return solv->allowuninstall;
1540   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1541     return solv->noupdateprovide;
1542   case SOLVER_FLAG_SPLITPROVIDES:
1543     return solv->dosplitprovides;
1544   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1545     return solv->dontinstallrecommended;
1546   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1547     return solv->addalreadyrecommended;
1548   case SOLVER_FLAG_NO_INFARCHCHECK:
1549     return solv->noinfarchcheck;
1550   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1551     return solv->keepexplicitobsoletes;
1552   case SOLVER_FLAG_BEST_OBEY_POLICY:
1553     return solv->bestobeypolicy;
1554   case SOLVER_FLAG_NO_AUTOTARGET:
1555     return solv->noautotarget;
1556   default:
1557     break;
1558   }
1559   return -1;
1560 }
1561 
1562 int
1563 solver_set_flag(Solver *solv, int flag, int value)
1564 {
1565   int old = solver_get_flag(solv, flag);
1566   switch (flag)
1567   {
1568   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1569     solv->allowdowngrade = value;
1570     break;
1571   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1572     solv->allownamechange = value;
1573     break;
1574   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1575     solv->allowarchchange = value;
1576     break;
1577   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1578     solv->allowvendorchange = value;
1579     break;
1580   case SOLVER_FLAG_ALLOW_UNINSTALL:
1581     solv->allowuninstall = value;
1582     break;
1583   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1584     solv->noupdateprovide = value;
1585     break;
1586   case SOLVER_FLAG_SPLITPROVIDES:
1587     solv->dosplitprovides = value;
1588     break;
1589   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1590     solv->dontinstallrecommended = value;
1591     break;
1592   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1593     solv->addalreadyrecommended = value;
1594     break;
1595   case SOLVER_FLAG_NO_INFARCHCHECK:
1596     solv->noinfarchcheck = value;
1597     break;
1598   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1599     solv->keepexplicitobsoletes = value;
1600     break;
1601   case SOLVER_FLAG_BEST_OBEY_POLICY:
1602     solv->bestobeypolicy = value;
1603     break;
1604   case SOLVER_FLAG_NO_AUTOTARGET:
1605     solv->noautotarget = value;
1606     break;
1607   default:
1608     break;
1609   }
1610   return old;
1611 }
1612 
1613 int
1614 cleandeps_check_mistakes(Solver *solv, int level)
1615 {
1616   Pool *pool = solv->pool;
1617   Rule *r;
1618   Id p, pp;
1619   int i;
1620   int mademistake = 0;
1621 
1622   if (!solv->cleandepsmap.size)
1623     return 0;
1624   /* check for mistakes */
1625   for (i = solv->installed->start; i < solv->installed->end; i++)
1626     {
1627       if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1628 	continue;
1629       r = solv->rules + solv->featurerules + (i - solv->installed->start);
1630       /* a mistake is when the featurerule is true but the updaterule is false */
1631       if (!r->p)
1632 	continue;
1633       FOR_RULELITERALS(p, pp, r)
1634 	if (p > 0 && solv->decisionmap[p] > 0)
1635 	  break;
1636       if (!p)
1637 	continue;	/* feature rule is not true */
1638       r = solv->rules + solv->updaterules + (i - solv->installed->start);
1639       if (!r->p)
1640 	continue;
1641       FOR_RULELITERALS(p, pp, r)
1642 	if (p > 0 && solv->decisionmap[p] > 0)
1643 	  break;
1644       if (p)
1645 	continue;	/* update rule is true */
1646       POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
1647       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
1648       POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
1649       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
1650       if (!solv->cleandeps_mistakes)
1651 	{
1652 	  solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
1653 	  queue_init(solv->cleandeps_mistakes);
1654 	}
1655       queue_push(solv->cleandeps_mistakes, i);
1656       MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
1657       solver_reenablepolicyrules_cleandeps(solv, i);
1658       mademistake = 1;
1659     }
1660   if (mademistake)
1661     solver_reset(solv);
1662   return mademistake;
1663 }
1664 
1665 static void
1666 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
1667 {
1668   int i, j;
1669   Id p, *cp2;
1670   for (i = j = 0; i < q->count; i++)
1671     {
1672       p = q->elements[i];
1673       for (cp2 = cp; *cp2; cp2++)
1674 	if (*cp2 == p)
1675 	  {
1676 	    q->elements[j++] = p;
1677 	    break;
1678 	  }
1679     }
1680   queue_truncate(q, j);
1681 }
1682 
1683 /*-------------------------------------------------------------------
1684  *
1685  * solver_run_sat
1686  *
1687  * all rules have been set up, now actually run the solver
1688  *
1689  */
1690 
1691 void
1692 solver_run_sat(Solver *solv, int disablerules, int doweak)
1693 {
1694   Queue dq;		/* local decisionqueue */
1695   Queue dqs;		/* local decisionqueue for supplements */
1696   int systemlevel;
1697   int level, olevel;
1698   Rule *r;
1699   int i, j, n;
1700   Solvable *s;
1701   Pool *pool = solv->pool;
1702   Id p, pp, *dp;
1703   int minimizationsteps;
1704   int installedpos = solv->installed ? solv->installed->start : 0;
1705 
1706   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
1707     {
1708       POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
1709       for (i = 1; i < solv->nrules; i++)
1710 	solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
1711     }
1712 
1713   POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
1714 
1715   /* start SAT algorithm */
1716   level = 1;
1717   systemlevel = level + 1;
1718   POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
1719 
1720   queue_init(&dq);
1721   queue_init(&dqs);
1722 
1723   /*
1724    * here's the main loop:
1725    * 1) propagate new decisions (only needed once)
1726    * 2) fulfill jobs
1727    * 3) try to keep installed packages
1728    * 4) fulfill all unresolved rules
1729    * 5) install recommended packages
1730    * 6) minimalize solution if we had choices
1731    * if we encounter a problem, we rewind to a safe level and restart
1732    * with step 1
1733    */
1734 
1735   minimizationsteps = 0;
1736   for (;;)
1737     {
1738       /*
1739        * initial propagation of the assertions
1740        */
1741       if (level == 1)
1742 	{
1743 	  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
1744 	  if ((r = propagate(solv, level)) != 0)
1745 	    {
1746 	      if (analyze_unsolvable(solv, r, disablerules))
1747 		continue;
1748 	      level = 0;
1749 	      break;	/* unsolvable */
1750 	    }
1751 	}
1752 
1753       /*
1754        * resolve jobs first
1755        */
1756      if (level < systemlevel)
1757 	{
1758 	  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
1759 	  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
1760 	    {
1761 	      Id l;
1762 	      if (r->d < 0)		/* ignore disabled rules */
1763 		continue;
1764 	      queue_empty(&dq);
1765 	      FOR_RULELITERALS(l, pp, r)
1766 		{
1767 		  if (l < 0)
1768 		    {
1769 		      if (solv->decisionmap[-l] <= 0)
1770 			break;
1771 		    }
1772 		  else
1773 		    {
1774 		      if (solv->decisionmap[l] > 0)
1775 			break;
1776 		      if (solv->decisionmap[l] == 0)
1777 			queue_push(&dq, l);
1778 		    }
1779 		}
1780 	      if (l || !dq.count)
1781 		continue;
1782 	      /* prune to installed if not updating */
1783 	      if (dq.count > 1 && solv->installed && !solv->updatemap_all &&
1784 		  !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
1785 		{
1786 		  int j, k;
1787 		  for (j = k = 0; j < dq.count; j++)
1788 		    {
1789 		      Solvable *s = pool->solvables + dq.elements[j];
1790 		      if (s->repo == solv->installed)
1791 			{
1792 			  dq.elements[k++] = dq.elements[j];
1793 			  if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
1794 			    {
1795 			      k = 0;	/* package wants to be updated, do not prune */
1796 			      break;
1797 			    }
1798 			}
1799 		    }
1800 		  if (k)
1801 		    dq.count = k;
1802 		}
1803 	      olevel = level;
1804 	      level = selectandinstall(solv, level, &dq, disablerules, i);
1805 	      if (level == 0)
1806 		break;
1807 	      if (level <= olevel)
1808 		break;
1809 	    }
1810           if (level == 0)
1811 	    break;	/* unsolvable */
1812 	  systemlevel = level + 1;
1813 	  if (i < solv->jobrules_end)
1814 	    continue;
1815           solv->decisioncnt_update = solv->decisionq.count;
1816           solv->decisioncnt_keep = solv->decisionq.count;
1817 	}
1818 
1819       /*
1820        * installed packages
1821        */
1822       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
1823 	{
1824 	  Repo *installed = solv->installed;
1825 	  int pass;
1826 
1827 	  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
1828 	  /* we use two passes if we need to update packages
1829            * to create a better user experience */
1830 	  for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
1831 	    {
1832 	      int passlevel = level;
1833 	      if (pass == 1)
1834 		solv->decisioncnt_keep = solv->decisionq.count;
1835 	      /* start with installedpos, the position that gave us problems last time */
1836 	      for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
1837 		{
1838 		  Rule *rr;
1839 		  Id d;
1840 
1841 		  if (i == installed->end)
1842 		    i = installed->start;
1843 		  s = pool->solvables + i;
1844 		  if (s->repo != installed)
1845 		    continue;
1846 
1847 		  if (solv->decisionmap[i] > 0)
1848 		    continue;
1849 		  if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
1850 		    continue;		/* updates first */
1851 		  r = solv->rules + solv->updaterules + (i - installed->start);
1852 		  rr = r;
1853 		  if (!rr->p || rr->d < 0)	/* disabled -> look at feature rule */
1854 		    rr -= solv->installed->end - solv->installed->start;
1855 		  if (!rr->p)		/* identical to update rule? */
1856 		    rr = r;
1857 		  if (!rr->p)
1858 		    continue;		/* orpaned package */
1859 
1860 		  /* XXX: noupdate check is probably no longer needed, as all jobs should
1861 		   * already be satisfied */
1862 		  /* Actually we currently still need it because of erase jobs */
1863 		  /* if noupdate is set we do not look at update candidates */
1864 		  queue_empty(&dq);
1865 		  if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i))
1866 		    {
1867 		      if (solv->multiversion.size && solv->multiversionupdaters
1868 			     && (d = solv->multiversionupdaters[i - installed->start]) != 0)
1869 			{
1870 			  /* special multiversion handling, make sure best version is chosen */
1871 			  queue_push(&dq, i);
1872 			  while ((p = pool->whatprovidesdata[d++]) != 0)
1873 			    if (solv->decisionmap[p] >= 0)
1874 			      queue_push(&dq, p);
1875 			  if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1876 			    prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1877 			  if (dq.count)
1878 			    {
1879 			      policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
1880 			      p = dq.elements[0];
1881 			      if (p != i && solv->decisionmap[p] == 0)
1882 				{
1883 				  rr = solv->rules + solv->featurerules + (i - solv->installed->start);
1884 				  if (!rr->p)		/* update rule == feature rule? */
1885 				    rr = rr - solv->featurerules + solv->updaterules;
1886 				  dq.count = 1;
1887 				}
1888 			      else
1889 				dq.count = 0;
1890 			    }
1891 			}
1892 		      else
1893 			{
1894 			  /* update to best package */
1895 			  FOR_RULELITERALS(p, pp, rr)
1896 			    {
1897 			      if (solv->decisionmap[p] > 0)
1898 				{
1899 				  dq.count = 0;		/* already fulfilled */
1900 				  break;
1901 				}
1902 			      if (!solv->decisionmap[p])
1903 				queue_push(&dq, p);
1904 			    }
1905 			}
1906 		    }
1907 		  if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1908 		    prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1909 		  /* install best version */
1910 		  if (dq.count)
1911 		    {
1912 		      olevel = level;
1913 		      level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
1914 		      if (level == 0)
1915 			{
1916 			  queue_free(&dq);
1917 			  queue_free(&dqs);
1918 			  return;
1919 			}
1920 		      if (level <= olevel)
1921 			{
1922 			  if (level == 1 || level < passlevel)
1923 			    break;	/* trouble */
1924 			  if (level < olevel)
1925 			    n = installed->start;	/* redo all */
1926 			  i--;
1927 			  n--;
1928 			  continue;
1929 			}
1930 		    }
1931 		  /* if still undecided keep package */
1932 		  if (solv->decisionmap[i] == 0)
1933 		    {
1934 		      olevel = level;
1935 		      if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
1936 			{
1937 #if 0
1938 			  POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
1939 			  level = setpropagatelearn(solv, level, -i, disablerules, 0);
1940 #else
1941 			  continue;
1942 #endif
1943 			}
1944 		      else
1945 			{
1946 			  POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
1947 			  level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
1948 			}
1949 		      if (level == 0)
1950 			break;
1951 		      if (level <= olevel)
1952 			{
1953 			  if (level == 1 || level < passlevel)
1954 			    break;	/* trouble */
1955 			  if (level < olevel)
1956 			    n = installed->start;	/* redo all */
1957 			  i--;
1958 			  n--;
1959 			  continue;	/* retry with learnt rule */
1960 			}
1961 		    }
1962 		}
1963 	      if (n < installed->end)
1964 		{
1965 		  installedpos = i;	/* retry problem solvable next time */
1966 		  break;		/* ran into trouble */
1967 		}
1968 	      installedpos = installed->start;	/* reset installedpos */
1969 	    }
1970           if (level == 0)
1971 	    break;		/* unsolvable */
1972 	  systemlevel = level + 1;
1973 	  if (pass < 2)
1974 	    continue;		/* had trouble, retry */
1975 	}
1976 
1977       if (level < systemlevel)
1978         systemlevel = level;
1979 
1980       /*
1981        * decide
1982        */
1983       solv->decisioncnt_resolve = solv->decisionq.count;
1984       POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
1985       for (i = 1, n = 1; n < solv->nrules; i++, n++)
1986 	{
1987 	  if (i == solv->nrules)
1988 	    i = 1;
1989 	  r = solv->rules + i;
1990 	  if (r->d < 0)		/* ignore disabled rules */
1991 	    continue;
1992 	  queue_empty(&dq);
1993 	  if (r->d == 0)
1994 	    {
1995 	      /* binary or unary rule */
1996 	      /* need two positive undecided literals */
1997 	      if (r->p < 0 || r->w2 <= 0)
1998 		continue;
1999 	      if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2000 		continue;
2001 	      queue_push(&dq, r->p);
2002 	      queue_push(&dq, r->w2);
2003 	    }
2004 	  else
2005 	    {
2006 	      /* make sure that
2007                * all negative literals are installed
2008                * no positive literal is installed
2009 	       * i.e. the rule is not fulfilled and we
2010                * just need to decide on the positive literals
2011                */
2012 	      if (r->p < 0)
2013 		{
2014 		  if (solv->decisionmap[-r->p] <= 0)
2015 		    continue;
2016 		}
2017 	      else
2018 		{
2019 		  if (solv->decisionmap[r->p] > 0)
2020 		    continue;
2021 		  if (solv->decisionmap[r->p] == 0)
2022 		    queue_push(&dq, r->p);
2023 		}
2024 	      dp = pool->whatprovidesdata + r->d;
2025 	      while ((p = *dp++) != 0)
2026 		{
2027 		  if (p < 0)
2028 		    {
2029 		      if (solv->decisionmap[-p] <= 0)
2030 			break;
2031 		    }
2032 		  else
2033 		    {
2034 		      if (solv->decisionmap[p] > 0)
2035 			break;
2036 		      if (solv->decisionmap[p] == 0)
2037 			queue_push(&dq, p);
2038 		    }
2039 		}
2040 	      if (p)
2041 		continue;
2042 	    }
2043 	  IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
2044 	    {
2045 	      POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
2046 	      solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
2047 	    }
2048 	  /* dq.count < 2 cannot happen as this means that
2049 	   * the rule is unit */
2050 	  assert(dq.count > 1);
2051 
2052 	  /* prune to cleandeps packages */
2053 	  if (solv->cleandepsmap.size && solv->installed)
2054 	    {
2055 	      Repo *installed = solv->installed;
2056 	      for (j = 0; j < dq.count; j++)
2057 		if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
2058 		  break;
2059 	      if (j < dq.count)
2060 		{
2061 		  dq.elements[0] = dq.elements[j];
2062 		  queue_truncate(&dq, 1);
2063 		}
2064 	    }
2065 
2066 	  olevel = level;
2067 	  level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2068 	  if (level == 0)
2069 	    break;		/* unsolvable */
2070 	  if (level < systemlevel || level == 1)
2071 	    break;		/* trouble */
2072 	  /* something changed, so look at all rules again */
2073 	  n = 0;
2074 	}
2075 
2076       if (n != solv->nrules)	/* ran into trouble? */
2077 	{
2078 	  if (level == 0)
2079 	    break;		/* unsolvable */
2080 	  continue;		/* start over */
2081 	}
2082 
2083       /* at this point we have a consistent system. now do the extras... */
2084 
2085       /* first decide leftover cleandeps packages */
2086       if (solv->cleandepsmap.size && solv->installed)
2087 	{
2088 	  for (p = solv->installed->start; p < solv->installed->end; p++)
2089 	    {
2090 	      s = pool->solvables + p;
2091 	      if (s->repo != solv->installed)
2092 		continue;
2093 	      if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2094 		{
2095 		  POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
2096 		  olevel = level;
2097 		  level = setpropagatelearn(solv, level, -p, 0, 0);
2098 		  if (level < olevel)
2099 		    break;
2100 		}
2101 	    }
2102 	  if (p < solv->installed->end)
2103 	    continue;
2104 	}
2105 
2106       solv->decisioncnt_weak = solv->decisionq.count;
2107       if (doweak)
2108 	{
2109 	  int qcount;
2110 
2111 	  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
2112 	  queue_empty(&dq);	/* recommended packages */
2113 	  queue_empty(&dqs);	/* supplemented packages */
2114 	  for (i = 1; i < pool->nsolvables; i++)
2115 	    {
2116 	      if (solv->decisionmap[i] < 0)
2117 		continue;
2118 	      if (solv->decisionmap[i] > 0)
2119 		{
2120 		  /* installed, check for recommends */
2121 		  Id *recp, rec, pp, p;
2122 		  s = pool->solvables + i;
2123 		  if (!solv->addalreadyrecommended && s->repo == solv->installed)
2124 		    continue;
2125 		  /* XXX need to special case AND ? */
2126 		  if (s->recommends)
2127 		    {
2128 		      recp = s->repo->idarraydata + s->recommends;
2129 		      while ((rec = *recp++) != 0)
2130 			{
2131 			  qcount = dq.count;
2132 			  FOR_PROVIDES(p, pp, rec)
2133 			    {
2134 			      if (solv->decisionmap[p] > 0)
2135 				{
2136 				  dq.count = qcount;
2137 				  break;
2138 				}
2139 			      else if (solv->decisionmap[p] == 0)
2140 				{
2141 				  if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
2142 				    continue;
2143 				  queue_pushunique(&dq, p);
2144 				}
2145 			    }
2146 			}
2147 		    }
2148 		}
2149 	      else
2150 		{
2151 		  s = pool->solvables + i;
2152 		  if (!s->supplements)
2153 		    continue;
2154 		  if (!pool_installable(pool, s))
2155 		    continue;
2156 		  if (!solver_is_supplementing(solv, s))
2157 		    continue;
2158 		  if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
2159 		    continue;
2160 		  queue_push(&dqs, i);
2161 		}
2162 	    }
2163 
2164 	  /* filter out all packages obsoleted by installed packages */
2165 	  /* this is no longer needed if we have reverse obsoletes */
2166           if ((dqs.count || dq.count) && solv->installed)
2167 	    {
2168 	      Map obsmap;
2169 	      Id obs, *obsp, po, ppo;
2170 
2171 	      map_init(&obsmap, pool->nsolvables);
2172 	      for (p = solv->installed->start; p < solv->installed->end; p++)
2173 		{
2174 		  s = pool->solvables + p;
2175 		  if (s->repo != solv->installed || !s->obsoletes)
2176 		    continue;
2177 		  if (solv->decisionmap[p] <= 0)
2178 		    continue;
2179 		  if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
2180 		    continue;
2181 		  obsp = s->repo->idarraydata + s->obsoletes;
2182 		  /* foreach obsoletes */
2183 		  while ((obs = *obsp++) != 0)
2184 		    FOR_PROVIDES(po, ppo, obs)
2185 		      MAPSET(&obsmap, po);
2186 		}
2187 	      for (i = j = 0; i < dqs.count; i++)
2188 		if (!MAPTST(&obsmap, dqs.elements[i]))
2189 		  dqs.elements[j++] = dqs.elements[i];
2190 	      dqs.count = j;
2191 	      for (i = j = 0; i < dq.count; i++)
2192 		if (!MAPTST(&obsmap, dq.elements[i]))
2193 		  dq.elements[j++] = dq.elements[i];
2194 	      dq.count = j;
2195 	      map_free(&obsmap);
2196 	    }
2197 
2198           /* filter out all already supplemented packages if requested */
2199           if (!solv->addalreadyrecommended && dqs.count)
2200 	    {
2201 	      int dosplitprovides_old = solv->dosplitprovides;
2202 	      /* turn off all new packages */
2203 	      for (i = 0; i < solv->decisionq.count; i++)
2204 		{
2205 		  p = solv->decisionq.elements[i];
2206 		  if (p < 0)
2207 		    continue;
2208 		  s = pool->solvables + p;
2209 		  if (s->repo && s->repo != solv->installed)
2210 		    solv->decisionmap[p] = -solv->decisionmap[p];
2211 		}
2212 	      solv->dosplitprovides = 0;
2213 	      /* filter out old supplements */
2214 	      for (i = j = 0; i < dqs.count; i++)
2215 		{
2216 		  p = dqs.elements[i];
2217 		  s = pool->solvables + p;
2218 		  if (!s->supplements)
2219 		    continue;
2220 		  if (!solver_is_supplementing(solv, s))
2221 		    dqs.elements[j++] = p;
2222 		  else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
2223 		    dqs.elements[j++] = p;
2224 		}
2225 	      dqs.count = j;
2226 	      /* undo turning off */
2227 	      for (i = 0; i < solv->decisionq.count; i++)
2228 		{
2229 		  p = solv->decisionq.elements[i];
2230 		  if (p < 0)
2231 		    continue;
2232 		  s = pool->solvables + p;
2233 		  if (s->repo && s->repo != solv->installed)
2234 		    solv->decisionmap[p] = -solv->decisionmap[p];
2235 		}
2236 	      solv->dosplitprovides = dosplitprovides_old;
2237 	    }
2238 
2239 	  /* multiversion doesn't mix well with supplements.
2240 	   * filter supplemented packages where we already decided
2241 	   * to install a different version (see bnc#501088) */
2242           if (dqs.count && solv->multiversion.size)
2243 	    {
2244 	      for (i = j = 0; i < dqs.count; i++)
2245 		{
2246 		  p = dqs.elements[i];
2247 		  if (MAPTST(&solv->multiversion, p))
2248 		    {
2249 		      Id p2, pp2;
2250 		      s = pool->solvables + p;
2251 		      FOR_PROVIDES(p2, pp2, s->name)
2252 			if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
2253 			  break;
2254 		      if (p2)
2255 			continue;	/* ignore this package */
2256 		    }
2257 		  dqs.elements[j++] = p;
2258 		}
2259 	      dqs.count = j;
2260 	    }
2261 
2262           /* make dq contain both recommended and supplemented pkgs */
2263 	  if (dqs.count)
2264 	    {
2265 	      for (i = 0; i < dqs.count; i++)
2266 		queue_pushunique(&dq, dqs.elements[i]);
2267 	    }
2268 
2269 	  if (dq.count)
2270 	    {
2271 	      Map dqmap;
2272 	      int decisioncount = solv->decisionq.count;
2273 
2274 	      if (dq.count == 1)
2275 		{
2276 		  /* simple case, just one package. no need to choose to best version */
2277 		  p = dq.elements[0];
2278 		  if (dqs.count)
2279 		    POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2280 		  else
2281 		    POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2282 		  level = setpropagatelearn(solv, level, p, 0, 0);
2283 		  if (level == 0)
2284 		    break;
2285 		  continue;	/* back to main loop */
2286 		}
2287 
2288 	      /* filter packages, this gives us the best versions */
2289 	      policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2290 
2291 	      /* create map of result */
2292 	      map_init(&dqmap, pool->nsolvables);
2293 	      for (i = 0; i < dq.count; i++)
2294 		MAPSET(&dqmap, dq.elements[i]);
2295 
2296 	      /* install all supplemented packages */
2297 	      for (i = 0; i < dqs.count; i++)
2298 		{
2299 		  p = dqs.elements[i];
2300 		  if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2301 		    continue;
2302 		  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2303 		  olevel = level;
2304 		  level = setpropagatelearn(solv, level, p, 0, 0);
2305 		  if (level <= olevel)
2306 		    break;
2307 		}
2308 	      if (i < dqs.count || solv->decisionq.count < decisioncount)
2309 		{
2310 		  map_free(&dqmap);
2311 		  if (level == 0)
2312 		    break;
2313 		  continue;
2314 		}
2315 
2316 	      /* install all recommended packages */
2317 	      /* more work as we want to created branches if multiple
2318                * choices are valid */
2319 	      for (i = 0; i < decisioncount; i++)
2320 		{
2321 		  Id rec, *recp, pp;
2322 		  p = solv->decisionq.elements[i];
2323 		  if (p < 0)
2324 		    continue;
2325 		  s = pool->solvables + p;
2326 		  if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
2327 		    continue;
2328 		  if (!s->recommends)
2329 		    continue;
2330 		  recp = s->repo->idarraydata + s->recommends;
2331 		  while ((rec = *recp++) != 0)
2332 		    {
2333 		      queue_empty(&dq);
2334 		      FOR_PROVIDES(p, pp, rec)
2335 			{
2336 			  if (solv->decisionmap[p] > 0)
2337 			    {
2338 			      dq.count = 0;
2339 			      break;
2340 			    }
2341 			  else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2342 			    queue_pushunique(&dq, p);
2343 			}
2344 		      if (!dq.count)
2345 			continue;
2346 		      if (dq.count > 1)
2347 			{
2348 			  /* multiple candidates, open a branch */
2349 			  for (i = 1; i < dq.count; i++)
2350 			    queue_push(&solv->branches, dq.elements[i]);
2351 			  queue_push(&solv->branches, -level);
2352 			}
2353 		      p = dq.elements[0];
2354 		      POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2355 		      olevel = level;
2356 		      level = setpropagatelearn(solv, level, p, 0, 0);
2357 		      if (level <= olevel || solv->decisionq.count < decisioncount)
2358 			break;	/* we had to revert some decisions */
2359 		    }
2360 		  if (rec)
2361 		    break;	/* had a problem above, quit loop */
2362 		}
2363 	      map_free(&dqmap);
2364 	      if (level == 0)
2365 		break;
2366 	      continue;		/* back to main loop so that all deps are checked */
2367 	    }
2368 	}
2369 
2370       solv->decisioncnt_orphan = solv->decisionq.count;
2371       if (solv->dupmap_all && solv->installed)
2372 	{
2373 	  int installedone = 0;
2374 
2375 	  /* let's see if we can install some unsupported package */
2376 	  POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
2377 	  for (i = 0; i < solv->orphaned.count; i++)
2378 	    {
2379 	      p = solv->orphaned.elements[i];
2380 	      if (solv->decisionmap[p])
2381 		continue;	/* already decided */
2382 	      if (solv->droporphanedmap_all)
2383 		continue;
2384 	      if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
2385 		continue;
2386 	      POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
2387 	      olevel = level;
2388 	      level = setpropagatelearn(solv, level, p, 0, 0);
2389 	      installedone = 1;
2390 	      if (level < olevel)
2391 		break;
2392 	    }
2393 	  if (installedone || i < solv->orphaned.count)
2394 	    {
2395 	      if (level == 0)
2396 		break;
2397 	      continue;		/* back to main loop */
2398 	    }
2399 	  for (i = 0; i < solv->orphaned.count; i++)
2400 	    {
2401 	      p = solv->orphaned.elements[i];
2402 	      if (solv->decisionmap[p])
2403 		continue;	/* already decided */
2404 	      POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
2405 	      olevel = level;
2406 	      level = setpropagatelearn(solv, level, -p, 0, 0);
2407 	      if (level < olevel)
2408 		break;
2409 	    }
2410 	  if (i < solv->orphaned.count)
2411 	    {
2412 	      if (level == 0)
2413 		break;
2414 	      continue;		/* back to main loop */
2415 	    }
2416 	}
2417 
2418      if (solv->installed && solv->cleandepsmap.size)
2419 	{
2420 	  if (cleandeps_check_mistakes(solv, level))
2421 	    {
2422 	      level = 1;	/* restart from scratch */
2423 	      systemlevel = level + 1;
2424 	      continue;
2425 	    }
2426 	}
2427 
2428      if (solv->solution_callback)
2429 	{
2430 	  solv->solution_callback(solv, solv->solution_callback_data);
2431 	  if (solv->branches.count)
2432 	    {
2433 	      int i = solv->branches.count - 1;
2434 	      int l = -solv->branches.elements[i];
2435 	      Id why;
2436 
2437 	      for (; i > 0; i--)
2438 		if (solv->branches.elements[i - 1] < 0)
2439 		  break;
2440 	      p = solv->branches.elements[i];
2441 	      POOL_DEBUG(SOLV_DEBUG_SOLVER, "branching with %s\n", pool_solvid2str(pool, p));
2442 	      queue_empty(&dq);
2443 	      for (j = i + 1; j < solv->branches.count; j++)
2444 		queue_push(&dq, solv->branches.elements[j]);
2445 	      solv->branches.count = i;
2446 	      level = l;
2447 	      revert(solv, level);
2448 	      if (dq.count > 1)
2449 	        for (j = 0; j < dq.count; j++)
2450 		  queue_push(&solv->branches, dq.elements[j]);
2451 	      olevel = level;
2452 	      why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2453 	      assert(why >= 0);
2454 	      level = setpropagatelearn(solv, level, p, disablerules, why);
2455 	      if (level == 0)
2456 		break;
2457 	      continue;
2458 	    }
2459 	  /* all branches done, we're finally finished */
2460 	  break;
2461 	}
2462 
2463       /* auto-minimization step */
2464      if (solv->branches.count)
2465 	{
2466 	  int l = 0, lasti = -1, lastl = -1;
2467 	  Id why;
2468 
2469 	  p = 0;
2470 	  for (i = solv->branches.count - 1; i >= 0; i--)
2471 	    {
2472 	      p = solv->branches.elements[i];
2473 	      if (p < 0)
2474 		l = -p;
2475 	      else if (p > 0 && solv->decisionmap[p] > l + 1)
2476 		{
2477 		  lasti = i;
2478 		  lastl = l;
2479 		}
2480 	    }
2481 	  if (lasti >= 0)
2482 	    {
2483 	      /* kill old solvable so that we do not loop */
2484 	      p = solv->branches.elements[lasti];
2485 	      solv->branches.elements[lasti] = 0;
2486 	      POOL_DEBUG(SOLV_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, pool_solvid2str(pool, p));
2487 	      minimizationsteps++;
2488 
2489 	      level = lastl;
2490 	      revert(solv, level);
2491 	      why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2492 	      assert(why >= 0);
2493 	      olevel = level;
2494 	      level = setpropagatelearn(solv, level, p, disablerules, why);
2495 	      if (level == 0)
2496 		break;
2497 	      continue;		/* back to main loop */
2498 	    }
2499 	}
2500       /* no minimization found, we're finally finished! */
2501       break;
2502     }
2503 
2504   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
2505 
2506   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
2507   queue_free(&dq);
2508   queue_free(&dqs);
2509   if (level == 0)
2510     {
2511       /* unsolvable */
2512       solv->decisioncnt_update = solv->decisionq.count;
2513       solv->decisioncnt_keep = solv->decisionq.count;
2514       solv->decisioncnt_resolve = solv->decisionq.count;
2515       solv->decisioncnt_weak = solv->decisionq.count;
2516       solv->decisioncnt_orphan = solv->decisionq.count;
2517     }
2518 #if 0
2519   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
2520 #endif
2521 }
2522 
2523 
2524 /*-------------------------------------------------------------------
2525  *
2526  * remove disabled conflicts
2527  *
2528  * purpose: update the decisionmap after some rules were disabled.
2529  * this is used to calculate the suggested/recommended package list.
2530  * Also returns a "removed" list to undo the discisionmap changes.
2531  */
2532 
2533 static void
2534 removedisabledconflicts(Solver *solv, Queue *removed)
2535 {
2536   Pool *pool = solv->pool;
2537   int i, n;
2538   Id p, why, *dp;
2539   Id new;
2540   Rule *r;
2541   Id *decisionmap = solv->decisionmap;
2542 
2543   queue_empty(removed);
2544   for (i = 0; i < solv->decisionq.count; i++)
2545     {
2546       p = solv->decisionq.elements[i];
2547       if (p > 0)
2548 	continue;	/* conflicts only, please */
2549       why = solv->decisionq_why.elements[i];
2550       if (why == 0)
2551 	{
2552 	  /* no rule involved, must be a orphan package drop */
2553 	  continue;
2554 	}
2555       /* we never do conflicts on free decisions, so there
2556        * must have been an unit rule */
2557       assert(why > 0);
2558       r = solv->rules + why;
2559       if (r->d < 0 && decisionmap[-p])
2560 	{
2561 	  /* rule is now disabled, remove from decisionmap */
2562 	  POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
2563 	  queue_push(removed, -p);
2564 	  queue_push(removed, decisionmap[-p]);
2565 	  decisionmap[-p] = 0;
2566 	}
2567     }
2568   if (!removed->count)
2569     return;
2570   /* we removed some confliced packages. some of them might still
2571    * be in conflict, so search for unit rules and re-conflict */
2572   new = 0;
2573   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
2574     {
2575       if (i == solv->nrules)
2576 	{
2577 	  i = 1;
2578 	  r = solv->rules + i;
2579 	}
2580       if (r->d < 0)
2581 	continue;
2582       if (!r->w2)
2583 	{
2584 	  if (r->p < 0 && !decisionmap[-r->p])
2585 	    new = r->p;
2586 	}
2587       else if (!r->d)
2588 	{
2589 	  /* binary rule */
2590 	  if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
2591 	    new = r->p;
2592 	  else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
2593 	    new = r->w2;
2594 	}
2595       else
2596 	{
2597 	  if (r->p < 0 && decisionmap[-r->p] == 0)
2598 	    new = r->p;
2599 	  if (new || DECISIONMAP_FALSE(r->p))
2600 	    {
2601 	      dp = pool->whatprovidesdata + r->d;
2602 	      while ((p = *dp++) != 0)
2603 		{
2604 		  if (new && p == new)
2605 		    continue;
2606 		  if (p < 0 && decisionmap[-p] == 0)
2607 		    {
2608 		      if (new)
2609 			{
2610 			  new = 0;
2611 			  break;
2612 			}
2613 		      new = p;
2614 		    }
2615 		  else if (!DECISIONMAP_FALSE(p))
2616 		    {
2617 		      new = 0;
2618 		      break;
2619 		    }
2620 		}
2621 	    }
2622 	}
2623       if (new)
2624 	{
2625 	  POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
2626 	  decisionmap[-new] = -1;
2627 	  new = 0;
2628 	  n = 0;	/* redo all rules */
2629 	}
2630     }
2631 }
2632 
2633 static inline void
2634 undo_removedisabledconflicts(Solver *solv, Queue *removed)
2635 {
2636   int i;
2637   for (i = 0; i < removed->count; i += 2)
2638     solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
2639 }
2640 
2641 
2642 /*-------------------------------------------------------------------
2643  *
2644  * weaken solvable dependencies
2645  */
2646 
2647 static void
2648 weaken_solvable_deps(Solver *solv, Id p)
2649 {
2650   int i;
2651   Rule *r;
2652 
2653   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
2654     {
2655       if (r->p != -p)
2656 	continue;
2657       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2658 	continue;	/* conflict */
2659       queue_push(&solv->weakruleq, i);
2660     }
2661 }
2662 
2663 
2664 /********************************************************************/
2665 /* main() */
2666 
2667 
2668 void
2669 solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
2670 {
2671   int i;
2672   Id how, what, select;
2673   Id p, pp;
2674   for (i = 0; i < job->count; i += 2)
2675     {
2676       how = job->elements[i];
2677       if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION)
2678 	continue;
2679       what = job->elements[i + 1];
2680       select = how & SOLVER_SELECTMASK;
2681       if (!multiversionmap->size)
2682 	map_grow(multiversionmap, pool->nsolvables);
2683       if (select == SOLVER_SOLVABLE_ALL)
2684 	{
2685 	  FOR_POOL_SOLVABLES(p)
2686 	    MAPSET(multiversionmap, p);
2687 	}
2688       else if (select == SOLVER_SOLVABLE_REPO)
2689 	{
2690 	  Solvable *s;
2691 	  Repo *repo = pool_id2repo(pool, what);
2692 	  if (repo)
2693 	    FOR_REPO_SOLVABLES(repo, p, s)
2694 	      MAPSET(multiversionmap, p);
2695 	}
2696       FOR_JOB_SELECT(p, pp, select, what)
2697         MAPSET(multiversionmap, p);
2698     }
2699 }
2700 
2701 void
2702 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
2703 {
2704   solver_calculate_multiversionmap(pool, job, multiversionmap);
2705 }
2706 
2707 /*
2708  * add a rule created by a job, record job number and weak flag
2709  */
2710 static inline void
2711 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
2712 {
2713   solver_addrule(solv, p, d);
2714   queue_push(&solv->ruletojob, job);
2715   if (weak)
2716     queue_push(&solv->weakruleq, solv->nrules - 1);
2717 }
2718 
2719 static inline void
2720 add_cleandeps_package(Solver *solv, Id p)
2721 {
2722   if (!solv->cleandeps_updatepkgs)
2723     {
2724       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
2725       queue_init(solv->cleandeps_updatepkgs);
2726     }
2727   queue_pushunique(solv->cleandeps_updatepkgs, p);
2728 }
2729 
2730 static void
2731 add_update_target(Solver *solv, Id p, Id how)
2732 {
2733   Pool *pool = solv->pool;
2734   Solvable *s = pool->solvables + p;
2735   Repo *installed = solv->installed;
2736   Id pi, pip;
2737   if (!solv->update_targets)
2738     {
2739       solv->update_targets = solv_calloc(1, sizeof(Queue));
2740       queue_init(solv->update_targets);
2741     }
2742   if (s->repo == installed)
2743     {
2744       queue_push2(solv->update_targets, p, p);
2745       return;
2746     }
2747   FOR_PROVIDES(pi, pip, s->name)
2748     {
2749       Solvable *si = pool->solvables + pi;
2750       if (si->repo != installed || si->name != s->name)
2751 	continue;
2752       if (how & SOLVER_FORCEBEST)
2753 	{
2754 	  if (!solv->bestupdatemap.size)
2755 	    map_grow(&solv->bestupdatemap, installed->end - installed->start);
2756 	  MAPSET(&solv->bestupdatemap, pi - installed->start);
2757 	}
2758       if (how & SOLVER_CLEANDEPS)
2759 	add_cleandeps_package(solv, pi);
2760       queue_push2(solv->update_targets, pi, p);
2761       /* check if it's ok to keep the installed package */
2762       if (s->evr == si->evr && solvable_identical(s, si))
2763         queue_push2(solv->update_targets, pi, pi);
2764     }
2765   if (s->obsoletes)
2766     {
2767       Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2768       while ((obs = *obsp++) != 0)
2769 	{
2770 	  FOR_PROVIDES(pi, pip, obs)
2771 	    {
2772 	      Solvable *si = pool->solvables + pi;
2773 	      if (si->repo != installed)
2774 		continue;
2775 	      if (si->name == s->name)
2776 		continue;	/* already handled above */
2777 	      if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
2778 		continue;
2779 	      if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
2780 		continue;
2781 	      if (how & SOLVER_FORCEBEST)
2782 		{
2783 		  if (!solv->bestupdatemap.size)
2784 		    map_grow(&solv->bestupdatemap, installed->end - installed->start);
2785 		  MAPSET(&solv->bestupdatemap, pi - installed->start);
2786 		}
2787 	      if (how & SOLVER_CLEANDEPS)
2788 		add_cleandeps_package(solv, pi);
2789 	      queue_push2(solv->update_targets, pi, p);
2790 	    }
2791 	}
2792     }
2793 }
2794 
2795 static int
2796 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
2797 {
2798   const Id *a = ap;
2799   const Id *b = bp;
2800   if (a[0] - b[0])
2801     return a[0] - b[0];
2802   return a[1] - b[1];
2803 }
2804 
2805 static void
2806 transform_update_targets(Solver *solv)
2807 {
2808   Repo *installed = solv->installed;
2809   Queue *update_targets = solv->update_targets;
2810   int i, j;
2811   Id p, q, lastp, lastq;
2812 
2813   if (!update_targets->count)
2814     {
2815       queue_free(update_targets);
2816       solv->update_targets = solv_free(update_targets);
2817       return;
2818     }
2819   if (update_targets->count > 2)
2820     solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
2821   queue_insertn(update_targets, 0, installed->end - installed->start, 0);
2822   lastp = lastq = 0;
2823   for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
2824     {
2825       if ((p = update_targets->elements[i]) != lastp)
2826 	{
2827 	  if (!solv->updatemap.size)
2828 	    map_grow(&solv->updatemap, installed->end - installed->start);
2829 	  MAPSET(&solv->updatemap, p - installed->start);
2830 	  update_targets->elements[j++] = 0;			/* finish old set */
2831 	  update_targets->elements[p - installed->start] = j;	/* start new set */
2832 	  lastp = p;
2833 	  lastq = 0;
2834 	}
2835       if ((q = update_targets->elements[i + 1]) != lastq)
2836 	{
2837           update_targets->elements[j++] = q;
2838 	  lastq = q;
2839 	}
2840     }
2841   queue_truncate(update_targets, j);
2842   queue_push(update_targets, 0);	/* finish last set */
2843 }
2844 
2845 
2846 static void
2847 addedmap2deduceq(Solver *solv, Map *addedmap)
2848 {
2849   Pool *pool = solv->pool;
2850   int i, j;
2851   Id p;
2852   Rule *r;
2853 
2854   queue_empty(&solv->addedmap_deduceq);
2855   for (i = 2, j = solv->rpmrules_end - 1; i < pool->nsolvables && j > 0; j--)
2856     {
2857       r = solv->rules + j;
2858       if (r->p >= 0)
2859 	continue;
2860       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2861 	continue;
2862       p = -r->p;
2863       if (!MAPTST(addedmap, p))
2864 	{
2865 	  /* should never happen, but... */
2866 	  if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
2867             queue_push(&solv->addedmap_deduceq, -p);
2868 	  continue;
2869 	}
2870       for (; i < p; i++)
2871         if (MAPTST(addedmap, i))
2872           queue_push(&solv->addedmap_deduceq, i);
2873       if (i == p)
2874         i++;
2875     }
2876   for (; i < pool->nsolvables; i++)
2877     if (MAPTST(addedmap, i))
2878       queue_push(&solv->addedmap_deduceq, i);
2879   j = 0;
2880   for (i = 2; i < pool->nsolvables; i++)
2881     if (MAPTST(addedmap, i))
2882       j++;
2883 }
2884 
2885 static void
2886 deduceq2addedmap(Solver *solv, Map *addedmap)
2887 {
2888   int j;
2889   Id p;
2890   Rule *r;
2891   for (j = solv->rpmrules_end - 1; j > 0; j--)
2892     {
2893       r = solv->rules + j;
2894       if (r->d < 0 && r->p)
2895 	solver_enablerule(solv, r);
2896       if (r->p >= 0)
2897 	continue;
2898       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2899 	continue;
2900       p = -r->p;
2901       MAPSET(addedmap, p);
2902     }
2903   for (j = 0; j < solv->addedmap_deduceq.count; j++)
2904     {
2905       p = solv->addedmap_deduceq.elements[j];
2906       if (p > 0)
2907 	MAPSET(addedmap, p);
2908       else
2909 	MAPCLR(addedmap, p);
2910     }
2911 }
2912 
2913 
2914 /*
2915  *
2916  * solve job queue
2917  *
2918  */
2919 
2920 int
2921 solver_solve(Solver *solv, Queue *job)
2922 {
2923   Pool *pool = solv->pool;
2924   Repo *installed = solv->installed;
2925   int i;
2926   int oldnrules, initialnrules;
2927   Map addedmap;		       /* '1' == have rpm-rules for solvable */
2928   Map installcandidatemap;
2929   Id how, what, select, name, weak, p, pp, d;
2930   Queue q;
2931   Solvable *s;
2932   Rule *r;
2933   int now, solve_start;
2934   int hasdupjob = 0;
2935   int hasbestinstalljob = 0;
2936 
2937   solve_start = solv_timems(0);
2938 
2939   /* log solver options */
2940   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
2941   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
2942   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
2943   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
2944   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors);
2945   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
2946 
2947   /* create whatprovides if not already there */
2948   if (!pool->whatprovides)
2949     pool_createwhatprovides(pool);
2950 
2951   /* create obsolete index */
2952   policy_create_obsolete_index(solv);
2953 
2954   /* remember job */
2955   queue_free(&solv->job);
2956   queue_init_clone(&solv->job, job);
2957   solv->pooljobcnt = pool->pooljobs.count;
2958   if (pool->pooljobs.count)
2959     queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
2960   job = &solv->job;
2961 
2962   /* free old stuff */
2963   if (solv->update_targets)
2964     {
2965       queue_free(solv->update_targets);
2966       solv->update_targets = solv_free(solv->update_targets);
2967     }
2968   if (solv->cleandeps_updatepkgs)
2969     {
2970       queue_free(solv->cleandeps_updatepkgs);
2971       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
2972     }
2973   queue_empty(&solv->ruleassertions);
2974   solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
2975   solv->choicerules_ref = solv_free(solv->choicerules_ref);
2976   if (solv->noupdate.size)
2977     map_empty(&solv->noupdate);
2978   if (solv->multiversion.size)
2979     {
2980       map_free(&solv->multiversion);
2981       map_init(&solv->multiversion, 0);
2982     }
2983   solv->updatemap_all = 0;
2984   if (solv->updatemap.size)
2985     {
2986       map_free(&solv->updatemap);
2987       map_init(&solv->updatemap, 0);
2988     }
2989   solv->bestupdatemap_all = 0;
2990   if (solv->bestupdatemap.size)
2991     {
2992       map_free(&solv->bestupdatemap);
2993       map_init(&solv->bestupdatemap, 0);
2994     }
2995   solv->fixmap_all = 0;
2996   if (solv->fixmap.size)
2997     {
2998       map_free(&solv->fixmap);
2999       map_init(&solv->fixmap, 0);
3000     }
3001   solv->dupmap_all = 0;
3002   if (solv->dupmap.size)
3003     {
3004       map_free(&solv->dupmap);
3005       map_init(&solv->dupmap, 0);
3006     }
3007   if (solv->dupinvolvedmap.size)
3008     {
3009       map_free(&solv->dupinvolvedmap);
3010       map_init(&solv->dupinvolvedmap, 0);
3011     }
3012   solv->droporphanedmap_all = 0;
3013   if (solv->droporphanedmap.size)
3014     {
3015       map_free(&solv->droporphanedmap);
3016       map_init(&solv->droporphanedmap, 0);
3017     }
3018   if (solv->cleandepsmap.size)
3019     {
3020       map_free(&solv->cleandepsmap);
3021       map_init(&solv->cleandepsmap, 0);
3022     }
3023 
3024   queue_empty(&solv->weakruleq);
3025   solv->watches = solv_free(solv->watches);
3026   queue_empty(&solv->ruletojob);
3027   if (solv->decisionq.count)
3028     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
3029   queue_empty(&solv->decisionq);
3030   queue_empty(&solv->decisionq_why);
3031   solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
3032   queue_empty(&solv->learnt_why);
3033   queue_empty(&solv->learnt_pool);
3034   queue_empty(&solv->branches);
3035   solv->propagate_index = 0;
3036   queue_empty(&solv->problems);
3037   queue_empty(&solv->solutions);
3038   queue_empty(&solv->orphaned);
3039   solv->stats_learned = solv->stats_unsolvable = 0;
3040   if (solv->recommends_index)
3041     {
3042       map_empty(&solv->recommendsmap);
3043       map_empty(&solv->suggestsmap);
3044       solv->recommends_index = 0;
3045     }
3046   solv->multiversionupdaters = solv_free(solv->multiversionupdaters);
3047 
3048 
3049   /*
3050    * create basic rule set of all involved packages
3051    * use addedmap bitmap to make sure we don't create rules twice
3052    */
3053 
3054   /* create multiversion map if needed */
3055   solver_calculate_multiversionmap(pool, job, &solv->multiversion);
3056 
3057   map_init(&addedmap, pool->nsolvables);
3058   MAPSET(&addedmap, SYSTEMSOLVABLE);
3059 
3060   map_init(&installcandidatemap, pool->nsolvables);
3061   queue_init(&q);
3062 
3063   now = solv_timems(0);
3064   /*
3065    * create rules for all package that could be involved with the solving
3066    * so called: rpm rules
3067    *
3068    */
3069   initialnrules = solv->rpmrules_end ? solv->rpmrules_end : 1;
3070   if (initialnrules > 1)
3071     deduceq2addedmap(solv, &addedmap);
3072   if (solv->nrules != initialnrules)
3073     solver_shrinkrules(solv, initialnrules);
3074   solv->nrules = initialnrules;
3075   solv->rpmrules_end = 0;
3076 
3077   if (installed)
3078     {
3079       /* check for update/verify jobs as they need to be known early */
3080       for (i = 0; i < job->count; i += 2)
3081 	{
3082 	  how = job->elements[i];
3083 	  what = job->elements[i + 1];
3084 	  select = how & SOLVER_SELECTMASK;
3085 	  switch (how & SOLVER_JOBMASK)
3086 	    {
3087 	    case SOLVER_VERIFY:
3088 	      if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3089 	        solv->fixmap_all = 1;
3090 	      FOR_JOB_SELECT(p, pp, select, what)
3091 		{
3092 		  s = pool->solvables + p;
3093 		  if (s->repo != installed)
3094 		    continue;
3095 		  if (!solv->fixmap.size)
3096 		    map_grow(&solv->fixmap, installed->end - installed->start);
3097 		  MAPSET(&solv->fixmap, p - installed->start);
3098 		}
3099 	      break;
3100 	    case SOLVER_UPDATE:
3101 	      if (select == SOLVER_SOLVABLE_ALL)
3102 		{
3103 		  solv->updatemap_all = 1;
3104 		  if (how & SOLVER_FORCEBEST)
3105 		    solv->bestupdatemap_all = 1;
3106 		  if (how & SOLVER_CLEANDEPS)
3107 		    {
3108 		      FOR_REPO_SOLVABLES(installed, p, s)
3109 			add_cleandeps_package(solv, p);
3110 		    }
3111 		}
3112 	      else if (select == SOLVER_SOLVABLE_REPO)
3113 		{
3114 		  Repo *repo = pool_id2repo(pool, what);
3115 		  if (!repo)
3116 		    break;
3117 		  if (repo == installed && !(how & SOLVER_TARGETED))
3118 		    {
3119 		      solv->updatemap_all = 1;
3120 		      if (how & SOLVER_FORCEBEST)
3121 			solv->bestupdatemap_all = 1;
3122 		      if (how & SOLVER_CLEANDEPS)
3123 			{
3124 			  FOR_REPO_SOLVABLES(installed, p, s)
3125 			    add_cleandeps_package(solv, p);
3126 			}
3127 		      break;
3128 		    }
3129 		  if (solv->noautotarget && !(how & SOLVER_TARGETED))
3130 		    break;
3131 		  /* targeted update */
3132 		  FOR_REPO_SOLVABLES(repo, p, s)
3133 		    add_update_target(solv, p, how);
3134 		}
3135 	      else
3136 		{
3137 		  if (!(how & SOLVER_TARGETED))
3138 		    {
3139 		      int targeted = 1;
3140 		      FOR_JOB_SELECT(p, pp, select, what)
3141 			{
3142 			  s = pool->solvables + p;
3143 			  if (s->repo != installed)
3144 			    continue;
3145 			  if (!solv->updatemap.size)
3146 			    map_grow(&solv->updatemap, installed->end - installed->start);
3147 			  MAPSET(&solv->updatemap, p - installed->start);
3148 			  if (how & SOLVER_FORCEBEST)
3149 			    {
3150 			      if (!solv->bestupdatemap.size)
3151 				map_grow(&solv->bestupdatemap, installed->end - installed->start);
3152 			      MAPSET(&solv->bestupdatemap, p - installed->start);
3153 			    }
3154 			  if (how & SOLVER_CLEANDEPS)
3155 			    add_cleandeps_package(solv, p);
3156 			  targeted = 0;
3157 			}
3158 		      if (!targeted || solv->noautotarget)
3159 			break;
3160 		    }
3161 		  FOR_JOB_SELECT(p, pp, select, what)
3162 		    add_update_target(solv, p, how);
3163 		}
3164 	      break;
3165 	    default:
3166 	      break;
3167 	    }
3168 	}
3169 
3170       if (solv->update_targets)
3171 	transform_update_targets(solv);
3172 
3173       oldnrules = solv->nrules;
3174       FOR_REPO_SOLVABLES(installed, p, s)
3175 	solver_addrpmrulesforsolvable(solv, s, &addedmap);
3176       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3177       oldnrules = solv->nrules;
3178       FOR_REPO_SOLVABLES(installed, p, s)
3179 	solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
3180       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3181     }
3182 
3183   /*
3184    * create rules for all packages involved in the job
3185    * (to be installed or removed)
3186    */
3187 
3188   oldnrules = solv->nrules;
3189   for (i = 0; i < job->count; i += 2)
3190     {
3191       how = job->elements[i];
3192       what = job->elements[i + 1];
3193       select = how & SOLVER_SELECTMASK;
3194 
3195       switch (how & SOLVER_JOBMASK)
3196 	{
3197 	case SOLVER_INSTALL:
3198 	  FOR_JOB_SELECT(p, pp, select, what)
3199 	    {
3200 	      MAPSET(&installcandidatemap, p);
3201 	      solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3202 	    }
3203 	  break;
3204 	case SOLVER_DISTUPGRADE:
3205 	  if (select == SOLVER_SOLVABLE_ALL)
3206 	    {
3207 	      solv->dupmap_all = 1;
3208 	      solv->updatemap_all = 1;
3209 	      if (how & SOLVER_FORCEBEST)
3210 		solv->bestupdatemap_all = 1;
3211 	    }
3212 	  if (!solv->dupmap_all)
3213 	    hasdupjob = 1;
3214 	  break;
3215 	default:
3216 	  break;
3217 	}
3218     }
3219   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3220 
3221 
3222   /*
3223    * add rules for suggests, enhances
3224    */
3225   oldnrules = solv->nrules;
3226   solver_addrpmrulesforweak(solv, &addedmap);
3227   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3228 
3229   /*
3230    * first pass done, we now have all the rpm rules we need.
3231    * unify existing rules before going over all job rules and
3232    * policy rules.
3233    * at this point the system is always solvable,
3234    * as an empty system (remove all packages) is a valid solution
3235    */
3236 
3237   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3238     {
3239       int possible = 0, installable = 0;
3240       for (i = 1; i < pool->nsolvables; i++)
3241 	{
3242 	  if (pool_installable(pool, pool->solvables + i))
3243 	    installable++;
3244 	  if (MAPTST(&addedmap, i))
3245 	    possible++;
3246 	}
3247       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3248     }
3249 
3250   if (solv->nrules > initialnrules)
3251     solver_unifyrules(solv);			/* remove duplicate rpm rules */
3252   solv->rpmrules_end = solv->nrules;		/* mark end of rpm rules */
3253 
3254   if (solv->nrules > initialnrules)
3255     addedmap2deduceq(solv, &addedmap);		/* so that we can recreate the addedmap */
3256 
3257   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3258   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now));
3259 
3260   /* create dup maps if needed. We need the maps early to create our
3261    * update rules */
3262   if (hasdupjob)
3263     solver_createdupmaps(solv);
3264 
3265   /*
3266    * create feature rules
3267    *
3268    * foreach installed:
3269    *   create assertion (keep installed, if no update available)
3270    *   or
3271    *   create update rule (A|update1(A)|update2(A)|...)
3272    *
3273    * those are used later on to keep a version of the installed packages in
3274    * best effort mode
3275    */
3276 
3277   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3278   if (installed)
3279     {
3280       /* foreach possibly installed solvable */
3281       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3282 	{
3283 	  if (s->repo != installed)
3284 	    {
3285 	      solver_addrule(solv, 0, 0);	/* create dummy rule */
3286 	      continue;
3287 	    }
3288 	  solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3289 	}
3290       /* make sure we accounted for all rules */
3291       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3292     }
3293   solv->featurerules_end = solv->nrules;
3294 
3295     /*
3296      * Add update rules for installed solvables
3297      *
3298      * almost identical to feature rules
3299      * except that downgrades/archchanges/vendorchanges are not allowed
3300      */
3301 
3302   solv->updaterules = solv->nrules;
3303 
3304   if (installed)
3305     { /* foreach installed solvables */
3306       /* we create all update rules, but disable some later on depending on the job */
3307       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3308 	{
3309 	  Rule *sr;
3310 
3311 	  if (s->repo != installed)
3312 	    {
3313 	      solver_addrule(solv, 0, 0);	/* create dummy rule */
3314 	      continue;
3315 	    }
3316 	  solver_addupdaterule(solv, s, 0);	/* allowall = 0: downgrades not allowed */
3317 	  /*
3318 	   * check for and remove duplicate
3319 	   */
3320 	  r = solv->rules + solv->nrules - 1;           /* r: update rule */
3321 	  sr = r - (installed->end - installed->start); /* sr: feature rule */
3322 	  /* it's orphaned if there is no feature rule or the feature rule
3323            * consists just of the installed package */
3324 	  if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
3325 	    queue_push(&solv->orphaned, i);
3326           if (!r->p)
3327 	    {
3328 	      assert(solv->dupmap_all && !sr->p);
3329 	      continue;
3330 	    }
3331 	  if (!solver_rulecmp(solv, r, sr))
3332 	    memset(sr, 0, sizeof(*sr));		/* delete unneeded feature rule */
3333 	  else
3334 	    solver_disablerule(solv, sr);	/* disable feature rule */
3335 	}
3336       /* consistency check: we added a rule for _every_ installed solvable */
3337       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3338     }
3339   solv->updaterules_end = solv->nrules;
3340 
3341 
3342   /*
3343    * now add all job rules
3344    */
3345 
3346   solv->jobrules = solv->nrules;
3347   for (i = 0; i < job->count; i += 2)
3348     {
3349       oldnrules = solv->nrules;
3350 
3351       if (i && i == solv->pooljobcnt)
3352         POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
3353       how = job->elements[i];
3354       what = job->elements[i + 1];
3355       weak = how & SOLVER_WEAK;
3356       select = how & SOLVER_SELECTMASK;
3357       switch (how & SOLVER_JOBMASK)
3358 	{
3359 	case SOLVER_INSTALL:
3360 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3361 	  if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3362 	    map_grow(&solv->cleandepsmap, installed->end - installed->start);
3363 	  if (select == SOLVER_SOLVABLE)
3364 	    {
3365 	      p = what;
3366 	      d = 0;
3367 	    }
3368 	  else
3369 	    {
3370 	      queue_empty(&q);
3371 	      FOR_JOB_SELECT(p, pp, select, what)
3372 		queue_push(&q, p);
3373 	      if (!q.count)
3374 		{
3375 		  /* no candidate found, make this an impossible rule */
3376 		  queue_push(&q, -SYSTEMSOLVABLE);
3377 		}
3378 	      p = queue_shift(&q);	/* get first candidate */
3379 	      d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);	/* internalize */
3380 	    }
3381 	  /* force install of namespace supplements hack */
3382 	  if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3383 	    {
3384 	      Reldep *rd = GETRELDEP(pool, what);
3385 	      if (rd->flags == REL_NAMESPACE)
3386 		{
3387 		  p = SYSTEMSOLVABLE;
3388 		  if (!solv->installsuppdepq)
3389 		    {
3390 		      solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3391 		      queue_init(solv->installsuppdepq);
3392 		    }
3393 		  queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3394 		}
3395 	    }
3396 	  solver_addjobrule(solv, p, d, i, weak);
3397           if (how & SOLVER_FORCEBEST)
3398 	    hasbestinstalljob = 1;
3399 	  break;
3400 	case SOLVER_ERASE:
3401 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3402 	  if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3403 	    map_grow(&solv->cleandepsmap, installed->end - installed->start);
3404 	  /* specific solvable: by id or by nevra */
3405 	  name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3406 	  if (select == SOLVER_SOLVABLE_ALL)	/* hmmm ;) */
3407 	    {
3408 	      FOR_POOL_SOLVABLES(p)
3409 	        solver_addjobrule(solv, -p, 0, i, weak);
3410 	    }
3411 	  else if (select == SOLVER_SOLVABLE_REPO)
3412 	    {
3413 	      Repo *repo = pool_id2repo(pool, what);
3414 	      if (repo)
3415 		FOR_REPO_SOLVABLES(repo, p, s)
3416 		  solver_addjobrule(solv, -p, 0, i, weak);
3417 	    }
3418 	  FOR_JOB_SELECT(p, pp, select, what)
3419 	    {
3420 	      s = pool->solvables + p;
3421 	      if (installed && s->repo == installed)
3422 		name = !name ? s->name : -1;
3423 	      solver_addjobrule(solv, -p, 0, i, weak);
3424 	    }
3425 	  /* special case for "erase a specific solvable": we also
3426 	   * erase all other solvables with that name, so that they
3427 	   * don't get picked up as replacement.
3428 	   * name is > 0 if exactly one installed solvable matched.
3429 	   */
3430 	  /* XXX: look also at packages that obsolete this package? */
3431 	  if (name > 0)
3432 	    {
3433 	      int j, k;
3434 	      k = solv->nrules;
3435 	      FOR_PROVIDES(p, pp, name)
3436 		{
3437 		  s = pool->solvables + p;
3438 		  if (s->name != name)
3439 		    continue;
3440 		  /* keep other versions installed */
3441 		  if (s->repo == installed)
3442 		    continue;
3443 		  /* keep installcandidates of other jobs */
3444 		  if (MAPTST(&installcandidatemap, p))
3445 		    continue;
3446 		  /* don't add the same rule twice */
3447 		  for (j = oldnrules; j < k; j++)
3448 		    if (solv->rules[j].p == -p)
3449 		      break;
3450 		  if (j == k)
3451 		    solver_addjobrule(solv, -p, 0, i, weak);	/* remove by id */
3452 		}
3453 	    }
3454 	  break;
3455 
3456 	case SOLVER_UPDATE:
3457 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3458 	  break;
3459 	case SOLVER_VERIFY:
3460 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3461 	  break;
3462 	case SOLVER_WEAKENDEPS:
3463 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3464 	  if (select != SOLVER_SOLVABLE)
3465 	    break;
3466 	  s = pool->solvables + what;
3467 	  weaken_solvable_deps(solv, what);
3468 	  break;
3469 	case SOLVER_MULTIVERSION:
3470 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3471 	  break;
3472 	case SOLVER_LOCK:
3473 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3474 	  if (select == SOLVER_SOLVABLE_ALL)
3475 	    {
3476 	      FOR_POOL_SOLVABLES(p)
3477 	        solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3478 	    }
3479           else if (select == SOLVER_SOLVABLE_REPO)
3480 	    {
3481 	      Repo *repo = pool_id2repo(pool, what);
3482 	      if (repo)
3483 	        FOR_REPO_SOLVABLES(repo, p, s)
3484 	          solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3485 	    }
3486 	  FOR_JOB_SELECT(p, pp, select, what)
3487 	    solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3488 	  break;
3489 	case SOLVER_DISTUPGRADE:
3490 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3491 	  break;
3492 	case SOLVER_DROP_ORPHANED:
3493 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3494 	  if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3495 	    solv->droporphanedmap_all = 1;
3496 	  FOR_JOB_SELECT(p, pp, select, what)
3497 	    {
3498 	      s = pool->solvables + p;
3499 	      if (!installed || s->repo != installed)
3500 		continue;
3501 	      if (!solv->droporphanedmap.size)
3502 		map_grow(&solv->droporphanedmap, installed->end - installed->start);
3503 	      MAPSET(&solv->droporphanedmap, p - installed->start);
3504 	    }
3505 	  break;
3506 	case SOLVER_USERINSTALLED:
3507 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3508 	  break;
3509 	default:
3510 	  POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3511 	  break;
3512 	}
3513 
3514 	/*
3515 	 * debug
3516 	 */
3517 
3518       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3519 	{
3520 	  int j;
3521 	  if (solv->nrules == oldnrules)
3522 	    POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
3523 	  for (j = oldnrules; j < solv->nrules; j++)
3524 	    {
3525 	      POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
3526 	      solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3527 	    }
3528 	}
3529     }
3530   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3531   solv->jobrules_end = solv->nrules;
3532 
3533   /* now create infarch and dup rules */
3534   if (!solv->noinfarchcheck)
3535     {
3536       solver_addinfarchrules(solv, &addedmap);
3537       if (pool->obsoleteusescolors)
3538 	{
3539 	  /* currently doesn't work well with infarch rules, so make
3540            * them weak */
3541 	  for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3542 	    queue_push(&solv->weakruleq, i);
3543 	}
3544     }
3545   else
3546     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3547 
3548   if (hasdupjob)
3549     solver_addduprules(solv, &addedmap);
3550   else
3551     solv->duprules = solv->duprules_end = solv->nrules;
3552 
3553   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3554     solver_addbestrules(solv, hasbestinstalljob);
3555   else
3556     solv->bestrules = solv->bestrules_end = solv->nrules;
3557 
3558   if (hasdupjob)
3559     solver_freedupmaps(solv);	/* no longer needed */
3560 
3561   if (1)
3562     solver_addchoicerules(solv);
3563   else
3564     solv->choicerules = solv->choicerules_end = solv->nrules;
3565 
3566   if (0)
3567     {
3568       for (i = solv->featurerules; i < solv->nrules; i++)
3569         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3570     }
3571   /* all rules created
3572    * --------------------------------------------------------------
3573    * prepare for solving
3574    */
3575 
3576   /* free unneeded memory */
3577   map_free(&addedmap);
3578   map_free(&installcandidatemap);
3579   queue_free(&q);
3580 
3581   POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
3582   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3583 
3584   /* create weak map */
3585   map_init(&solv->weakrulemap, solv->nrules);
3586   for (i = 0; i < solv->weakruleq.count; i++)
3587     {
3588       p = solv->weakruleq.elements[i];
3589       MAPSET(&solv->weakrulemap, p);
3590     }
3591 
3592   /* enable cleandepsmap creation if we have updatepkgs */
3593   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
3594     map_grow(&solv->cleandepsmap, installed->end - installed->start);
3595   /* no mistakes */
3596   if (solv->cleandeps_mistakes)
3597     {
3598       queue_free(solv->cleandeps_mistakes);
3599       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
3600     }
3601 
3602   /* all new rules are learnt after this point */
3603   solv->learntrules = solv->nrules;
3604 
3605   /* create watches chains */
3606   makewatches(solv);
3607 
3608   /* create assertion index. it is only used to speed up
3609    * makeruledecsions() a bit */
3610   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
3611     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
3612       queue_push(&solv->ruleassertions, i);
3613 
3614   /* disable update rules that conflict with our job */
3615   solver_disablepolicyrules(solv);
3616 
3617   /* make initial decisions based on assertion rules */
3618   makeruledecisions(solv);
3619   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
3620 
3621   /*
3622    * ********************************************
3623    * solve!
3624    * ********************************************
3625    */
3626 
3627   now = solv_timems(0);
3628   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
3629   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
3630 
3631   /*
3632    * prepare solution queue if there were problems
3633    */
3634   solver_prepare_solutions(solv);
3635 
3636   POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
3637   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
3638 
3639   /* return number of problems */
3640   return solv->problems.count ? solv->problems.count / 2 : 0;
3641 }
3642 
3643 Transaction *
3644 solver_create_transaction(Solver *solv)
3645 {
3646   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion);
3647 }
3648 
3649 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
3650 {
3651   queue_free(orphanedq);
3652   queue_init_clone(orphanedq, &solv->orphaned);
3653 }
3654 
3655 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
3656 {
3657   Pool *pool = solv->pool;
3658   Queue redoq, disabledq;
3659   int goterase, i;
3660   Solvable *s;
3661   Rule *r;
3662   Map obsmap;
3663 
3664   if (!recommendationsq && !suggestionsq)
3665     return;
3666 
3667   map_init(&obsmap, pool->nsolvables);
3668   if (solv->installed)
3669     {
3670       Id obs, *obsp, p, po, ppo;
3671       for (p = solv->installed->start; p < solv->installed->end; p++)
3672 	{
3673 	  s = pool->solvables + p;
3674 	  if (s->repo != solv->installed || !s->obsoletes)
3675 	    continue;
3676 	  if (solv->decisionmap[p] <= 0)
3677 	    continue;
3678 	  if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
3679 	    continue;
3680 	  obsp = s->repo->idarraydata + s->obsoletes;
3681 	  /* foreach obsoletes */
3682 	  while ((obs = *obsp++) != 0)
3683 	    FOR_PROVIDES(po, ppo, obs)
3684 	      MAPSET(&obsmap, po);
3685 	}
3686     }
3687 
3688   queue_init(&redoq);
3689   queue_init(&disabledq);
3690   goterase = 0;
3691   /* disable all erase jobs (including weak "keep uninstalled" rules) */
3692   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
3693     {
3694       if (r->d < 0)	/* disabled ? */
3695 	continue;
3696       if (r->p >= 0)	/* install job? */
3697 	continue;
3698       queue_push(&disabledq, i);
3699       solver_disablerule(solv, r);
3700       goterase++;
3701     }
3702 
3703   if (goterase)
3704     {
3705       enabledisablelearntrules(solv);
3706       removedisabledconflicts(solv, &redoq);
3707     }
3708 
3709   /*
3710    * find recommended packages
3711    */
3712   if (recommendationsq)
3713     {
3714       Id rec, *recp, p, pp;
3715 
3716       queue_empty(recommendationsq);
3717       /* create map of all recommened packages */
3718       solv->recommends_index = -1;
3719       MAPZERO(&solv->recommendsmap);
3720 
3721       /* put all packages the solver already chose in the map */
3722       if (solv->decisioncnt_weak)
3723 	{
3724 	  for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
3725 	    {
3726 	      Id why;
3727 	      why = solv->decisionq_why.elements[i];
3728 	      if (why)
3729 		continue;	/* forced by unit rule */
3730 	      p = solv->decisionq.elements[i];
3731 	      if (p < 0)
3732 		continue;
3733 	      MAPSET(&solv->recommendsmap, p);
3734 	    }
3735 	}
3736 
3737       for (i = 0; i < solv->decisionq.count; i++)
3738 	{
3739 	  p = solv->decisionq.elements[i];
3740 	  if (p < 0)
3741 	    continue;
3742 	  s = pool->solvables + p;
3743 	  if (s->recommends)
3744 	    {
3745 	      recp = s->repo->idarraydata + s->recommends;
3746 	      while ((rec = *recp++) != 0)
3747 		{
3748 		  FOR_PROVIDES(p, pp, rec)
3749 		    if (solv->decisionmap[p] > 0)
3750 		      break;
3751 		  if (p)
3752 		    {
3753 		      if (!noselected)
3754 			{
3755 			  FOR_PROVIDES(p, pp, rec)
3756 			    if (solv->decisionmap[p] > 0)
3757 			      MAPSET(&solv->recommendsmap, p);
3758 			}
3759 		      continue;	/* p != 0: already fulfilled */
3760 		    }
3761 		  FOR_PROVIDES(p, pp, rec)
3762 		    MAPSET(&solv->recommendsmap, p);
3763 		}
3764 	    }
3765 	}
3766       for (i = 1; i < pool->nsolvables; i++)
3767 	{
3768 	  if (solv->decisionmap[i] < 0)
3769 	    continue;
3770 	  if (solv->decisionmap[i] > 0 && noselected)
3771 	    continue;
3772           if (MAPTST(&obsmap, i))
3773 	    continue;
3774 	  s = pool->solvables + i;
3775 	  if (!MAPTST(&solv->recommendsmap, i))
3776 	    {
3777 	      if (!s->supplements)
3778 		continue;
3779 	      if (!pool_installable(pool, s))
3780 		continue;
3781 	      if (!solver_is_supplementing(solv, s))
3782 		continue;
3783 	    }
3784 	  queue_push(recommendationsq, i);
3785 	}
3786       /* we use MODE_SUGGEST here so that repo prio is ignored */
3787       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
3788     }
3789 
3790   /*
3791    * find suggested packages
3792    */
3793 
3794   if (suggestionsq)
3795     {
3796       Id sug, *sugp, p, pp;
3797 
3798       queue_empty(suggestionsq);
3799       /* create map of all suggests that are still open */
3800       solv->recommends_index = -1;
3801       MAPZERO(&solv->suggestsmap);
3802       for (i = 0; i < solv->decisionq.count; i++)
3803 	{
3804 	  p = solv->decisionq.elements[i];
3805 	  if (p < 0)
3806 	    continue;
3807 	  s = pool->solvables + p;
3808 	  if (s->suggests)
3809 	    {
3810 	      sugp = s->repo->idarraydata + s->suggests;
3811 	      while ((sug = *sugp++) != 0)
3812 		{
3813 		  FOR_PROVIDES(p, pp, sug)
3814 		    if (solv->decisionmap[p] > 0)
3815 		      break;
3816 		  if (p)
3817 		    {
3818 		      if (!noselected)
3819 			{
3820 			  FOR_PROVIDES(p, pp, sug)
3821 			    if (solv->decisionmap[p] > 0)
3822 			      MAPSET(&solv->suggestsmap, p);
3823 			}
3824 		      continue;	/* already fulfilled */
3825 		    }
3826 		  FOR_PROVIDES(p, pp, sug)
3827 		    MAPSET(&solv->suggestsmap, p);
3828 		}
3829 	    }
3830 	}
3831       for (i = 1; i < pool->nsolvables; i++)
3832 	{
3833 	  if (solv->decisionmap[i] < 0)
3834 	    continue;
3835 	  if (solv->decisionmap[i] > 0 && noselected)
3836 	    continue;
3837           if (MAPTST(&obsmap, i))
3838 	    continue;
3839 	  s = pool->solvables + i;
3840 	  if (!MAPTST(&solv->suggestsmap, i))
3841 	    {
3842 	      if (!s->enhances)
3843 		continue;
3844 	      if (!pool_installable(pool, s))
3845 		continue;
3846 	      if (!solver_is_enhancing(solv, s))
3847 		continue;
3848 	    }
3849 	  queue_push(suggestionsq, i);
3850 	}
3851       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
3852     }
3853 
3854   /* undo removedisabledconflicts */
3855   if (redoq.count)
3856     undo_removedisabledconflicts(solv, &redoq);
3857   queue_free(&redoq);
3858 
3859   /* undo job rule disabling */
3860   for (i = 0; i < disabledq.count; i++)
3861     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
3862   queue_free(&disabledq);
3863   map_free(&obsmap);
3864 }
3865 
3866 
3867 /***********************************************************************/
3868 /* disk usage computations */
3869 
3870 /*-------------------------------------------------------------------
3871  *
3872  * calculate DU changes
3873  */
3874 
3875 void
3876 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
3877 {
3878   Map installedmap;
3879 
3880   solver_create_state_maps(solv, &installedmap, 0);
3881   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
3882   map_free(&installedmap);
3883 }
3884 
3885 
3886 /*-------------------------------------------------------------------
3887  *
3888  * calculate changes in install size
3889  */
3890 
3891 int
3892 solver_calc_installsizechange(Solver *solv)
3893 {
3894   Map installedmap;
3895   int change;
3896 
3897   solver_create_state_maps(solv, &installedmap, 0);
3898   change = pool_calc_installsizechange(solv->pool, &installedmap);
3899   map_free(&installedmap);
3900   return change;
3901 }
3902 
3903 void
3904 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
3905 {
3906   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
3907 }
3908 
3909 void
3910 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
3911 {
3912   Pool *pool = solv->pool;
3913   Map installedmap;
3914   int i;
3915   pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
3916   pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
3917   for (i = 0; i < res->count; i++)
3918     if (res->elements[i] != -1)
3919       {
3920 	Solvable *s = pool->solvables + pkgs->elements[i];
3921 	if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
3922 	  res->elements[i] = -1;
3923       }
3924   map_free(&installedmap);
3925 }
3926 
3927 /*-------------------------------------------------------------------
3928  *
3929  * decision introspection
3930  */
3931 
3932 int
3933 solver_get_decisionlevel(Solver *solv, Id p)
3934 {
3935   return solv->decisionmap[p];
3936 }
3937 
3938 void
3939 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
3940 {
3941   queue_free(decisionq);
3942   queue_init_clone(decisionq, &solv->decisionq);
3943 }
3944 
3945 int
3946 solver_get_lastdecisionblocklevel(Solver *solv)
3947 {
3948   Id p;
3949   if (solv->decisionq.count == 0)
3950     return 0;
3951   p = solv->decisionq.elements[solv->decisionq.count - 1];
3952   if (p < 0)
3953     p = -p;
3954   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
3955 }
3956 
3957 void
3958 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
3959 {
3960   Id p;
3961   int i;
3962 
3963   queue_empty(decisionq);
3964   for (i = 0; i < solv->decisionq.count; i++)
3965     {
3966       p = solv->decisionq.elements[i];
3967       if (p < 0)
3968 	p = -p;
3969       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3970         break;
3971     }
3972   if (i == solv->decisionq.count)
3973     return;
3974   for (i = 0; i < solv->decisionq.count; i++)
3975     {
3976       p = solv->decisionq.elements[i];
3977       if (p < 0)
3978 	p = -p;
3979       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3980         queue_push(decisionq, p);
3981       else
3982         break;
3983     }
3984 }
3985 
3986 int
3987 solver_describe_decision(Solver *solv, Id p, Id *infop)
3988 {
3989   int i;
3990   Id pp, why;
3991 
3992   if (infop)
3993     *infop = 0;
3994   if (!solv->decisionmap[p])
3995     return SOLVER_REASON_UNRELATED;
3996   pp = solv->decisionmap[p] < 0 ? -p : p;
3997   for (i = 0; i < solv->decisionq.count; i++)
3998     if (solv->decisionq.elements[i] == pp)
3999       break;
4000   if (i == solv->decisionq.count)	/* just in case... */
4001     return SOLVER_REASON_UNRELATED;
4002   why = solv->decisionq_why.elements[i];
4003   if (why > 0)
4004     {
4005       if (infop)
4006 	*infop = why;
4007       return SOLVER_REASON_UNIT_RULE;
4008     }
4009   why = -why;
4010   if (i < solv->decisioncnt_update)
4011     {
4012       if (i == 0)
4013 	{
4014 	  if (infop)
4015 	    *infop = SYSTEMSOLVABLE;
4016 	  return SOLVER_REASON_KEEP_INSTALLED;
4017 	}
4018       if (infop)
4019 	*infop = why;
4020       return SOLVER_REASON_RESOLVE_JOB;
4021     }
4022   if (i < solv->decisioncnt_keep)
4023     {
4024       if (why == 0 && pp < 0)
4025 	return SOLVER_REASON_CLEANDEPS_ERASE;
4026       if (infop)
4027 	{
4028 	  if (why >= solv->updaterules && why < solv->updaterules_end)
4029 	    *infop = why - solv->updaterules;
4030 	  else if (why >= solv->featurerules && why < solv->featurerules_end)
4031 	    *infop = why - solv->featurerules;
4032 	}
4033       return SOLVER_REASON_UPDATE_INSTALLED;
4034     }
4035   if (i < solv->decisioncnt_resolve)
4036     {
4037       if (why == 0 && pp < 0)
4038 	return SOLVER_REASON_CLEANDEPS_ERASE;
4039       if (infop)
4040 	{
4041 	  if (why >= solv->updaterules && why < solv->updaterules_end)
4042 	    *infop = why - solv->updaterules;
4043 	  else if (why >= solv->featurerules && why < solv->featurerules_end)
4044 	    *infop = why - solv->featurerules;
4045 	}
4046       return SOLVER_REASON_KEEP_INSTALLED;
4047     }
4048   if (i < solv->decisioncnt_weak)
4049     {
4050       if (infop)
4051 	*infop = why;
4052       return SOLVER_REASON_RESOLVE;
4053     }
4054   if (solv->decisionq.count < solv->decisioncnt_orphan)
4055     return SOLVER_REASON_WEAKDEP;
4056   return SOLVER_REASON_RESOLVE_ORPHAN;
4057 }
4058 
4059 
4060 void
4061 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
4062 {
4063   Pool *pool = solv->pool;
4064   int i;
4065   int level = solv->decisionmap[p];
4066   int decisionno;
4067   Solvable *s;
4068 
4069   queue_empty(whyq);
4070   if (level < 0)
4071     return;	/* huh? */
4072   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
4073     if (solv->decisionq.elements[decisionno] == p)
4074       break;
4075   if (decisionno == solv->decisionq.count)
4076     return;	/* huh? */
4077   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
4078     return;	/* huh? */
4079 
4080   /* 1) list all packages that recommend us */
4081   for (i = 1; i < pool->nsolvables; i++)
4082     {
4083       Id *recp, rec, pp2, p2;
4084       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
4085 	continue;
4086       s = pool->solvables + i;
4087       if (!s->recommends)
4088 	continue;
4089       if (!solv->addalreadyrecommended && s->repo == solv->installed)
4090 	continue;
4091       recp = s->repo->idarraydata + s->recommends;
4092       while ((rec = *recp++) != 0)
4093 	{
4094 	  int found = 0;
4095 	  FOR_PROVIDES(p2, pp2, rec)
4096 	    {
4097 	      if (p2 == p)
4098 		found = 1;
4099 	      else
4100 		{
4101 		  /* if p2 is already installed, this recommends is ignored */
4102 		  if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4103 		    break;
4104 		}
4105 	    }
4106 	  if (!p2 && found)
4107 	    {
4108 	      queue_push(whyq, SOLVER_REASON_RECOMMENDED);
4109 	      queue_push2(whyq, p2, rec);
4110 	    }
4111 	}
4112     }
4113   /* 2) list all supplements */
4114   s = pool->solvables + p;
4115   if (s->supplements && level > 0)
4116     {
4117       Id *supp, sup, pp2, p2;
4118       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
4119        * everything above our level in the decisionmap */
4120       for (i = decisionno; i < solv->decisionq.count; i++ )
4121 	{
4122 	  p2 = solv->decisionq.elements[i];
4123 	  if (p2 > 0)
4124 	    solv->decisionmap[p2] = -solv->decisionmap[p2];
4125 	}
4126       supp = s->repo->idarraydata + s->supplements;
4127       while ((sup = *supp++) != 0)
4128 	if (solver_dep_fulfilled(solv, sup))
4129 	  {
4130 	    int found = 0;
4131 	    /* let's see if this is an easy supp */
4132 	    FOR_PROVIDES(p2, pp2, sup)
4133 	      {
4134 		if (!solv->addalreadyrecommended && solv->installed)
4135 		  {
4136 		    if (pool->solvables[p2].repo == solv->installed)
4137 		      continue;
4138 		  }
4139 	        if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4140 		  {
4141 		    queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4142 		    queue_push2(whyq, p2, sup);
4143 		    found = 1;
4144 		  }
4145 	      }
4146 	    if (!found)
4147 	      {
4148 		/* hard case, just note dependency with no package */
4149 		queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4150 	        queue_push2(whyq, 0, sup);
4151 	      }
4152 	  }
4153       for (i = decisionno; i < solv->decisionq.count; i++)
4154 	{
4155 	  p2 = solv->decisionq.elements[i];
4156 	  if (p2 > 0)
4157 	    solv->decisionmap[p2] = -solv->decisionmap[p2];
4158 	}
4159     }
4160 }
4161 
4162 void
4163 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
4164 {
4165   Id p, pp;
4166   how &= SOLVER_SELECTMASK;
4167   queue_empty(pkgs);
4168   if (how == SOLVER_SOLVABLE_ALL)
4169     {
4170       FOR_POOL_SOLVABLES(p)
4171         queue_push(pkgs, p);
4172     }
4173   else if (how == SOLVER_SOLVABLE_REPO)
4174     {
4175       Repo *repo = pool_id2repo(pool, what);
4176       Solvable *s;
4177       if (repo)
4178 	FOR_REPO_SOLVABLES(repo, p, s)
4179 	  queue_push(pkgs, p);
4180     }
4181   else
4182     {
4183       FOR_JOB_SELECT(p, pp, how, what)
4184 	queue_push(pkgs, p);
4185     }
4186 }
4187 
4188 int
4189 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4190 {
4191   Id p, pp, pi, pip;
4192   Id select = how & SOLVER_SELECTMASK;
4193   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4194     return 0;
4195   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4196     return 0;
4197   if (!pool->installed)
4198     return 1;
4199   FOR_JOB_SELECT(p, pp, select, what)
4200     if (pool->solvables[p].repo == pool->installed)
4201       return 0;
4202   /* hard work */
4203   FOR_JOB_SELECT(p, pp, select, what)
4204     {
4205       Solvable *s = pool->solvables + p;
4206       FOR_PROVIDES(pi, pip, s->name)
4207 	{
4208 	  Solvable *si = pool->solvables + pi;
4209 	  if (si->repo != pool->installed || si->name != s->name)
4210 	    continue;
4211 	  return 0;
4212 	}
4213       if (s->obsoletes)
4214 	{
4215 	  Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4216 	  while ((obs = *obsp++) != 0)
4217 	    {
4218 	      FOR_PROVIDES(pi, pip, obs)
4219 		{
4220 		  Solvable *si = pool->solvables + pi;
4221 		  if (si->repo != pool->installed)
4222 		    continue;
4223 		  if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4224 		    continue;
4225 		  if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4226 		    continue;
4227 		  return 0;
4228 		}
4229 	    }
4230 	}
4231     }
4232   return 1;
4233 }
4234