- cleanup
[platform/upstream/libsolv.git] / src / solver.c
index a0b04f6..af66605 100644 (file)
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <assert.h>
 
 #include "solver.h"
 #include "bitmap.h"
 #include "evr.h"
 #include "policy.h"
 
+
+
 #define RULES_BLOCK 63
 
 
 int
+solver_splitprovides(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, *pp;
+  Reldep *rd;
+  Solvable *s;
+
+  if (!solv->dosplitprovides || !solv->installed)
+    return 0;
+  if (!ISRELDEP(dep))
+    return 0;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags != REL_WITH)
+    return 0;
+  FOR_PROVIDES(p, pp, dep)
+    {
+      s = pool->solvables + p;
+      if (s->repo == solv->installed && s->name == rd->name)
+       return 1;
+    }
+  return 0;
+}
+
+int
 solver_dep_installed(Solver *solv, Id dep)
 {
-  /* disable for now, splitprovides don't work anyway and it breaks
-     a testcase */
 #if 0
   Pool *pool = solv->pool;
   Id p, *pp;
@@ -40,16 +65,16 @@ solver_dep_installed(Solver *solv, Id dep)
       Reldep *rd = GETRELDEP(pool, dep);
       if (rd->flags == REL_AND)
        {
-         if (!dep_installed(solv, rd->name))
+         if (!solver_dep_installed(solv, rd->name))
            return 0;
-         return dep_installed(solv, rd->evr);
+         return solver_dep_installed(solv, rd->evr);
        }
       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
-       return dep_installed(solv, rd->evr);
+       return solver_dep_installed(solv, rd->evr);
     }
   FOR_PROVIDES(p, pp, dep)
     {
-      if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables)
+      if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
        return 1;
     }
 #endif
@@ -73,6 +98,8 @@ dep_possible(Solver *solv, Id dep, Map *m)
            return 0;
          return dep_possible(solv, rd->evr, m);
        }
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+       return solver_splitprovides(solv, rd->evr);
       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
        return solver_dep_installed(solv, rd->evr);
     }
@@ -91,34 +118,32 @@ dep_possible(Solver *solv, Id dep, Map *m)
  */
 
 static void
-printruleelement(Solver *solv, Rule *r, Id v)
+printruleelement(Solver *solv, int type, Rule *r, Id v)
 {
   Pool *pool = solv->pool;
   Solvable *s;
   if (v < 0)
     {
       s = pool->solvables + -v;
-      printf("    !%s-%s.%s [%d]", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), -v);
+      POOL_DEBUG(type, "    !%s [%d]", solvable2str(pool, s), -v);
     }
   else
     {
       s = pool->solvables + v;
-      printf("    %s-%s.%s [%d]", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), v);
+      POOL_DEBUG(type, "    %s [%d]", solvable2str(pool, s), v);
     }
   if (r)
     {
       if (r->w1 == v)
-       printf(" (w1)");
+       POOL_DEBUG(type, " (w1)");
       if (r->w2 == v)
-       printf(" (w2)");
+       POOL_DEBUG(type, " (w2)");
     }
   if (solv->decisionmap[s - pool->solvables] > 0)
-    printf(" I.%d", solv->decisionmap[s - pool->solvables]);
+    POOL_DEBUG(type, " Install.level%d", solv->decisionmap[s - pool->solvables]);
   if (solv->decisionmap[s - pool->solvables] < 0)
-    printf(" C.%d", -solv->decisionmap[s - pool->solvables]);
-  if (r && r->w1 == 0)
-    printf(" (disabled)");
-  printf("\n");
+    POOL_DEBUG(type, " Conflict.level%d", -solv->decisionmap[s - pool->solvables]);
+  POOL_DEBUG(type, "\n");
 }
 
 
@@ -127,32 +152,57 @@ printruleelement(Solver *solv, Rule *r, Id v)
  */
 
 static void
-printrule(Solver *solv, Rule *r)
+printrule(Solver *solv, int type, Rule *r)
 {
+  Pool *pool = solv->pool;
   int i;
   Id v;
 
   if (r >= solv->rules && r < solv->rules + solv->nrules)   /* r is a solver rule */
-    printf("Rule #%d:\n", (int)(r - solv->rules));
+    POOL_DEBUG(type, "Rule #%d:", (int)(r - solv->rules));
   else
-    printf("Rule:\n");                /* r is any rule */
+    POOL_DEBUG(type, "Rule:");                /* r is any rule */
+  if (r && r->w1 == 0)
+    POOL_DEBUG(type, " (disabled)");
+  POOL_DEBUG(type, "\n");
   for (i = 0; ; i++)
     {
       if (i == 0)
+         /* print direct literal */
        v = r->p;
       else if (r->d == ID_NULL)
        {
          if (i == 2)
            break;
+         /* binary rule --> print w2 as second literal */
          v = r->w2;
        }
       else
+         /* every other which is in d */
        v = solv->pool->whatprovidesdata[r->d + i - 1];
       if (v == ID_NULL)
        break;
-      printruleelement(solv, r, v);
+      printruleelement(solv, type, r, v);
     }
-  printf("    next: %d %d\n", r->n1, r->n2);
+  POOL_DEBUG(type, "    next rules: %d %d\n", r->n1, r->n2);
+}
+
+static void
+printruleclass(Solver *solv, int type, Rule *r)
+{
+  Pool *pool = solv->pool;
+  Id p = r - solv->rules;
+  assert(p >= 0);
+  if (p < solv->learntrules)
+    if (MAPTST(&solv->weakrulemap, p))
+      POOL_DEBUG(type, "WEAK ");
+  if (p >= solv->learntrules)
+    POOL_DEBUG(type, "LEARNT ");
+  else if (p >= solv->systemrules)
+    POOL_DEBUG(type, "SYSTEM ");
+  else if (p >= solv->jobrules)
+    POOL_DEBUG(type, "JOB ");
+  printrule(solv, type, r);
 }
 
 
@@ -176,7 +226,7 @@ unifyrules_sortcmp(const void *ap, const void *bp)
   Rule *b = (Rule *)bp;
   Id *ad, *bd;
   int x;
-  
+
   x = a->p - b->p;
   if (x)
     return x;                         /* p differs */
@@ -214,12 +264,15 @@ unifyrules_sortcmp(const void *ap, const void *bp)
 static void
 unifyrules(Solver *solv)
 {
+  Pool *pool = solv->pool;
   int i, j;
   Rule *ir, *jr;
 
   if (solv->nrules <= 1)              /* nothing to unify */
     return;
 
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
+
   /* sort rules first */
   unifyrules_sortcmp_data = solv->pool;
   qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
@@ -229,7 +282,7 @@ unifyrules(Solver *solv)
    * j = pruned
    */
   jr = 0;
-  for (i = j = 1, ir = solv->rules + 1; i < solv->nrules; i++, ir++)
+  for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
     {
       if (jr && !unifyrules_sortcmp(ir, jr))
        continue;                      /* prune! */
@@ -239,13 +292,12 @@ unifyrules(Solver *solv)
     }
 
   /* reduced count from nrules to j rules */
-  if (solv->pool->verbose) printf("pruned rules from %d to %d\n", solv->nrules, j);
+  POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
 
   /* adapt rule buffer */
-  solv->rules = (Rule *)xrealloc(solv->rules, ((solv->nrules + RULES_BLOCK) & ~RULES_BLOCK) * sizeof(Rule));
   solv->nrules = j;
-#if 1
-  if (solv->pool->verbose)
+  solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
+  IF_POOLDEBUG (SAT_DEBUG_STATS)
     {
       int binr = 0;
       int lits = 0;
@@ -264,10 +316,10 @@ unifyrules(Solver *solv)
                lits++;
            }
        }
-      printf("  binary: %d\n", binr);
-      printf("  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
+      POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
+      POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
     }
-#endif
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
 }
 
 #if 0
@@ -283,7 +335,7 @@ hashrule(Solver *solv, Id p, Id d, int n)
   int *dp;
 
   if (n <= 1)
-    return (x * 37) ^ (unsigned int)d; 
+    return (x * 37) ^ (unsigned int)d;
   dp = solv->pool->whatprovidesdata + d;
   while (*dp)
     x = (x * 37) ^ (unsigned int)*dp++;
@@ -294,32 +346,43 @@ hashrule(Solver *solv, Id p, Id d, int n)
 
 /*
  * add rule
- *  p = direct literal; > 0 for learnt, < 0 for installed pkg (rpm)
+ *  p = direct literal; always < 0 for installed rpm rules
  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
  *
  *
  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
- * 
- * p < 0 : rule from rpm (installed pkg)
- * d > 0 : Offset in whatprovidesdata (list of providers)
- * 
+ *
+ * p < 0 : pkg id of A
+ * d > 0 : Offset in whatprovidesdata (list of providers of b)
+ *
  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
- *  d < 0: Id of solvable (e.g. B1)
- * 
+ * p < 0 : pkg id of A
+ * d < 0 : Id of solvable (e.g. B1)
+ *
  * d == 0: unary rule, assertion => (A) or (-A)
- * 
+ *
  *   Install:    p > 0, d = 0   (A)             user requested install
  *   Remove:     p < 0, d = 0   (-A)            user requested remove
  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
- *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider)
+ *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
  *   ?           p > 0, d < 0   (A|-B)
  *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
+ *
+ *   resulting watches:
+ *   ------------------
+ *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
+ *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
+ *   every other : w1 = p, w2 = whatprovidesdata[d];
+ *   Disabled rule: w1 = 0
+ *
+ *   always returns a rule for non-rpm rules
  */
 
 static Rule *
 addrule(Solver *solv, Id p, Id d)
 {
+  Pool *pool = solv->pool;
   Rule *r = 0;
   Id *dp = 0;
 
@@ -341,41 +404,38 @@ addrule(Solver *solv, Id p, Id d)
 
   if (d < 0)
     {
+      /* always a binary rule */
       if (p == d)
        return 0;                      /* ignore self conflict */
       n = 1;
     }
-  else if (d == 0)                    /* user requested */
-    n = 0;
-  else
+  else if (d > 0)
     {
-      for (dp = solv->pool->whatprovidesdata + d; *dp; dp++, n++)
+      for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
        if (*dp == -p)
          return 0;                     /* rule is self-fulfilling */
       if (n == 1)
-       d = dp[-1];
+       d = dp[-1];                     /* take single literal */
     }
 
-  if (n == 0)                         /* direct assertion */
+#if 0
+  if (n == 0 && !solv->jobrules)
     {
-      if (!solv->jobrules)
-       {
-         /* this is a rpm rule assertion, we do not have to allocate it */
-         /* it can be identified by a level of 1 and a zero reason */
-         /* we must not drop those rules from the decisionq when rewinding! */
-         if (p > 0)
-           abort();
-         if (solv->decisionmap[-p] > 0 || solv->decisionmap[-p] < -1)
-           abort();
-         if (solv->decisionmap[-p])
-           return NULL;
-         queue_push(&solv->decisionq, p);
-         queue_push(&solv->decisionq_why, 0);
-         solv->decisionmap[-p] = -1;
-         return 0;
-       }
+      /* this is a rpm rule assertion, we do not have to allocate it */
+      /* it can be identified by a level of 1 and a zero reason */
+      /* we must not drop those rules from the decisionq when rewinding! */
+      assert(p < 0);
+      assert(solv->decisionmap[-p] == 0 || solv->decisionmap[-p] == -1);
+      if (solv->decisionmap[-p])
+       return 0;       /* already got that one */
+      queue_push(&solv->decisionq, p);
+      queue_push(&solv->decisionq_why, 0);
+      solv->decisionmap[-p] = -1;
+      return 0;
     }
-  else if (n == 1 && p > d)
+#endif
+
+  if (n == 1 && p > d)
     {
       /* smallest literal first so we can find dups */
       n = p;
@@ -386,31 +446,28 @@ addrule(Solver *solv, Id p, Id d)
 
   /* check if the last added rule is exactly the same as what we're looking for. */
   if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
-    return r;
+    return r;  /* binary rule */
 
   if (r && n > 1 && r->d && r->p == p)
     {
+      /* Rule where d is an offset in whatprovidesdata */
       Id *dp2;
       if (d == r->d)
        return r;
-      dp2 = solv->pool->whatprovidesdata + r->d;
-      for (dp = solv->pool->whatprovidesdata + d; *dp; dp++, dp2++)
+      dp2 = pool->whatprovidesdata + r->d;
+      for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
        if (*dp != *dp2)
          break;
       if (*dp == *dp2)
        return r;
    }
-  
+
   /*
    * allocate new rule
    */
 
-  /* check and extend rule buffer */
-  if ((solv->nrules & RULES_BLOCK) == 0)
-    {
-      solv->rules = (Rule *)xrealloc(solv->rules, (solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
-    }
-
+  /* extend rule buffer */
+  solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
   r = solv->rules + solv->nrules++;    /* point to rule space */
 
   r->p = p;
@@ -432,10 +489,17 @@ addrule(Solver *solv, Id p, Id d)
     {
       r->d = d;
       r->w1 = p;
-      r->w2 = solv->pool->whatprovidesdata[d];
+      r->w2 = pool->whatprovidesdata[d];
     }
   r->n1 = 0;
   r->n2 = 0;
+
+  IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
+    {
+      POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
+      printrule(solv, SAT_DEBUG_RULE_CREATION, r);
+    }
+
   return r;
 }
 
@@ -462,7 +526,7 @@ enablerule(Solver *solv, Rule *r)
  * consisting of multiple job rules.
  */
 
-static void 
+static void
 disableproblem(Solver *solv, Id v)
 {
   Rule *r;
@@ -481,7 +545,7 @@ disableproblem(Solver *solv, Id v)
       disablerule(solv, r);
 }
 
-static void 
+static void
 enableproblem(Solver *solv, Id v)
 {
   Rule *r;
@@ -503,29 +567,31 @@ enableproblem(Solver *solv, Id v)
 static void
 printproblem(Solver *solv, Id v)
 {
+  Pool *pool = solv->pool;
   int i;
   Rule *r;
   Id *jp;
 
   if (v > 0)
-    printrule(solv, solv->rules + v);
+    printrule(solv, SAT_DEBUG_SOLUTIONS, solv->rules + v);
   else
     {
       v = -(v + 1);
-      printf("JOB %d\n", v);
+      POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "JOB %d\n", v);
       jp = solv->ruletojob.elements;
       for (i = solv->jobrules, r = solv->rules + i; i < solv->systemrules; i++, r++, jp++)
        if (*jp == v)
          {
-           printf(" -");
-           printrule(solv, r);
+           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "- ");
+           printrule(solv, SAT_DEBUG_SOLUTIONS, r);
          }
-      printf("ENDJOB\n");
+      POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "ENDJOB\n");
     }
 }
 
 
-/**********************************************************************************/
+
+/************************************************************************/
 
 /* go through system and job rules and add direct assertions
  * to the decisionqueue. If we find a conflict, disable rules and
@@ -534,28 +600,41 @@ printproblem(Solver *solv, Id v)
 static void
 makeruledecisions(Solver *solv)
 {
+  Pool *pool = solv->pool;
   int i, ri;
   Rule *r, *rr;
   Id v, vv;
   int decisionstart;
 
-  /* no learnt rules for now */
-  if (solv->learntrules && solv->learntrules != solv->nrules)
-    abort();
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions ; size decisionq: %d -----\n",solv->decisionq.count);
 
   decisionstart = solv->decisionq.count;
-  /* the loop is over jobrules, system rules and weak rules */
-  for (ri = solv->jobrules, r = solv->rules + ri; ri < solv->nrules; ri++, r++)
+  /* rpm rules don't have assertions, so we can start with the job
+   * rules (rpm assertions are not resulting in a rule, but cause a
+   * immediate decision) */
+  /* nowadays they can be weak, so start with rule 1 */
+  for (ri = 1, r = solv->rules + ri; ri < solv->nrules; ri++, r++)
     {
-      if (!r->w1 || r->w2)
+      if (!r->w1 || r->w2)     /* disabled or no assertion */
+       continue;
+      /* do weak rules in phase 2 */
+      if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
        continue;
       v = r->p;
       vv = v > 0 ? v : -v;
-      if (solv->decisionmap[vv] == 0)
+      if (!solv->decisionmap[vv])
        {
          queue_push(&solv->decisionq, v);
          queue_push(&solv->decisionq_why, r - solv->rules);
          solv->decisionmap[vv] = v > 0 ? 1 : -1;
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
+           {
+             Solvable *s = solv->pool->solvables + vv;
+             if (v < 0)
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", solvable2str(solv->pool, s));
+             else
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "installing  %s (assertion)\n", solvable2str(solv->pool, s));
+           }
          continue;
        }
       if (v > 0 && solv->decisionmap[vv] > 0)
@@ -563,43 +642,77 @@ makeruledecisions(Solver *solv)
       if (v < 0 && solv->decisionmap[vv] < 0)
        continue;
       /* found a conflict! */
-      /* if we are weak, just disable ourself */
-      if (ri >= solv->weakrules)
+      if (ri >= solv->learntrules)
        {
-         printf("conflict, but I am weak, disabling ");
-         printrule(solv, r);
-         r->w1 = 0;
+         /* conflict with a learnt rule */
+         /* can happen when packages cannot be installed for
+           * multiple reasons. */
+          /* we disable the learnt rule in this case */
+         disablerule(solv, r);
          continue;
        }
-      /* only job and system rules left */
+      /* only job and system rules left in the decisionq */
+      /* find the decision which is the "opposite" of the jobrule */
       for (i = 0; i < solv->decisionq.count; i++)
        if (solv->decisionq.elements[i] == -v)
          break;
-      if (i == solv->decisionq.count)
-       abort();
-      if (solv->decisionq_why.elements[i] == 0)
-       {
-         /* conflict with rpm rule, need only disable our rule */
-         printf("conflict with rpm rule, disabling rule #%d\n", ri);
+      assert(i < solv->decisionq.count);
+      if (v == -SYSTEMSOLVABLE) {
+       /* conflict with system solvable */
+       queue_push(&solv->problems, solv->learnt_pool.count);
+        queue_push(&solv->learnt_pool, ri);
+       queue_push(&solv->learnt_pool, 0);
+       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
+       if (ri < solv->systemrules)
+         v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
+       else
          v = ri;
+       queue_push(&solv->problems, v);
+       queue_push(&solv->problems, 0);
+       disableproblem(solv, v);
+       continue;
+      }
+      assert(solv->decisionq_why.elements[i]);
+      if (solv->decisionq_why.elements[i] < solv->jobrules)
+       {
+         /* conflict with rpm rule assertion */
+         queue_push(&solv->problems, solv->learnt_pool.count);
+         queue_push(&solv->learnt_pool, ri);
+         queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
+         queue_push(&solv->learnt_pool, 0);
+         assert(v > 0 || v == -SYSTEMSOLVABLE);
+         POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
          if (ri < solv->systemrules)
            v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
+         else
+           v = ri;
          queue_push(&solv->problems, v);
-         disableproblem(solv, v);
          queue_push(&solv->problems, 0);
+         disableproblem(solv, v);
          continue;
        }
+
       /* conflict with another job or system rule */
-      /* remove old decision */
-      printf("conflicting system/job rules over literal %d\n", vv);
+      /* record proof */
+      queue_push(&solv->problems, solv->learnt_pool.count);
+      queue_push(&solv->learnt_pool, ri);
+      queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
+      queue_push(&solv->learnt_pool, 0);
+
+      POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "conflicting system/job assertions over literal %d\n", vv);
+
       /* push all of our rules asserting this literal on the problem stack */
       for (i = solv->jobrules, rr = solv->rules + i; i < solv->nrules; i++, rr++)
        {
          if (!rr->w1 || rr->w2)
            continue;
-         if (rr->p != v && rr->p != -v)
+         if (rr->p != vv && rr->p != -vv)
            continue;
-         printf(" - disabling rule #%d\n", i);
+         if (i >= solv->learntrules)
+           continue;
+         if (MAPTST(&solv->weakrulemap, i))
+           continue;
+         POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
          v = i;
          if (i < solv->systemrules)
            v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
@@ -619,16 +732,102 @@ makeruledecisions(Solver *solv)
       ri = solv->jobrules - 1;
       r = solv->rules + ri;
     }
+
+  /* phase 2: now do the weak assertions */
+  for (ri = 1, r = solv->rules + ri; ri < solv->learntrules; ri++, r++)
+    {
+      if (!r->w1 || r->w2)     /* disabled or no assertion */
+       continue;
+      if (!MAPTST(&solv->weakrulemap, ri))
+       continue;
+      v = r->p;
+      vv = v > 0 ? v : -v;
+      if (!solv->decisionmap[vv])
+       {
+         queue_push(&solv->decisionq, v);
+         queue_push(&solv->decisionq_why, r - solv->rules);
+         solv->decisionmap[vv] = v > 0 ? 1 : -1;
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
+           {
+             Solvable *s = solv->pool->solvables + vv;
+             if (v < 0)
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", solvable2str(solv->pool, s));
+             else
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", solvable2str(solv->pool, s));
+           }
+         continue;
+       }
+      if (v > 0 && solv->decisionmap[vv] > 0)
+       continue;
+      if (v < 0 && solv->decisionmap[vv] < 0)
+       continue;
+      POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
+      printrule(solv, SAT_DEBUG_UNSOLVABLE, r);
+      disablerule(solv, r);
+    }
+  
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions end; size decisionq: %d -----\n",solv->decisionq.count);
+}
+
+/*
+ * we have enabled or disabled some of our rules. We now reenable all
+ * of our learnt rules but the ones that were learnt from rules that
+ * are now disabled.
+ */
+static void
+enabledisablelearntrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Id why, *whyp;
+  int i;
+
+  POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
+  for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
+    {
+      whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
+      while ((why = *whyp++) != 0)
+       {
+#if 0
+         if (why < 0)
+           continue;           /* rpm assertion */
+#endif
+         assert(why < i);
+         if (!solv->rules[why].w1)
+           break;
+       }
+      /* why != 0: we found a disabled rule, disable the learnt rule */
+      if (why && r->w1)
+       {
+         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "disabling ");
+             printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
+           }
+          disablerule(solv, r);
+       }
+      else if (!why && !r->w1)
+       {
+         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "re-enabling ");
+             printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
+           }
+          enablerule(solv, r);
+       }
+    }
 }
 
 
 /* FIXME: bad code ahead, replace as soon as possible */
+/* FIXME: should probably look at SOLVER_INSTALL_SOLVABLE_ONE_OF */
+
 static void
 disableupdaterules(Solver *solv, Queue *job, int jobidx)
 {
   Pool *pool = solv->pool;
   int i, j;
-  Id how, what, p, *pp;
+  Id name, how, what, p, *pp;
   Solvable *s;
   Repo *installed;
   Rule *r;
@@ -640,7 +839,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
 
   if (jobidx != -1)
     {
-      how = job->elements[jobidx];
+      how = job->elements[jobidx] & ~SOLVER_WEAK;
       switch(how)
        {
        case SOLVER_INSTALL_SOLVABLE:
@@ -663,7 +862,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
       if (j == lastjob)
        continue;
       lastjob = j;
-      how = job->elements[j];
+      how = job->elements[j] & ~SOLVER_WEAK;
       what = job->elements[j + 1];
       switch(how)
        {
@@ -673,21 +872,28 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
            {
              if (pool->solvables[p].name != s->name)
                continue;
-             if (p >= installed->start && p < installed->start + installed->nsolvables)
+             if (pool->solvables[p].repo == installed)
                MAPSET(&solv->noupdate, p - installed->start);
            }
          break;
        case SOLVER_ERASE_SOLVABLE:
-         if (what >= installed->start && what < installed->start + installed->nsolvables)
+         s = pool->solvables + what;
+         if (s->repo == installed)
            MAPSET(&solv->noupdate, what - installed->start);
          break;
        case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
        case SOLVER_ERASE_SOLVABLE_PROVIDES:
+         name = (how == SOLVER_ERASE_SOLVABLE_NAME) ? what : 0;
+         while (ISRELDEP(name))
+           {
+             Reldep *rd = GETRELDEP(pool, name);
+             name = rd->name;
+           }
          FOR_PROVIDES(p, pp, what)
            {
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
+             if (name && pool->solvables[p].name != name)
                continue;
-             if (p >= installed->start && p < installed->start + installed->nsolvables)
+             if (pool->solvables[p].repo == installed)
                MAPSET(&solv->noupdate, p - installed->start);
            }
          break;
@@ -702,9 +908,9 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
 
   if (jobidx != -1)
     {
-      /* re just disabled job #jobidx. enable all update rules
+      /* we just disabled job #jobidx. enable all update rules
        * that aren't disabled by the remaining job rules */
-      how = job->elements[jobidx];
+      how = job->elements[jobidx] & ~SOLVER_WEAK;
       what = job->elements[jobidx + 1];
       switch(how)
        {
@@ -714,63 +920,61 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
            {
              if (pool->solvables[p].name != s->name)
                continue;
-             if (p < installed->start || p >= installed->start + installed->nsolvables)
+             if (pool->solvables[p].repo != installed)
                continue;
              if (MAPTST(&solv->noupdate, p - installed->start))
                continue;
              r = solv->rules + solv->systemrules + (p - installed->start);
              if (r->w1)
                continue;
-             if (r->d == 0 || r->w2 != r->p)
-               r->w1 = r->p;
-             else
-               r->w1 = solv->pool->whatprovidesdata[r->d];
-             if (pool->verbose)
+             enablerule(solv, r);
+             IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
                {
-                 printf("@@@ re-enabling ");
-                 printrule(solv, r);
+                 POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+                 printrule(solv, SAT_DEBUG_SOLUTIONS, r);
                }
            }
          break;
        case SOLVER_ERASE_SOLVABLE:
-         if (what < installed->start || what >= installed->start + installed->nsolvables)
+         s = pool->solvables + what;
+         if (s->repo != installed)
            break;
          if (MAPTST(&solv->noupdate, what - installed->start))
            break;
          r = solv->rules + solv->systemrules + (what - installed->start);
          if (r->w1)
            break;
-         if (r->d == 0 || r->w2 != r->p)
-           r->w1 = r->p;
-         else
-           r->w1 = solv->pool->whatprovidesdata[r->d];
-         if (pool->verbose)
+         enablerule(solv, r);
+         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
            {
-             printf("@@@ re-enabling ");
-             printrule(solv, r);
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             printrule(solv, SAT_DEBUG_SOLUTIONS, r);
            }
          break;
        case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
        case SOLVER_ERASE_SOLVABLE_PROVIDES:
+         name = (how == SOLVER_ERASE_SOLVABLE_NAME) ? what : 0;
+         while (ISRELDEP(name))
+           {
+             Reldep *rd = GETRELDEP(pool, name);
+             name = rd->name;
+           }
          FOR_PROVIDES(p, pp, what)
            {
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
+             if (name && pool->solvables[p].name != name)
                continue;
-             if (p < installed->start || p >= installed->start + installed->nsolvables)
+             if (pool->solvables[p].repo != installed)
                continue;
              if (MAPTST(&solv->noupdate, p - installed->start))
                continue;
              r = solv->rules + solv->systemrules + (p - installed->start);
              if (r->w1)
                continue;
-             if (r->d == 0 || r->w2 != r->p)
-               r->w1 = r->p;
-             else
-               r->w1 = solv->pool->whatprovidesdata[r->d];
-             if (pool->verbose)
+             enablerule(solv, r);
+             IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
                {
-                 printf("@@@ re-enabling ");
-                 printrule(solv, r);
+                 POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+                 printrule(solv, SAT_DEBUG_SOLUTIONS, r);
                }
            }
          break;
@@ -784,14 +988,56 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
     {
       r = solv->rules + solv->systemrules + i;
       if (r->w1 && MAPTST(&solv->noupdate, i))
-       r->w1 = 0;              /* was enabled, need to disable */
+        disablerule(solv, r);  /* was enabled, need to disable */
+    }
+}
+
+#if 0
+static void
+addpatchatomrequires(Solver *solv, Solvable *s, Id *dp, Queue *q, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id fre, *frep, p, *pp, ndp;
+  Solvable *ps;
+  Queue fq;
+  Id qbuf[64];
+  int i, used = 0;
+
+  queue_init_buffer(&fq, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  queue_push(&fq, -(s - pool->solvables));
+  for (; *dp; dp++)
+    queue_push(&fq, *dp);
+  ndp = pool_queuetowhatprovides(pool, &fq);
+  frep = s->repo->idarraydata + s->freshens;
+  while ((fre = *frep++) != 0)
+    {
+      FOR_PROVIDES(p, pp, fre)
+       {
+         ps = pool->solvables + p;
+         addrule(solv, -p, ndp);
+         used = 1;
+         if (!MAPTST(m, p))
+           queue_push(q, p);
+       }
+    }
+  if (used)
+    {
+      for (i = 1; i < fq.count; i++)
+       {
+         p = fq.elements[i];
+         if (!MAPTST(m, p))
+           queue_push(q, p);
+       }
     }
+  queue_free(&fq);
 }
+#endif
 
 
 /*
  * add (install) rules for solvable
- * 
+ * for unfulfilled requirements, conflicts, obsoletes,....
+ * add a negative assertion for solvables that are not installable
  */
 
 static void
@@ -803,6 +1049,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
   Id qbuf[64];
   int i;
   int dontfix;
+  int patchatom;
   Id req, *reqp;
   Id con, *conp;
   Id obs, *obsp;
@@ -812,6 +1059,8 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
   Id *dp;
   Id n;
 
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
+
   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
   queue_push(&q, s - pool->solvables); /* push solvable Id */
 
@@ -821,7 +1070,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
        * n: Id of solvable
        * s: Pointer to solvable
        */
-      
+
       n = queue_shift(&q);
       if (MAPTST(m, n))                       /* continue if already done */
        continue;
@@ -830,46 +1079,65 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
       s = pool->solvables + n;        /* s = Solvable in question */
 
       dontfix = 0;
-      if (installed
-         && !solv->fixsystem
-         && n >= installed->start             /* is it installed? */
-         && n < installed->start + installed->nsolvables)
+      if (installed                    /* Installed system available */
+         && !solv->fixsystem           /* NOT repair errors in rpm dependency graph */
+         && s->repo == installed)      /* solvable is installed? */
       {
        dontfix = 1;                   /* dont care about broken rpm deps */
       }
 
+      if (!dontfix && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
+       {
+         POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
+         addrule(solv, -n, 0);         /* uninstallable */
+       }
+
+      patchatom = 0;
+      if (s->freshens && !s->supplements)
+       {
+         const char *name = id2str(pool, s->name);
+         if (name[0] == 'a' && !strncmp(name, "atom:", 5))
+           patchatom = 1;
+       }
+
       /*-----------------------------------------
        * check requires of s
        */
-      
+
       if (s->requires)
        {
          reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
+         while ((req = *reqp++) != 0) /* go throw all requires */
            {
              if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
                continue;
 
-             dp = GET_PROVIDESP(req, p);       /* get providers of req */
+             dp = pool_whatprovides(pool, req);
 
              if (*dp == SYSTEMSOLVABLE)        /* always installed */
                continue;
 
+#if 0
+             if (patchatom)
+               {
+                 addpatchatomrequires(solv, s, dp, &q, m);
+                 continue;
+               }
+#endif
              if (dontfix)
                {
                  /* the strategy here is to not insist on dependencies
                    * that are already broken. so if we find one provider
                    * that was already installed, we know that the
                    * dependency was not broken before so we enforce it */
-                 for (i = 0; dp[i]; i++)       /* for all providers */
+                 for (i = 0; (p = dp[i]) != 0; i++)    /* for all providers */
                    {
-                     if (dp[i] >= installed->start && dp[i] < installed->start + installed->nsolvables)
+                     if (pool->solvables[p].repo == installed)
                        break;          /* provider was installed */
                    }
-                 if (!dp[i])           /* previously broken dependency */
+                 if (!p)               /* previously broken dependency */
                    {
-                     if (pool->verbose)
-                       printf("ignoring broken requires %s of installed package %s-%s.%s\n", dep2str(pool, req), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
                      continue;
                    }
                }
@@ -877,19 +1145,18 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
              if (!*dp)
                {
                  /* nothing provides req! */
-                 if (pool->verbose)
-                    printf("package %s-%s.%s [%ld] is not installable (%s)\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), (long int)(s - pool->solvables), dep2str(pool, req));
+                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
                  addrule(solv, -n, 0); /* mark requestor as uninstallable */
-                 if (solv->rc_output)
-                   printf(">!> !unflag %s-%s.%s[%s]\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), repo_name(s->repo));
                  continue;
                }
 
-#if 0
-             printf("addrule %s-%s.%s %s %d %d\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), dep2str(pool, req), -n, dp - pool->whatprovidesdata);
-             for (i = 0; dp[i]; i++)
-               printf("  %s-%s.%s\n", id2str(pool, pool->solvables[dp[i]].name), id2str(pool, pool->solvables[dp[i]].evr), id2str(pool, pool->solvables[dp[i]].arch));
-#endif
+             IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
+               {
+                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
+                 for (i = 0; dp[i]; i++)
+                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvable2str(pool, pool->solvables + dp[i]));
+               }
+
              /* add 'requires' dependency */
               /* rule: (-requestor|provider1|provider2|...|providerN) */
              addrule(solv, -n, dp - pool->whatprovidesdata);
@@ -905,11 +1172,14 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
 
        } /* if, requirements */
 
-      
+      /* that's all we check for src packages */
+      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+       continue;
+
       /*-----------------------------------------
        * check conflicts of s
        */
-      
+
       if (s->conflicts)
        {
          conp = s->repo->idarraydata + s->conflicts;
@@ -918,7 +1188,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
              FOR_PROVIDES(p, pp, con)
                {
                   /* dontfix: dont care about conflicts with already installed packs */
-                 if (dontfix && p >= installed->start && p < installed->start + installed->nsolvables)
+                 if (dontfix && pool->solvables[p].repo == installed)
                    continue;
                  /* rule: -n|-p: either solvable _or_ provider of conflict */
                  addrule(solv, -n, -p);
@@ -929,7 +1199,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
       /*-----------------------------------------
        * check obsoletes if not installed
        */
-      if (!installed || n < installed->start || n >= (installed->start + installed->nsolvables))
+      if (!installed || pool->solvables[n].repo != installed)
        {                              /* not installed */
          if (s->obsoletes)
            {
@@ -972,6 +1242,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
        }
     }
   queue_free(&q);
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
 }
 
 static void
@@ -982,7 +1253,7 @@ addrpmrulesforweak(Solver *solv, Map *m)
   Id sup, *supp;
   int i, n;
 
-  if (pool->verbose) printf("addrpmrulesforweak... (%d)\n", solv->nrules);
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
   for (i = n = 1; n < pool->nsolvables; i++, n++)
     {
       if (i == pool->nsolvables)
@@ -1019,7 +1290,7 @@ addrpmrulesforweak(Solver *solv, Map *m)
       addrpmrulesforsolvable(solv, s, m);
       n = 0;
     }
-  if (pool->verbose) printf("done. (%d)\n", solv->nrules);
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
 }
 
 static void
@@ -1030,20 +1301,24 @@ addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allowall)
   Queue qs;
   Id qsbuf[64];
 
-  if (!MAPTST(m, s - pool->solvables)) /* add rule for s if not already done */
-    addrpmrulesforsolvable(solv, s, m); 
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
+
   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
   policy_findupdatepackages(solv, s, &qs, allowall);
+  if (!MAPTST(m, s - pool->solvables)) /* add rule for s if not already done */
+    addrpmrulesforsolvable(solv, s, m);
   for (i = 0; i < qs.count; i++)
     if (!MAPTST(m, qs.elements[i]))
       addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
   queue_free(&qs);
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
 }
 
 /*
  * add rule for update
  *   (A|A1|A2|A3...)  An = update candidates for A
- * 
+ *
  * s = (installed) solvable
  */
 
@@ -1056,6 +1331,8 @@ addupdaterule(Solver *solv, Solvable *s, int allowall)
   Queue qs;
   Id qsbuf[64];
 
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
+
   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
   policy_findupdatepackages(solv, s, &qs, allowall);
   if (qs.count == 0)                  /* no updaters found */
@@ -1064,16 +1341,32 @@ addupdaterule(Solver *solv, Solvable *s, int allowall)
     d = pool_queuetowhatprovides(pool, &qs);   /* intern computed queue */
   queue_free(&qs);
   addrule(solv, s - pool->solvables, d);       /* allow update of s */
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
 }
 
 
 /*-----------------------------------------------------------------*/
 /* watches */
 
+/*
+ * print watches
+ *
+ */
+
+static void
+printWatches(Solver *solv, int type)
+{
+  Pool *pool = solv->pool;
+  int counter;
+
+  POOL_DEBUG(type, "Watches: \n");
+  for (counter = -(pool->nsolvables - 1); counter < pool->nsolvables; counter++)
+    POOL_DEBUG(type, "    solvable [%d] -- rule [%d]\n", counter, solv->watches[counter + pool->nsolvables]);
+}
 
 /*
  * makewatches
- * 
+ *
  * initial setup for all watches
  */
 
@@ -1084,11 +1377,11 @@ makewatches(Solver *solv)
   int i;
   int nsolvables = solv->pool->nsolvables;
 
-  xfree(solv->watches);
+  sat_free(solv->watches);
                                       /* lower half for removals, upper half for installs */
-  solv->watches = (Id *)xcalloc(2 * nsolvables, sizeof(Id));
+  solv->watches = sat_calloc(2 * nsolvables, sizeof(Id));
 #if 1
-  /* do it reverse so rpm rules get triggered first */
+  /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
 #else
   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
@@ -1129,11 +1422,14 @@ addwatches(Solver *solv, Rule *r)
 /* rule propagation */
 
 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
+#define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
 
 /*
  * propagate
- * 
+ *
  * propagate decision to all rules
+ * return : 0 = everything is OK
+ *          watched rule = there is a conflict
  */
 
 static Rule *
@@ -1147,29 +1443,38 @@ propagate(Solver *solv, int level)
   Id *decisionmap = solv->decisionmap;
   Id *watches = solv->watches + pool->nsolvables;
 
+  POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate -----\n");
+
   while (solv->propagate_index < solv->decisionq.count)
     {
       /* negate because our watches trigger if literal goes FALSE */
       pkg = -solv->decisionq.elements[solv->propagate_index++];
-#if 0
-  printf("popagate for decision %d level %d\n", -pkg, level);
-  printruleelement(solv, 0, -pkg);
-#endif
+      IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
+        {
+         POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+         printruleelement(solv, SAT_DEBUG_PROPAGATE, 0, -pkg);
+         if (0)
+             printWatches(solv, SAT_DEBUG_SCHUBI);
+        }
+
       for (rp = watches + pkg; *rp; rp = nrp)
        {
          r = solv->rules + *rp;
-#if 0
-  printf("  watch triggered ");
-  printrule(solv, r);
-#endif
+
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
+           {
+             POOL_DEBUG(SAT_DEBUG_PROPAGATE,"  watch triggered ");
+             printrule(solv, SAT_DEBUG_PROPAGATE, r);
+           }
+
          if (pkg == r->w1)
            {
-             ow = r->w2;
+             ow = r->w2; /* regard the second watchpoint to come to a solution */
              nrp = &r->n1;
            }
          else
            {
-             ow = r->w1;
+             ow = r->w1; /* regard the first watchpoint to come to a solution */
              nrp = &r->n2;
            }
          /* if clause is TRUE, nothing to do */
@@ -1179,6 +1484,8 @@ propagate(Solver *solv, int level)
           if (r->d)
            {
              /* not a binary clause, check if we need to move our watch */
+             /* search for a literal that is not ow and not false */
+             /* (true is also ok, in that case the rule is fulfilled) */
              if (r->p && r->p != ow && !DECISIONMAP_TRUE(-r->p))
                p = r->p;
              else
@@ -1188,12 +1495,13 @@ propagate(Solver *solv, int level)
              if (p)
                {
                  /* p is free to watch, move watch to p */
-#if 0
-                 if (p > 0)
-                   printf("    -> move w%d to %s-%s.%s\n", (pkg == r->w1 ? 1 : 2), id2str(pool, pool->solvables[p].name), id2str(pool, pool->solvables[p].evr), id2str(pool, pool->solvables[p].arch));
-                 else
-                   printf("    -> move w%d to !%s-%s.%s\n", (pkg == r->w1 ? 1 : 2), id2str(pool, pool->solvables[-p].name), id2str(pool, pool->solvables[-p].evr), id2str(pool, pool->solvables[-p].arch));
-#endif
+                 IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
+                   {
+                     if (p > 0)
+                       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
+                     else
+                       POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
+                   }
                  *rp = *nrp;
                  nrp = rp;
                  if (pkg == r->w1)
@@ -1213,10 +1521,10 @@ propagate(Solver *solv, int level)
           /* unit clause found, set other watch to TRUE */
          if (DECISIONMAP_TRUE(-ow))
            return r;           /* eek, a conflict! */
-         if (pool->verbose > 2)
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
            {
-             printf("unit ");
-             printrule(solv, r);
+             POOL_DEBUG(SAT_DEBUG_PROPAGATE, "   unit ");
+             printrule(solv, SAT_DEBUG_PROPAGATE, r);
            }
          if (ow > 0)
             decisionmap[ow] = level;
@@ -1224,17 +1532,18 @@ propagate(Solver *solv, int level)
             decisionmap[-ow] = -level;
          queue_push(&solv->decisionq, ow);
          queue_push(&solv->decisionq_why, r - solv->rules);
-#if 0
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
            {
              Solvable *s = pool->solvables + (ow > 0 ? ow : -ow);
              if (ow > 0)
-               printf("  -> decided to install %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvable2str(pool, s));
              else
-               printf("  -> decided to conflict %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvable2str(pool, s));
            }
-#endif
        }
     }
+  POOL_DEBUG(SAT_DEBUG_PROPAGATE, "----- propagate end-----\n");
+
   return 0;    /* all is well */
 }
 
@@ -1248,28 +1557,30 @@ propagate(Solver *solv, int level)
  */
 
 static int
-analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
+analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
 {
   Pool *pool = solv->pool;
   Queue r;
   int rlevel = 1;
   Map seen;            /* global? */
-  Id v, vv, *dp;
+  Id v, vv, *dp, why;
   int l, i, idx;
-  int num = 0;
+  int num = 0, l1num = 0;
   int learnt_why = solv->learnt_pool.count;
   Id *decisionmap = solv->decisionmap;
+
   queue_init(&r);
 
-  if (pool->verbose > 1) printf("ANALYZE at %d ----------------------\n", level);
+  POOL_DEBUG(SAT_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
   map_init(&seen, pool->nsolvables);
   idx = solv->decisionq.count;
   for (;;)
     {
-      if (pool->verbose > 1) printrule(solv, c);
+      IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
+       printruleclass(solv, SAT_DEBUG_ANALYZE, c);
       queue_push(&solv->learnt_pool, c - solv->rules);
       dp = c->d ? pool->whatprovidesdata + c->d : 0;
+      /* go through all literals of the rule */
       for (i = -1; ; i++)
        {
          if (i == -1)
@@ -1280,8 +1591,9 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
            v = *dp++;
          if (v == 0)
            break;
+
          if (DECISIONMAP_TRUE(v))      /* the one true literal */
-             continue;
+           continue;
          vv = v > 0 ? v : -v;
          if (MAPTST(&seen, vv))
            continue;
@@ -1290,16 +1602,10 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
            l = -l;
          if (l == 1)
            {
-#if 0
-             int j;
-             for (j = 0; j < solv->decisionq.count; j++)
-               if (solv->decisionq.elements[j] == v)
-                 break;
-             if (j == solv->decisionq.count)
-               abort();
-             queue_push(&rulq, -(j + 1));
-#endif
-             continue;                 /* initial setting */
+             /* a level 1 literal, mark it for later */
+             MAPSET(&seen, vv);        /* mark for scanning in level 1 phase */
+             l1num++;
+             continue;
            }
          MAPSET(&seen, vv);
          if (l == level)
@@ -1307,19 +1613,11 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
          else
            {
              queue_push(&r, v);
-#if 0
-  printf("PUSH %d ", v);
-  printruleelement(solv, 0, v);
-#endif
              if (l > rlevel)
                rlevel = l;
            }
        }
-#if 0
-      printf("num = %d\n", num);
-#endif
-      if (num <= 0)
-       abort();
+      assert(num > 0);
       for (;;)
        {
          v = solv->decisionq.elements[--idx];
@@ -1332,34 +1630,74 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
       if (--num == 0)
        break;
     }
-  *pr = -v;
+  *pr = -v;    /* so that v doesn't get lost */
+
+  /* add involved level 1 rules */
+  if (l1num)
+    {
+      POOL_DEBUG(SAT_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
+      idx++;
+      while (idx)
+       {
+         v = solv->decisionq.elements[--idx];
+         vv = v > 0 ? v : -v;
+         if (!MAPTST(&seen, vv))
+           continue;
+         why = solv->decisionq_why.elements[idx];
+         if (!why)
+           {
+             queue_push(&solv->learnt_pool, -vv);
+             IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
+               {
+                 POOL_DEBUG(SAT_DEBUG_ANALYZE, "RPM ASSERT Rule:\n");
+                 printruleelement(solv, SAT_DEBUG_ANALYZE, 0, v);
+               }
+             continue;
+           }
+         queue_push(&solv->learnt_pool, why);
+         c = solv->rules + why;
+         dp = c->d ? pool->whatprovidesdata + c->d : 0;
+         IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
+           printruleclass(solv, SAT_DEBUG_ANALYZE, c);
+         for (i = -1; ; i++)
+           {
+             if (i == -1)
+               v = c->p;
+             else if (c->d == 0)
+               v = i ? 0 : c->w2;
+             else
+               v = *dp++;
+             if (v == 0)
+               break;
+             if (DECISIONMAP_TRUE(v))  /* the one true literal */
+               continue;
+             vv = v > 0 ? v : -v;
+             l = solv->decisionmap[vv];
+             if (l != 1 && l != -1)
+               continue;
+             MAPSET(&seen, vv);
+           }
+       }
+    }
+  map_free(&seen);
+
   if (r.count == 0)
     *dr = 0;
   else if (r.count == 1 && r.elements[0] < 0)
     *dr = r.elements[0];
   else
     *dr = pool_queuetowhatprovides(pool, &r);
-  if (pool->verbose > 1)
+  IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
     {
-      printf("learned rule for level %d (am %d)\n", rlevel, level);
-      printruleelement(solv, 0, -v);
+      POOL_DEBUG(SAT_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
+      printruleelement(solv, SAT_DEBUG_ANALYZE, 0, *pr);
       for (i = 0; i < r.count; i++)
-        {
-          v = r.elements[i];
-          printruleelement(solv, 0, v);
-        }
+        printruleelement(solv, SAT_DEBUG_ANALYZE, 0, r.elements[i]);
     }
-  map_free(&seen);
+  /* push end marker on learnt reasons stack */
   queue_push(&solv->learnt_pool, 0);
-#if 0
-  for (i = learnt_why; solv->learnt_pool.elements[i]; i++)
-    {
-      printf("learnt_why ");
-      printrule(solv, solv->rules + solv->learnt_pool.elements[i]);
-    }
-#endif
-  if (why)
-    *why = learnt_why;
+  if (whyp)
+    *whyp = learnt_why;
   return rlevel;
 }
 
@@ -1373,44 +1711,32 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *why)
 static void
 reset_solver(Solver *solv)
 {
+  Pool *pool = solv->pool;
   int i;
   Id v;
 
-  /* delete all learnt rules */
-  solv->nrules = solv->learntrules;
-  queue_empty(&solv->learnt_why);
-  queue_empty(&solv->learnt_pool);
-
-  /* redo all direct rpm rule decisions */
-  /* we break at the first decision with a why attached, this is
-   * either a job/system rule assertion or a propagated decision */
-  for (i = 0; i < solv->decisionq.count; i++)
+  /* rewind decisions to direct rpm rule assertions */
+  for (i = solv->decisionq.count - 1; i >= solv->directdecisions; i--)
     {
       v = solv->decisionq.elements[i];
       solv->decisionmap[v > 0 ? v : -v] = 0;
     }
-  for (i = 0; i < solv->decisionq_why.count; i++)
-    if (solv->decisionq_why.elements[i])
-      break;
-    else
-      {
-        v = solv->decisionq.elements[i];
-        solv->decisionmap[v > 0 ? v : -v] = v > 0 ? 1 : -1;
-      }
 
-  if (solv->pool->verbose > 1)
-    printf("decisions done reduced from %d to %d\n", solv->decisionq.count, i);
+  POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions done reduced from %d to %d\n", solv->decisionq.count, solv->directdecisions);
 
-  solv->decisionq_why.count = i;
-  solv->decisionq.count = i;
+  solv->decisionq_why.count = solv->directdecisions;
+  solv->decisionq.count = solv->directdecisions;
   solv->recommends_index = -1;
   solv->propagate_index = 0;
 
+  /* adapt learnt rule status to new set of enabled/disabled rules */
+  enabledisablelearntrules(solv);
+
   /* redo all job/system decisions */
   makeruledecisions(solv);
-  if (solv->pool->verbose > 1)
-    printf("decisions after adding job and system rules: %d\n", solv->decisionq.count);
-  /* recreate watches */
+  POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
+
+  /* recreate watch chains */
   makewatches(solv);
 }
 
@@ -1420,28 +1746,24 @@ reset_solver(Solver *solv)
  */
 
 static void
-analyze_unsolvable_rule(Solver *solv, Rule *r)
+analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp)
 {
+  Pool *pool = solv->pool;
   int i;
   Id why = r - solv->rules;
-  if (solv->pool->verbose > 1)
-    {
-      if (why >= solv->jobrules && why < solv->systemrules)
-       printf("JOB ");
-      if (why >= solv->systemrules && why < solv->weakrules)
-       printf("SYSTEM %d ", why - solv->systemrules);
-      if (why >= solv->weakrules && why < solv->learntrules)
-       printf("WEAK ");
-      if (solv->learntrules && why >= solv->learntrules)
-       printf("LEARNED ");
-      printrule(solv, r);
-    }
+
+  IF_POOLDEBUG (SAT_DEBUG_UNSOLVABLE)
+    printruleclass(solv, SAT_DEBUG_UNSOLVABLE, r);
   if (solv->learntrules && why >= solv->learntrules)
     {
       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
-       analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i]);
+       if (solv->learnt_pool.elements[i] > 0)
+         analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp);
       return;
     }
+  if (MAPTST(&solv->weakrulemap, why))
+    if (!*lastweakp || why > *lastweakp)
+      *lastweakp = why;
   /* do not add rpm rules to problem */
   if (why < solv->jobrules)
     return;
@@ -1452,7 +1774,7 @@ analyze_unsolvable_rule(Solver *solv, Rule *r)
   if (solv->problems.count)
     {
       for (i = solv->problems.count - 1; i >= 0; i--)
-       if (solv->problems.elements[i] == 0)
+       if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
          break;
        else if (solv->problems.elements[i] == why)
          return;
@@ -1469,21 +1791,32 @@ analyze_unsolvable_rule(Solver *solv, Rule *r)
  */
 
 static int
-analyze_unsolvable(Solver *solv, Rule *r, int disablerules)
+analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
 {
   Pool *pool = solv->pool;
-  Map seen;            /* global? */
+  Rule *r;
+  Map seen;            /* global to speed things up? */
   Id v, vv, *dp, why;
   int l, i, idx;
   Id *decisionmap = solv->decisionmap;
   int oldproblemcount;
-  int lastweak;
+  int oldlearntpoolcount;
+  Id lastweak;
 
-  if (pool->verbose > 1)
-    printf("ANALYZE UNSOLVABLE ----------------------\n");
+  POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
   oldproblemcount = solv->problems.count;
+  oldlearntpoolcount = solv->learnt_pool.count;
+
+  /* make room for proof index */
+  /* must update it later, as analyze_unsolvable_rule would confuse
+   * it with a rule index if we put the real value in already */
+  queue_push(&solv->problems, 0);
+
+  r = cr;
   map_init(&seen, pool->nsolvables);
-  analyze_unsolvable_rule(solv, r);
+  queue_push(&solv->learnt_pool, r - solv->rules);
+  lastweak = 0;
+  analyze_unsolvable_rule(solv, r, &lastweak);
   dp = r->d ? pool->whatprovidesdata + r->d : 0;
   for (i = -1; ; i++)
     {
@@ -1511,16 +1844,9 @@ analyze_unsolvable(Solver *solv, Rule *r, int disablerules)
       if (!MAPTST(&seen, vv))
        continue;
       why = solv->decisionq_why.elements[idx];
-      if (!why)
-       {
-#if 0
-         printf("RPM ");
-         printruleelement(solv, 0, v);
-#endif
-         continue;
-       }
+      queue_push(&solv->learnt_pool, why);
       r = solv->rules + why;
-      analyze_unsolvable_rule(solv, r);
+      analyze_unsolvable_rule(solv, r, &lastweak);
       dp = r->d ? pool->whatprovidesdata + r->d : 0;
       for (i = -1; ; i++)
        {
@@ -1544,38 +1870,31 @@ analyze_unsolvable(Solver *solv, Rule *r, int disablerules)
   map_free(&seen);
   queue_push(&solv->problems, 0);      /* mark end of this problem */
 
-  lastweak = 0;
-  if (solv->weakrules != solv->learntrules)
-    {
-      for (i = oldproblemcount; i < solv->problems.count - 1; i++)
-       {
-         why = solv->problems.elements[i];
-         if (why < solv->weakrules || why >= solv->learntrules)
-           continue;
-         if (!lastweak || lastweak < why)
-           lastweak = why;
-       }
-    }
   if (lastweak)
     {
       /* disable last weak rule */
       solv->problems.count = oldproblemcount;
+      solv->learnt_pool.count = oldlearntpoolcount;
       r = solv->rules + lastweak;
-      printf("disabling weak ");
-      printrule(solv, r);
-      r->w1 = 0;
+      POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling ");
+      printruleclass(solv, SAT_DEBUG_UNSOLVABLE, r);
+      disablerule(solv, r);
       reset_solver(solv);
       return 1;
     }
-  else if (disablerules)
+
+  /* finish proof */
+  queue_push(&solv->learnt_pool, 0);
+  solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
+
+  if (disablerules)
     {
-      for (i = oldproblemcount; i < solv->problems.count - 1; i++)
+      for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
         disableproblem(solv, solv->problems.elements[i]);
       reset_solver(solv);
       return 1;
     }
-  if (pool->verbose)
-    printf("UNSOLVABLE\n");
+  POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
   return 0;
 }
 
@@ -1591,6 +1910,7 @@ analyze_unsolvable(Solver *solv, Rule *r, int disablerules)
 static void
 revert(Solver *solv, int level)
 {
+  Pool *pool = solv->pool;
   Id v, vv;
   while (solv->decisionq.count)
     {
@@ -1598,9 +1918,9 @@ revert(Solver *solv, int level)
       vv = v > 0 ? v : -v;
       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
         break;
-#if 0
-      printf("reverting decision %d at %d\n", v, solv->decisionmap[vv]);
-#endif
+      POOL_DEBUG(SAT_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
+      if (v > 0 && solv->recommendations.count && v == solv->recommendations.elements[solv->recommendations.count - 1])
+       solv->recommendations.count--;
       solv->decisionmap[vv] = 0;
       solv->decisionq.count--;
       solv->decisionq_why.count--;
@@ -1646,16 +1966,20 @@ watch2onhighest(Solver *solv, Rule *r)
 /*
  * setpropagatelearn
  *
- * add free decision to decision q, increase level
+ * add free decision to decisionq, increase level and
  * propagate decision, return if no conflict.
  * in conflict case, analyze conflict rule, add resulting
  * rule to learnt rule set, make decision from learnt
  * rule (always unit) and re-propagate.
+ *
+ * returns the new solver level or 0 if unsolvable
+ *
  */
 
 static int
 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
 {
+  Pool *pool = solv->pool;
   Rule *r;
   Id p, d;
   int l, why;
@@ -1677,21 +2001,15 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
        break;
       if (level == 1)
        return analyze_unsolvable(solv, r, disablerules);
-      printf("conflict with rule #%d\n", (int)(r - solv->rules));
+      POOL_DEBUG(SAT_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
       l = analyze(solv, level, r, &p, &d, &why);       /* learnt rule in p and d */
-      if (l >= level || l <= 0)
-       abort();
-      printf("reverting decisions (level %d -> %d)\n", level, l);
+      assert(l > 0 && l < level);
+      POOL_DEBUG(SAT_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
       level = l;
       revert(solv, level);
       r = addrule(solv, p, d);       /* p requires d */
-      if (!r)
-       abort();
-      if (solv->learnt_why.count != (r - solv->rules) - solv->learntrules)
-       {
-         printf("%d %d\n", solv->learnt_why.count, (int)(r - solv->rules) - solv->learntrules);
-         abort();
-       }
+      assert(r);
+      assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
       queue_push(&solv->learnt_why, why);
       if (d)
        {
@@ -1702,12 +2020,12 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
       queue_push(&solv->decisionq, p);
       queue_push(&solv->decisionq_why, r - solv->rules);
-      if (solv->pool->verbose > 1)
+      IF_POOLDEBUG (SAT_DEBUG_ANALYZE)
        {
-         printf("decision: ");
-         printruleelement(solv, 0, p);
-         printf("new rule: ");
-         printrule(solv, r);
+         POOL_DEBUG(SAT_DEBUG_ANALYZE, "decision: ");
+         printruleelement(solv, SAT_DEBUG_ANALYZE, 0, p);
+         POOL_DEBUG(SAT_DEBUG_ANALYZE, "new rule: ");
+         printrule(solv, SAT_DEBUG_ANALYZE, r);
        }
     }
   return level;
@@ -1717,6 +2035,9 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules)
 /*
  * install best package from the queue. We add an extra package, inst, if
  * provided. See comment in weak install section.
+ *
+ * returns the new solver level or 0 if unsolvable
+ *
  */
 static int
 selectandinstall(Solver *solv, int level, Queue *dq, Id inst, int disablerules)
@@ -1744,10 +2065,9 @@ selectandinstall(Solver *solv, int level, Queue *dq, Id inst, int disablerules)
        }
     }
   p = dq->elements[i];
-#if 0
-  Solvable *s = pool->solvables + p;
-  printf("installing %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-#endif
+
+  POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
+
   return setpropagatelearn(solv, level, p, disablerules);
 }
 
@@ -1772,7 +2092,7 @@ Solver *
 solver_create(Pool *pool, Repo *installed)
 {
   Solver *solv;
-  solv = (Solver *)xcalloc(1, sizeof(Solver));
+  solv = (Solver *)sat_calloc(1, sizeof(Solver));
   solv->pool = pool;
   solv->installed = installed;
 
@@ -1781,19 +2101,22 @@ solver_create(Pool *pool, Repo *installed)
   queue_init(&solv->decisionq_why);
   queue_init(&solv->problems);
   queue_init(&solv->suggestions);
+  queue_init(&solv->recommendations);
   queue_init(&solv->learnt_why);
   queue_init(&solv->learnt_pool);
   queue_init(&solv->branches);
+  queue_init(&solv->covenantq);
+  queue_init(&solv->weakruleq);
 
   map_init(&solv->recommendsmap, pool->nsolvables);
   map_init(&solv->suggestsmap, pool->nsolvables);
-  map_init(&solv->noupdate, installed ? installed->nsolvables : 0);
+  map_init(&solv->noupdate, installed ? installed->end - installed->start : 0);
   solv->recommends_index = 0;
 
-  solv->decisionmap = (Id *)xcalloc(pool->nsolvables, sizeof(Id));
-  solv->rules = (Rule *)xmalloc((solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule));
-  memset(solv->rules, 0, sizeof(Rule));
+  solv->decisionmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
   solv->nrules = 1;
+  solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
+  memset(solv->rules, 0, sizeof(Rule));
 
   return solv;
 }
@@ -1813,18 +2136,23 @@ solver_free(Solver *solv)
   queue_free(&solv->learnt_pool);
   queue_free(&solv->problems);
   queue_free(&solv->suggestions);
+  queue_free(&solv->recommendations);
   queue_free(&solv->branches);
+  queue_free(&solv->covenantq);
+  queue_free(&solv->weakruleq);
 
   map_free(&solv->recommendsmap);
   map_free(&solv->suggestsmap);
   map_free(&solv->noupdate);
-  xfree(solv->decisionmap);
-  xfree(solv->rules);
-  xfree(solv->watches);
-  xfree(solv->weaksystemrules);
-  xfree(solv->obsoletes);
-  xfree(solv->obsoletes_data);
-  xfree(solv);
+  map_free(&solv->weakrulemap);
+
+  sat_free(solv->decisionmap);
+  sat_free(solv->rules);
+  sat_free(solv->watches);
+  sat_free(solv->weaksystemrules);
+  sat_free(solv->obsoletes);
+  sat_free(solv->obsoletes_data);
+  sat_free(solv);
 }
 
 
@@ -1832,7 +2160,7 @@ solver_free(Solver *solv)
 
 /*
  * run_solver
- * 
+ *
  * all rules have been set up, now actually run the solver
  *
  */
@@ -1849,34 +2177,45 @@ run_solver(Solver *solv, int disablerules, int doweak)
   Pool *pool = solv->pool;
   Id p, *dp;
 
-#if 0
-  printf("number of rules: %d\n", solv->nrules);
-  for (i = 0; i < solv->nrules; i++)
-    printrule(solv, solv->rules + i);
-#endif
+  IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
+    {
+      POOL_DEBUG (SAT_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
+      for (i = 1; i < solv->nrules; i++)
+       printruleclass(solv, SAT_DEBUG_RULE_CREATION, solv->rules + i);
+    }
 
-  /* all new rules are learnt after this point */
-  solv->learntrules = solv->nrules;
-  /* crate watches lists */
-  makewatches(solv);
+  POOL_DEBUG(SAT_DEBUG_STATS, "initial decisions: %d\n", solv->decisionq.count);
 
-  if (pool->verbose) printf("initial decisions: %d\n", solv->decisionq.count);
+  IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
+    printdecisions(solv);
 
   /* start SAT algorithm */
   level = 1;
   systemlevel = level + 1;
-  if (pool->verbose) printf("solving...\n");
+  POOL_DEBUG(SAT_DEBUG_STATS, "solving...\n");
 
   queue_init(&dq);
+
+  /*
+   * here's the main loop:
+   * 1) propagate new decisions (only needed for level 1)
+   * 2) try to keep installed packages
+   * 3) fulfill all unresolved rules
+   * 4) install recommended packages
+   * 5) minimalize solution if we had choices
+   * if we encounter a problem, we rewind to a safe level and restart
+   * with step 1
+   */
+   
   for (;;)
     {
       /*
        * propagate
        */
-      
+
       if (level == 1)
        {
-         if (pool->verbose) printf("propagating (%d %d)...\n", solv->propagate_index, solv->decisionq.count);
+         POOL_DEBUG(SAT_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
          if ((r = propagate(solv, level)) != 0)
            {
              if (analyze_unsolvable(solv, r, disablerules))
@@ -1889,25 +2228,21 @@ run_solver(Solver *solv, int disablerules, int doweak)
       /*
        * installed packages
        */
-      
-      if (level < systemlevel && solv->installed->nsolvables)
+
+      if (level < systemlevel && solv->installed && solv->installed->nsolvables)
        {
          if (!solv->updatesystem)
            {
              /* try to keep as many packages as possible */
-             if (pool->verbose) printf("installing system packages\n");
-             for (i = solv->installed->start, n = 0; ; i++, n++)
+             POOL_DEBUG(SAT_DEBUG_STATS, "installing system packages\n");
+             for (i = solv->installed->start; i < solv->installed->end; i++)
                {
-                 if (n == solv->installed->nsolvables)
-                   break;
-                 if (i == solv->installed->start + solv->installed->nsolvables)
-                   i = solv->installed->start;
                  s = pool->solvables + i;
+                 if (s->repo != solv->installed)
+                   continue;
                  if (solv->decisionmap[i] != 0)
                    continue;
-#if 0
-                 printf("keeping %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-#endif
+                 POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
                  olevel = level;
                  level = setpropagatelearn(solv, level, i, disablerules);
                  if (level == 0)
@@ -1916,16 +2251,19 @@ run_solver(Solver *solv, int disablerules, int doweak)
                      return;
                    }
                  if (level <= olevel)
-                   n = 0;
+                   break;
                }
+             if (i < solv->installed->end)
+               continue;
            }
          if (solv->weaksystemrules)
            {
-             if (pool->verbose) printf("installing weak system packages\n");
-             for (i = solv->installed->start, n = 0; ; i++, n++)
+             POOL_DEBUG(SAT_DEBUG_STATS, "installing weak system packages\n");
+             for (i = solv->installed->start; i < solv->installed->end; i++)
                {
-                 if (n == solv->installed->nsolvables)
-                   break;
+                 s = pool->solvables + i;
+                 if (s->repo != solv->installed)
+                   continue;
                  if (solv->decisionmap[i] > 0 || (solv->decisionmap[i] < 0 && solv->weaksystemrules[i - solv->installed->start] == 0))
                    continue;
                  /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
@@ -1958,12 +2296,9 @@ run_solver(Solver *solv, int disablerules, int doweak)
                      return;
                    }
                  if (level <= olevel)
-                   {
-                     n = 0;
-                     break;
-                   }
+                   break;
                }
-             if (n != solv->installed->nsolvables)
+             if (i < solv->installed->end)
                continue;
            }
          systemlevel = level;
@@ -1972,8 +2307,8 @@ run_solver(Solver *solv, int disablerules, int doweak)
       /*
        * decide
        */
-      
-      if (pool->verbose) printf("deciding unresolved rules\n");
+
+      POOL_DEBUG(SAT_DEBUG_STATS, "deciding unresolved rules\n");
       for (i = 1, n = 1; ; i++, n++)
        {
          if (n == solv->nrules)
@@ -1981,7 +2316,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
          if (i == solv->nrules)
            i = 1;
          r = solv->rules + i;
-         if (!r->w1)
+         if (!r->w1)   /* ignore disabled rules */
            continue;
          queue_empty(&dq);
          if (r->d == 0)
@@ -2034,15 +2369,14 @@ run_solver(Solver *solv, int disablerules, int doweak)
              if (p)
                continue;
            }
-         if (dq.count < 2)
+         IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
            {
-             /* cannot happen as this means that
-               * the rule is unit */
-             printrule(solv, r);
-             abort();
+             POOL_DEBUG(SAT_DEBUG_PROPAGATE, "unfulfilled ");
+             printruleclass(solv, SAT_DEBUG_PROPAGATE, r);
            }
-         if (pool->verbose > 2)
-           printrule(solv, r);
+         /* dq.count < 2 cannot happen as this means that
+          * the rule is unit */
+         assert(dq.count > 1);
 
          olevel = level;
          level = selectandinstall(solv, level, &dq, 0, disablerules);
@@ -2058,12 +2392,12 @@ run_solver(Solver *solv, int disablerules, int doweak)
 
       if (n != solv->nrules)   /* continue if level < systemlevel */
        continue;
-      
-      if (doweak && !solv->problems.count)
+
+      if (doweak)
        {
          int qcount;
 
-         if (pool->verbose) printf("installing recommended packages\n");
+         POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended packages\n");
          queue_empty(&dq);
          for (i = 1; i < pool->nsolvables; i++)
            {
@@ -2112,10 +2446,8 @@ run_solver(Solver *solv, int disablerules, int doweak)
              if (dq.count > 1)
                policy_filter_unwanted(solv, &dq, 0, POLICY_MODE_RECOMMEND);
              p = dq.elements[0];
-             s = pool->solvables + p;
-#if 1
-             printf("installing recommended %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-#endif
+             POOL_DEBUG(SAT_DEBUG_STATS, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+             queue_push(&solv->recommendations, p);
              level = setpropagatelearn(solv, level, p, 0);
              continue;
            }
@@ -2132,10 +2464,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                if (solv->branches.elements[i - 1] < 0)
                  break;
              p = solv->branches.elements[i];
-#if 1
-             s = pool->solvables + p;
-             printf("branching with %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-#endif
+             POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
              queue_empty(&dq);
              for (j = i + 1; j < solv->branches.count; j++)
                queue_push(&dq, solv->branches.elements[j]);
@@ -2179,10 +2508,8 @@ run_solver(Solver *solv, int disablerules, int doweak)
              /* kill old solvable so that we do not loop */
              p = solv->branches.elements[lasti];
              solv->branches.elements[lasti] = 0;
-             s = pool->solvables + p;
-#if 1
-             printf("minimizing %d -> %d with %s-%s.%s\n", solv->decisionmap[p], l, id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-#endif
+             POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], l, solvable2str(pool, pool->solvables + p));
+
              level = lastl;
              revert(solv, level);
              olevel = level;
@@ -2197,17 +2524,18 @@ run_solver(Solver *solv, int disablerules, int doweak)
        }
       break;
     }
+  POOL_DEBUG(SAT_DEBUG_STATS, "done solving.\n\n");
   queue_free(&dq);
 }
 
-  
+
 /*
  * refine_suggestion
  * at this point, all rules that led to conflicts are disabled.
  * we re-enable all rules of a problem set but rule "sug", then
  * continue to disable more rules until there as again a solution.
  */
-  
+
 /* FIXME: think about conflicting assertions */
 
 static void
@@ -2220,13 +2548,13 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
   Queue disabled;
   int disabledcnt;
 
-  if (pool->verbose)
+  IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
     {
-      printf("refine_suggestion start\n");
+      POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
       for (i = 0; problem[i]; i++)
        {
          if (problem[i] == sug)
-           printf("=> ");
+           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
          printproblem(solv, problem[i]);
        }
     }
@@ -2234,7 +2562,7 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
   queue_empty(refined);
   queue_push(refined, sug);
 
-  /* re-enable all problem rules with the exception of "sug" */
+  /* re-enable all problem rules with the exception of "sug"(gests) */
   revert(solv, 1);
   reset_solver(solv);
 
@@ -2248,31 +2576,37 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
   for (;;)
     {
       /* re-enable as many weak rules as possible */
-      for (i = solv->weakrules; i < solv->learntrules; i++)
+      for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++)
        {
-         r = solv->rules + i;
-         if (!r->w1)
-           enablerule(solv, r);
+         if (r->w1)
+           continue;
+         if (!MAPTST(&solv->weakrulemap, i))
+           continue;
+         enablerule(solv, r);
        }
 
       queue_empty(&solv->problems);
       revert(solv, 1);         /* XXX move to reset_solver? */
       reset_solver(solv);
-      run_solver(solv, 0, 0);
+
+      if (!solv->problems.count)
+        run_solver(solv, 0, 0);
+
       if (!solv->problems.count)
        {
-         if (pool->verbose)
-           printf("no more problems!\n");
-#if 0
-         printdecisions(solv);
-#endif
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
+         IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
+           printdecisions(solv);
          break;                /* great, no more problems */
        }
       disabledcnt = disabled.count;
-      for (i = 0; i < solv->problems.count - 1; i++)
+      /* start with 1 to skip over proof index */
+      for (i = 1; i < solv->problems.count - 1; i++)
        {
          /* ignore solutions in refined */
           v = solv->problems.elements[i];
+         if (v == 0)
+           break;      /* end of problem reached */
          for (j = 0; problem[j]; j++)
            if (problem[j] != sug && problem[j] == v)
              break;
@@ -2283,8 +2617,7 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
       if (disabled.count == disabledcnt)
        {
          /* no solution found, this was an invalid suggestion! */
-         if (pool->verbose)
-           printf("no solution found!\n");
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
          refined->count = 0;
          break;
        }
@@ -2301,9 +2634,9 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
        {
          /* more than one solution, disable all */
          /* do not push anything on refine list */
-         if (pool->verbose > 1)
+         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
            {
-             printf("more than one solution found:\n");
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
              for (i = disabledcnt; i < disabled.count; i++)
                printproblem(solv, disabled.elements[i]);
            }
@@ -2318,8 +2651,8 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
   /* disable problem rules again */
   for (i = 0; problem[i]; i++)
     disableproblem(solv, problem[i]);
-  if (pool->verbose)
-    printf("refine_suggestion end\n");
+  disableupdaterules(solv, job, -1);
+  POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
 }
 
 static void
@@ -2333,11 +2666,15 @@ problems_to_solutions(Solver *solv, Queue *job)
   Id why;
   int i, j;
 
+  if (!solv->problems.count)
+    return;
   queue_clone(&problems, &solv->problems);
   queue_init(&solution);
   queue_init(&solutions);
-  problem = problems.elements;
-  for (i = 0; i < problems.count; i++)
+  /* copy over proof index */
+  queue_push(&solutions, problems.elements[0]);
+  problem = problems.elements + 1;
+  for (i = 1; i < problems.count; i++)
     {
       Id v = problems.elements[i];
       if (v == 0)
@@ -2347,6 +2684,9 @@ problems_to_solutions(Solver *solv, Queue *job)
          queue_push(&solutions, 0);
          if (i + 1 == problems.count)
            break;
+         /* copy over proof of next problem */
+          queue_push(&solutions, problems.elements[i + 1]);
+         i++;
          problem = problems.elements + i + 1;
          continue;
        }
@@ -2357,16 +2697,20 @@ problems_to_solutions(Solver *solv, Queue *job)
       for (j = 0; j < solution.count; j++)
        {
          why = solution.elements[j];
+         /* must be either job descriptor or system rule */
+         assert(why < 0 || (why >= solv->systemrules && why < solv->learntrules));
 #if 0
          printproblem(solv, why);
 #endif
          if (why < 0)
            {
+             /* job descriptor */
              queue_push(&solutions, 0);
              queue_push(&solutions, -why);
            }
-         else if (why >= solv->systemrules && why < solv->weakrules)
+         else
            {
+             /* system rule, find replacement package */
              Id p, rp = 0;
              p = solv->installed->start + (why - solv->systemrules);
              if (solv->weaksystemrules && solv->weaksystemrules[why - solv->systemrules])
@@ -2386,8 +2730,6 @@ problems_to_solutions(Solver *solv, Queue *job)
              queue_push(&solutions, p);
              queue_push(&solutions, rp);
            }
-         else
-           abort();
        }
       /* mark end of this solution */
       queue_push(&solutions, 0);
@@ -2398,110 +2740,180 @@ problems_to_solutions(Solver *solv, Queue *job)
   /* copy queue over to solutions */
   queue_free(&solv->problems);
   queue_clone(&solv->problems, &solutions);
+
+  /* bring solver back into problem state */
+  revert(solv, 1);             /* XXX move to reset_solver? */
+  reset_solver(solv);
+
+  assert(solv->problems.count == solutions.count);
   queue_free(&solutions);
 }
 
+Id
+solver_next_problem(Solver *solv, Id problem)
+{
+  Id *pp;
+  if (problem == 0)
+    return solv->problems.count ? 1 : 0;
+  pp = solv->problems.elements + problem;
+  while (pp[0] || pp[1])
+    {
+      /* solution */
+      pp += 2;
+      while (pp[0] || pp[1])
+        pp += 2;
+      pp += 2;
+    }
+  pp += 2;
+  problem = pp - solv->problems.elements;
+  if (problem >= solv->problems.count)
+    return 0;
+  return problem + 1;
+}
 
-  
-/*
- * printdecisions
- */
-  
-static const char *
-id2rc(Solver *solv, Id id)
+Id
+solver_next_solution(Solver *solv, Id problem, Id solution)
 {
-  const char *evr;
-  if (solv->rc_output != 2)
-    return "";
-  evr = id2str(solv->pool, id);
-  if (*evr < '0' || *evr > '9')
-    return "0:";
-  while (*evr >= '0' && *evr <= '9')
-    evr++;
-  if (*evr != ':')
-    return "0:";
-  return "";
+  Id *pp;
+  if (solution == 0)
+    {
+      solution = problem;
+      pp = solv->problems.elements + solution;
+      return pp[0] || pp[1] ? solution : 0;
+    }
+  pp = solv->problems.elements + solution;
+  while (pp[0] || pp[1])
+    pp += 2;
+  pp += 2;
+  solution = pp - solv->problems.elements;
+  return pp[0] || pp[1] ? solution : 0;
 }
 
-void
-printdecisions(Solver *solv)
+Id
+solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
+{
+  Id *pp;
+  element = element ? element + 2 : solution;
+  pp = solv->problems.elements + element;
+  if (!(pp[0] || pp[1]))
+    return 0;
+  *p = pp[0];
+  *rp = pp[1];
+  return element;
+}
+
+
+/*
+ * create obsoletesmap from solver decisions
+ * required for decision handling
+ *
+ * for solvables in installed repo:
+ *   0 - not obsoleted
+ *   p - one of the packages that obsolete us
+ * for all others:
+ *   n - number of packages this package obsoletes
+ */
+
+Id *
+create_decisions_obsoletesmap(Solver *solv)
 {
   Pool *pool = solv->pool;
-  Id p, *obsoletesmap;
+  Repo *installed = solv->installed;
+  Id p, *obsoletesmap = NULL;
   int i;
   Solvable *s;
 
-  obsoletesmap = (Id *)xcalloc(pool->nsolvables, sizeof(Id));
-  for (i = 0; i < solv->decisionq.count; i++)
+  obsoletesmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id));
+  if (installed)
     {
-      Id *pp, n;
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         Id *pp, n;
 
-      n = solv->decisionq.elements[i];
-      if (n < 0)
-       continue;
-      if (n == SYSTEMSOLVABLE)
-       continue;
-      if (n >= solv->installed->start && n < solv->installed->start + solv->installed->nsolvables)
-       continue;
-      s = pool->solvables + n;
-      FOR_PROVIDES(p, pp, s->name)
-       if (s->name == pool->solvables[p].name)
-         {
-           if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables && !obsoletesmap[p])
+         n = solv->decisionq.elements[i];
+         if (n < 0)
+           continue;
+         if (n == SYSTEMSOLVABLE)
+           continue;
+         s = pool->solvables + n;
+         if (s->repo == installed)             /* obsoletes don't count for already installed packages */
+           continue;
+         FOR_PROVIDES(p, pp, s->name)
+           if (s->name == pool->solvables[p].name)
              {
-               obsoletesmap[p] = n;
-               obsoletesmap[n]++;
+               if (pool->solvables[p].repo == installed && !obsoletesmap[p])
+                 {
+                   obsoletesmap[p] = n;
+                   obsoletesmap[n]++;
+                 }
              }
-         }
-    }
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      Id obs, *obsp;
-      Id *pp, n;
+       }
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         Id obs, *obsp;
+         Id *pp, n;
 
-      n = solv->decisionq.elements[i];
-      if (n < 0)
-       continue;
-      if (n == SYSTEMSOLVABLE)
-       continue;
-      if (n >= solv->installed->start && n < solv->installed->start + solv->installed->nsolvables)
-       continue;
-      s = pool->solvables + n;
-      if (!s->obsoletes)
-       continue;
-      obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       FOR_PROVIDES(p, pp, obs)
-         {
-           if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables && !obsoletesmap[p])
+         n = solv->decisionq.elements[i];
+         if (n < 0)
+           continue;
+         if (n == SYSTEMSOLVABLE)
+           continue;
+         s = pool->solvables + n;
+         if (s->repo == installed)             /* obsoletes don't count for already installed packages */
+           continue;
+         if (!s->obsoletes)
+           continue;
+         obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           FOR_PROVIDES(p, pp, obs)
              {
-               obsoletesmap[p] = n;
-               obsoletesmap[n]++;
+               if (pool->solvables[p].repo == installed && !obsoletesmap[p])
+                 {
+                   obsoletesmap[p] = n;
+                   obsoletesmap[n]++;
+                 }
              }
-         }
+       }
     }
+  return obsoletesmap;
+}
 
-  if (solv->rc_output)
-    printf(">!> Solution #1:\n");
+/*
+ * printdecisions
+ */
+
+void
+printdecisions(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p, *obsoletesmap = create_decisions_obsoletesmap( solv );
+  int i;
+  Solvable *s;
+
+  IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
+    {
+      POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions -----\n");
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         printruleelement(solv, SAT_DEBUG_SCHUBI, 0, p);
+       }
+      POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- Decisions end -----\n");
+    }
 
-  int installs = 0, uninstalls = 0, upgrades = 0;
-  
   /* print solvables to be erased */
 
-  for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
+  if (installed)
     {
-      if (solv->decisionmap[i] > 0)
-       continue;
-      if (obsoletesmap[i])
-       continue;
-      s = pool->solvables + i;
-      if (solv->rc_output == 2)
-       printf(">!> remove  %s-%s%s\n", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
-      else if (solv->rc_output)
-       printf(">!> remove  %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-      else
-       printf("erase   %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-      uninstalls++;
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         if (solv->decisionmap[p] >= 0)
+           continue;
+         if (obsoletesmap[p])
+           continue;
+         POOL_DEBUG(SAT_DEBUG_RESULT, "erase   %s\n", solvable2str(pool, s));
+       }
     }
 
   /* print solvables to be installed */
@@ -2514,165 +2926,430 @@ printdecisions(Solver *solv)
        continue;
       if (p == SYSTEMSOLVABLE)
        continue;
-      if (p >= solv->installed->start && p < solv->installed->start + solv->installed->nsolvables)
-       continue;
       s = pool->solvables + p;
+      if (installed && s->repo == installed)
+       continue;
 
       if (!obsoletesmap[p])
         {
-         if (solv->rc_output)
-           printf(">!> ");
-          printf("install %s-%s%s", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
-         if (solv->rc_output != 2)
-            printf(".%s", id2str(pool, s->arch));
-         installs++;
+          POOL_DEBUG(SAT_DEBUG_RESULT, "install %s", solvable2str(pool, s));
         }
-      else if (!solv->rc_output)
-       {
-         printf("update  %s-%s.%s  (obsoletes", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-         for (j = solv->installed->start; j < solv->installed->start + solv->installed->nsolvables; j++)
-           {
-             if (obsoletesmap[j] != p)
-               continue;
-             s = pool->solvables + j;
-             printf(" %s-%s.%s", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-           }
-         printf(")");
-         upgrades++;
-       }
       else
        {
-         Solvable *f, *fn = 0;
-         for (j = solv->installed->start; j < solv->installed->start + solv->installed->nsolvables; j++)
-           {
-             if (obsoletesmap[j] != p)
-               continue;
-             f = pool->solvables + j;
-             if (fn || f->name != s->name)
-               {
-                 if (solv->rc_output == 2)
-                   printf(">!> remove  %s-%s%s\n", id2str(pool, f->name), id2rc(solv, f->evr), id2str(pool, f->evr));
-                 else if (solv->rc_output)
-                   printf(">!> remove  %s-%s.%s\n", id2str(pool, f->name), id2str(pool, f->evr), id2str(pool, f->arch));
-                 uninstalls++;
-               }
-             else
-               fn = f;
-           }
-         if (!fn)
-           {
-             printf(">!> install %s-%s%s", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
-             if (solv->rc_output != 2)
-               printf(".%s", id2str(pool, s->arch));
-             installs++;
-           }
-         else
-           {
-             if (solv->rc_output == 2)
-               printf(">!> upgrade %s-%s => %s-%s%s", id2str(pool, fn->name), id2str(pool, fn->evr), id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
-             else
-               printf(">!> upgrade %s-%s.%s => %s-%s.%s", id2str(pool, fn->name), id2str(pool, fn->evr), id2str(pool, fn->arch), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
-             upgrades++;
-           }
+         POOL_DEBUG(SAT_DEBUG_RESULT, "update  %s", solvable2str(pool, s));
+          POOL_DEBUG(SAT_DEBUG_RESULT, "  (obsoletes");
+         for (j = installed->start; j < installed->end; j++)
+           if (obsoletesmap[j] == p)
+             POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + j));
+         POOL_DEBUG(SAT_DEBUG_RESULT, ")");
        }
-      if (solv->rc_output)
-       {
-         Repo *repo = s->repo;
-         if (repo && strcmp(repo_name(repo), "locales"))
-           printf("[%s]", repo_name(repo));
-        }
-      printf("\n");
+      POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
     }
 
-  if (solv->rc_output)
-    printf(">!> installs=%d, upgrades=%d, uninstalls=%d\n", installs, upgrades, uninstalls);
-  
-  xfree(obsoletesmap);
+  sat_free(obsoletesmap);
+
+  if (solv->recommendations.count)
+    {
+      POOL_DEBUG(SAT_DEBUG_RESULT, "\nrecommended packages:\n");
+      for (i = 0; i < solv->recommendations.count; i++)
+       {
+         s = pool->solvables + solv->recommendations.elements[i];
+         POOL_DEBUG(SAT_DEBUG_RESULT, "- %s\n", solvable2str(pool, s));
+       }
+    }
 
   if (solv->suggestions.count)
     {
-      printf("\nsuggested packages:\n");
+      POOL_DEBUG(SAT_DEBUG_RESULT, "\nsuggested packages:\n");
       for (i = 0; i < solv->suggestions.count; i++)
        {
          s = pool->solvables + solv->suggestions.elements[i];
-         printf("- %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+         POOL_DEBUG(SAT_DEBUG_RESULT, "- %s\n", solvable2str(pool, s));
        }
     }
 }
 
-void
-printsolutions(Solver *solv, Queue *job)
+
+/* this is basically the reverse of addrpmrulesforsolvable */
+SolverProbleminfo
+solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
 {
   Pool *pool = solv->pool;
-  int pcnt;
-  int i;
-  Id p, rp, what;
-  Solvable *s, *sd;
+  Repo *installed = solv->installed;
+  Rule *r;
+  Solvable *s;
+  int dontfix = 0;
+  Id p, *pp, req, *reqp, con, *conp, obs, *obsp, *dp;
 
-  printf("Encountered problems! Here are the solutions:\n\n");
-  pcnt = 1;
-  for (i = 0; i < solv->problems.count; )
+  assert(rid > 0);
+  if (rid >= solv->systemrules)
     {
-      printf("Problem %d:\n", pcnt++);
-      printf("====================================\n");
-      for (;;)
-        {
-         if (solv->problems.elements[i] == 0 && solv->problems.elements[i + 1] == 0)
-           {
-             /* end of solutions for this problems reached */
-             i += 2;
-             break;
-           }
-         for (;;)
-           {
-             p = solv->problems.elements[i];
-             rp = solv->problems.elements[i + 1];
-             i += 2;
-             if (p == 0 && rp == 0)
+      *depp = 0;
+      *sourcep = solv->installed->start + (rid - solv->systemrules);
+      *targetp = 0;
+      return SOLVER_PROBLEM_UPDATE_RULE;
+    }
+  if (rid >= solv->jobrules)
+    {
+
+      r = solv->rules + rid;
+      p = solv->ruletojob.elements[rid - solv->jobrules];
+      *depp = job->elements[p + 1];
+      *sourcep = p;
+      *targetp = job->elements[p];
+      if (r->d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && job->elements[p] != SOLVER_INSTALL_SOLVABLE_ONE_OF)
+       return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
+      return SOLVER_PROBLEM_JOB_RULE;
+    }
+  r = solv->rules + rid;
+  assert(r->p < 0);
+  if (r->d == 0 && r->w2 == 0)
+    {
+      /* a rpm rule assertion */
+      s = pool->solvables - r->p;
+      if (installed && !solv->fixsystem && s->repo == installed)
+       dontfix = 1;
+      assert(!dontfix);        /* dontfix packages never have a neg assertion */
+      *sourcep = -r->p;
+      *targetp = 0;
+      /* see why the package is not installable */
+      if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s))
+       {
+         *depp = 0;
+         return SOLVER_PROBLEM_NOT_INSTALLABLE;
+       }
+      /* check requires */
+      assert(s->requires);
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+         if (req == SOLVABLE_PREREQMARKER)
+           continue;
+         dp = pool_whatprovides(pool, req);
+         if (*dp == 0)
+           break;
+       }
+      assert(req);
+      *depp = req;
+      return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP;
+    }
+  s = pool->solvables - r->p;
+  if (installed && !solv->fixsystem && s->repo == installed)
+    dontfix = 1;
+  if (r->d == 0 && r->w2 < 0)
+    {
+      /* a package conflict */
+      Solvable *s2 = pool->solvables - r->w2;
+      int dontfix2 = 0;
+
+      if (installed && !solv->fixsystem && s2->repo == installed)
+       dontfix2 = 1;
+
+      /* if both packages have the same name and at least one of them
+       * is not installed, they conflict */
+      if (s->name == s2->name && (!installed || (s->repo != installed || s2->repo != installed)))
+       {
+         *depp = 0;
+         *sourcep = -r->p;
+         *targetp = -r->w2;
+         return SOLVER_PROBLEM_SAME_NAME;
+       }
+
+      /* check conflicts in both directions */
+      if (s->conflicts)
+       {
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
+            {
+              FOR_PROVIDES(p, pp, con)
                {
-                 /* end of this solution reached */
-                 printf("\n");
-                 break;
+                 if (dontfix && pool->solvables[p].repo == installed)
+                   continue;
+                 if (p != -r->w2)
+                   continue;
+                 *depp = con;
+                 *sourcep = -r->p;
+                 *targetp = p;
+                 return SOLVER_PROBLEM_PACKAGE_CONFLICT;
                }
-             if (p == 0)
-               {
-                 /* job, p is index into job queue */
-                 what = job->elements[rp];
-                 switch (job->elements[rp - 1])
-                   {
-                   case SOLVER_INSTALL_SOLVABLE:
+           }
+       }
+      if (s2->conflicts)
+       {
+         conp = s2->repo->idarraydata + s2->conflicts;
+         while ((con = *conp++) != 0)
+            {
+              FOR_PROVIDES(p, pp, con)
+               {
+                 if (dontfix2 && pool->solvables[p].repo == installed)
+                   continue;
+                 if (p != -r->p)
+                   continue;
+                 *depp = con;
+                 *sourcep = -r->w2;
+                 *targetp = p;
+                 return SOLVER_PROBLEM_PACKAGE_CONFLICT;
+               }
+           }
+       }
+      /* check obsoletes in both directions */
+      if ((!installed || s->repo != installed) && s->obsoletes)
+       {
+         obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, obs)
+               {
+                 if (p != -r->w2)
+                   continue;
+                 *depp = obs;
+                 *sourcep = -r->p;
+                 *targetp = p;
+                 return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
+               }
+           }
+       }
+      if ((!installed || s2->repo != installed) && s2->obsoletes)
+       {
+         obsp = s2->repo->idarraydata + s2->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, obs)
+               {
+                 if (p != -r->p)
+                   continue;
+                 *depp = obs;
+                 *sourcep = -r->w2;
+                 *targetp = p;
+                 return SOLVER_PROBLEM_PACKAGE_OBSOLETES;
+               }
+           }
+       }
+      /* all cases checked, can't happen */
+      assert(0);
+    }
+  /* simple requires */
+  assert(s->requires);
+  reqp = s->repo->idarraydata + s->requires;
+  while ((req = *reqp++) != 0)
+    {
+      if (req == SOLVABLE_PREREQMARKER)
+       continue;
+      dp = pool_whatprovides(pool, req);
+      if (r->d == 0)
+       {
+         if (*dp == r->w2 && dp[1] == 0)
+           break;
+       }
+      else if (dp - pool->whatprovidesdata == r->d)
+       break;
+    }
+  assert(req);
+  *depp = req;
+  *sourcep = -r->p;
+  *targetp = 0;
+  return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE;
+}
+
+static void
+findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
+{
+  Id rid;
+  Id lreqr, lconr, lsysr, ljobr;
+  Rule *r;
+  int reqassert = 0;
+
+  lreqr = lconr = lsysr = ljobr = 0;
+  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
+    {
+      assert(rid > 0);
+      if (rid >= solv->learntrules)
+       findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
+      else if (rid >= solv->systemrules)
+       {
+         if (!*sysrp)
+           *sysrp = rid;
+       }
+      else if (rid >= solv->jobrules)
+       {
+         if (!*jobrp)
+           *jobrp = rid;
+       }
+      else
+       {
+         r = solv->rules + rid;
+         if (!r->d && r->w2 < 0)
+           {
+             if (!*conrp)
+               *conrp = rid;
+           }
+         else
+           {
+             if (r->d == 0 && r->w2 == 0 && !reqassert)
+               {
+                 /* prefer assertions (XXX: bad idea?) */
+                 *reqrp = rid;
+                 reqassert = 1;
+               }
+             if (!*reqrp)
+               *reqrp = rid;
+             else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed)
+               {
+                 /* prefer rules of installed packages */
+                 Id op = *reqrp >= 0 ? solv->rules[*reqrp].p : -*reqrp;
+                 if (op <= 0 || solv->pool->solvables[op].repo != solv->installed)
+                   *reqrp = rid;
+               }
+           }
+       }
+    }
+  if (!*reqrp && lreqr)
+    *reqrp = lreqr;
+  if (!*conrp && lconr)
+    *conrp = lconr;
+  if (!*jobrp && ljobr)
+    *jobrp = ljobr;
+  if (!*sysrp && lsysr)
+    *sysrp = lsysr;
+}
+
+/*
+ * search for a rule that describes the problem to the
+ * user. A pretty hopeless task, actually. We currently
+ * prefer simple requires.
+ */
+Id
+solver_findproblemrule(Solver *solv, Id problem)
+{
+  Id reqr, conr, sysr, jobr;
+  Id idx = solv->problems.elements[problem - 1];
+  reqr = conr = sysr = jobr = 0;
+  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
+  if (reqr)
+    return reqr;
+  if (conr)
+    return conr;
+  if (sysr)
+    return sysr;
+  if (jobr)
+    return jobr;
+  assert(0);
+}
+
+void
+printprobleminfo(Solver *solv, Queue *job, Id problem)
+{
+  Pool *pool = solv->pool;
+  Id probr;
+  Id dep, source, target;
+  Solvable *s, *s2;
+
+  probr = solver_findproblemrule(solv, problem);
+  switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
+    {
+    case SOLVER_PROBLEM_UPDATE_RULE:
+      s = pool_id2solvable(pool, source);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
+      return;
+    case SOLVER_PROBLEM_JOB_RULE:
+      POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n");
+      return;
+    case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
+      POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides requested %s\n", dep2str(pool, dep));
+      return;
+    case SOLVER_PROBLEM_NOT_INSTALLABLE:
+      s = pool_id2solvable(pool, source);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s));
+      return;
+    case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
+      s = pool_id2solvable(pool, source);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
+      return;
+    case SOLVER_PROBLEM_SAME_NAME:
+      s = pool_id2solvable(pool, source);
+      s2 = pool_id2solvable(pool, target);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
+      return;
+    case SOLVER_PROBLEM_PACKAGE_CONFLICT:
+      s = pool_id2solvable(pool, source);
+      s2 = pool_id2solvable(pool, target);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+      return;
+    case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
+      s = pool_id2solvable(pool, source);
+      s2 = pool_id2solvable(pool, target);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+      return;
+    case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
+      s = pool_id2solvable(pool, source);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
+      return;
+    }
+}
+
+void
+printsolutions(Solver *solv, Queue *job)
+{
+  Pool *pool = solv->pool;
+  int pcnt;
+  Id p, rp, how, what;
+  Id problem, solution, element;
+  Solvable *s, *sd;
+
+  POOL_DEBUG(SAT_DEBUG_RESULT, "Encountered problems! Here are the solutions:\n\n");
+  pcnt = 1;
+  problem = 0;
+  while ((problem = solver_next_problem(solv, problem)) != 0)
+    {
+      POOL_DEBUG(SAT_DEBUG_RESULT, "Problem %d:\n", pcnt++);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "====================================\n");
+      printprobleminfo(solv, job, problem);
+      POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
+      solution = 0;
+      while ((solution = solver_next_solution(solv, problem, solution)) != 0)
+        {
+         element = 0;
+         while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
+           {
+             if (p == 0)
+               {
+                 /* job, rp is index into job queue */
+                 how = job->elements[rp - 1] & ~SOLVER_WEAK;
+                 what = job->elements[rp];
+                 switch (how)
+                   {
+                   case SOLVER_INSTALL_SOLVABLE:
                      s = pool->solvables + what;
-                     if (what >= solv->installed->start && what < solv->installed->start + solv->installed->nsolvables)
-                       printf("- do not keep %s-%s.%s installed\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+                     if (solv->installed && s->repo == solv->installed)
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, s));
                      else
-                       printf("- do not install %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solvable2str(pool, s));
                      break;
                    case SOLVER_ERASE_SOLVABLE:
                      s = pool->solvables + what;
-                     if (what >= solv->installed->start && what < solv->installed->start + solv->installed->nsolvables)
-                       printf("- do not deinstall %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+                     if (solv->installed && s->repo == solv->installed)
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solvable2str(pool, s));
                      else
-                       printf("- do not forbid installation of %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, s));
                      break;
                    case SOLVER_INSTALL_SOLVABLE_NAME:
-                     printf("- do not install %s\n", id2str(pool, what));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", dep2str(pool, what));
                      break;
                    case SOLVER_ERASE_SOLVABLE_NAME:
-                     printf("- do not deinstall %s\n", id2str(pool, what));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", dep2str(pool, what));
                      break;
                    case SOLVER_INSTALL_SOLVABLE_PROVIDES:
-                     printf("- do not install a solvable providing %s\n", dep2str(pool, what));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable providing %s\n", dep2str(pool, what));
                      break;
                    case SOLVER_ERASE_SOLVABLE_PROVIDES:
-                     printf("- do not deinstall all solvables providing %s\n", dep2str(pool, what));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables providing %s\n", dep2str(pool, what));
                      break;
                    case SOLVER_INSTALL_SOLVABLE_UPDATE:
                      s = pool->solvables + what;
-                     printf("- do not install most recent version of %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool
-    , s->arch));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solvable2str(pool, s));
                      break;
                    default:
-                     printf("- do something different\n");
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do something different\n");
                      break;
                    }
                }
@@ -2684,40 +3361,43 @@ printsolutions(Solver *solv, Queue *job)
                  if (sd)
                    {
                      int gotone = 0;
-                     if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr) > 0)
+                     if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
                        {
-                         printf("- allow downgrade of %s-%s.%s to %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
+                         POOL_DEBUG(SAT_DEBUG_RESULT, "- allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
                          gotone = 1;
                        }
-                     if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(pool, s, sd))
+                     if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(solv, s, sd))
                        {
-                         printf("- allow architecture change of %s-%s.%s to %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
+                         POOL_DEBUG(SAT_DEBUG_RESULT, "- allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
                          gotone = 1;
                        }
-                     if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(pool, s, sd))
+                     if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(solv, s, sd))
                        {
                          if (sd->vendor)
-                           printf("- allow vendor change from '%s' (%s-%s.%s) to '%s' (%s-%s.%s)\n", id2str(pool, s->vendor), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->vendor), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
+                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow vendor change from '%s' (%s) to '%s' (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), id2str(pool, sd->vendor), solvable2str(pool, sd));
                          else
-                           printf("- allow vendor change from '%s' (%s-%s.%s) to no vendor (%s-%s.%s)\n", id2str(pool, s->vendor), id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
+                           POOL_DEBUG(SAT_DEBUG_RESULT, "- allow vendor change from '%s' (%s) to no vendor (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), solvable2str(pool, sd));
                          gotone = 1;
                        }
                      if (!gotone)
-                       printf("- allow replacement of %s-%s.%s with %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), id2str(pool, sd->name), id2str(pool, sd->evr), id2str(pool, sd->arch));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- allow replacement of %s with %s\n", solvable2str(pool, s), solvable2str(pool, sd));
                    }
                  else
                    {
-                     printf("- allow deinstallation of %s-%s.%s [%ld]\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch), (long int)(s - pool->solvables));
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- allow deinstallation of %s\n", solvable2str(pool, s));
                    }
 
                }
            }
+         POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
         }
     }
 }
 
 
-/* for each installed solvable find which packages with *different* names
+/* create reverse obsoletes map for installed solvables
+ *
+ * for each installed solvable find which packages with *different* names
  * obsolete the solvable.
  * this index is used in policy_findupdatepackages if noupdateprovide is set.
  */
@@ -2731,11 +3411,14 @@ create_obsolete_index(Solver *solv)
   Id p, *pp, obs, *obsp, *obsoletes, *obsoletes_data;
   int i, n;
 
-  /* create reverse obsoletes map for installed solvables */
-  solv->obsoletes = obsoletes = xcalloc(installed->nsolvables, sizeof(Id));
+  if (!installed || !installed->nsolvables)
+    return;
+  solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
   for (i = 1; i < pool->nsolvables; i++)
     {
       s = pool->solvables + i;
+      if (s->repo == installed)
+       continue;
       if (!s->obsoletes)
        continue;
       if (!pool_installable(pool, s))
@@ -2744,7 +3427,7 @@ create_obsolete_index(Solver *solv)
       while ((obs = *obsp++) != 0)
         FOR_PROVIDES(p, pp, obs)
          {
-           if (p < installed->start || p >= installed->start + installed->nsolvables)
+           if (pool->solvables[p].repo != installed)
              continue;
            if (pool->solvables[p].name == s->name)
              continue;
@@ -2758,11 +3441,13 @@ create_obsolete_index(Solver *solv)
         n += obsoletes[i] + 1;
         obsoletes[i] = n;
       }
-  solv->obsoletes_data = obsoletes_data = xcalloc(n + 1, sizeof(Id));
-  if (pool->verbose) printf("obsoletes data: %d entries\n", n + 1);
+  solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
+  POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
   for (i = pool->nsolvables - 1; i > 0; i--)
     {
       s = pool->solvables + i;
+      if (s->repo == installed)
+       continue;
       if (!s->obsoletes)
        continue;
       if (!pool_installable(pool, s))
@@ -2771,7 +3456,7 @@ create_obsolete_index(Solver *solv)
       while ((obs = *obsp++) != 0)
         FOR_PROVIDES(p, pp, obs)
          {
-           if (p < installed->start || p >= installed->start + installed->nsolvables)
+           if (pool->solvables[p].repo != installed)
              continue;
            if (pool->solvables[p].name == s->name)
              continue;
@@ -2782,6 +3467,116 @@ create_obsolete_index(Solver *solv)
     }
 }
 
+static void
+removedisabledconflicts(Solver *solv, Queue *removed)
+{
+  Pool *pool = solv->pool;
+  int i, n;
+  Id p, why, *dp;
+  Id new;
+  Rule *r;
+  Id *decisionmap = solv->decisionmap;
+
+  POOL_DEBUG(SAT_DEBUG_STATS, "removedisabledconflicts\n");
+  queue_empty(removed);
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p > 0)
+       continue;
+      /* a conflict. we never do conflicts on free decisions, so there
+       * must have been an unit rule */
+      why = solv->decisionq_why.elements[i];
+      assert(why > 0);
+      r = solv->rules + why;
+      if (!r->w1 && decisionmap[-p])
+       {
+         /* rule is now disabled, remove from decisionmap */
+         POOL_DEBUG(SAT_DEBUG_STATS, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p);
+         queue_push(removed, -p);
+         queue_push(removed, decisionmap[-p]);
+         decisionmap[-p] = 0;
+       }
+    }
+  if (!removed->count)
+    return;
+  /* we removed some confliced packages. some of them might still
+   * be in conflict, so search for unit rules and re-conflict */
+  new = 0;
+  for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
+    {
+      if (i == solv->nrules)
+       {
+         i = 1;
+         r = solv->rules + i;
+       }
+      if (!r->w1)
+       continue;
+      if (!r->w2)
+       {
+         if (r->p < 0 && !decisionmap[-r->p])
+           new = r->p;
+       }
+      else if (!r->d)
+       {
+         /* binary rule */
+         if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
+           new = r->p;
+         else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
+           new = r->w2;
+       }
+      else
+       {
+         if (r->p < 0 && decisionmap[-r->p] == 0)
+           new = r->p;
+         if (new || DECISIONMAP_FALSE(r->p))
+           {
+             dp = pool->whatprovidesdata + r->d;
+             while ((p = *dp++) != 0)
+               {
+                 if (new && p == new)
+                   continue;
+                 if (p < 0 && decisionmap[-p] == 0)
+                   {
+                     if (new)
+                       {
+                         new = 0;
+                         break;
+                       }
+                     new = p;
+                   }
+                 else if (!DECISIONMAP_FALSE(p))
+                   {
+                     new = 0;
+                     break;
+                   }
+               }
+           }
+       }
+      if (new)
+       {
+         POOL_DEBUG(SAT_DEBUG_STATS, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new);
+         decisionmap[-new] = -1;
+         n = 0;        /* redo all rules */
+       }
+    }
+}
+
+static void
+weaken_solvable_deps(Solver *solv, Id p)
+{
+  int i;
+  Rule *r;
+
+  for (i = 1, r = solv->rules + i; i < solv->jobrules; i++, r++)
+    {
+      if (r->p != -p)
+       continue;
+      if (r->d == 0 && r->w2 < 0)
+       continue;       /* conflict */
+      queue_push(&solv->weakruleq, i);
+    }
+}
 
 /*-----------------------------------------------------------------*/
 /* main() */
@@ -2793,23 +3588,31 @@ create_obsolete_index(Solver *solv)
  */
 
 void
-solve(Solver *solv, Queue *job)
+solver_solve(Solver *solv, Queue *job)
 {
   Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
   int i;
-  Map addedmap;                               /* '1' == have rule for solvable */
-  Id how, what, p, *pp, d;
-  Queue q;
+  int oldnrules;
+  Map addedmap;                       /* '1' == have rpm-rules for solvable */
+  Id how, what, weak, name, p, *pp, d;
+  Queue q, redoq;
   Solvable *s;
+  int gotweak;
+  Rule *r;
+
+  /* create whatprovides if not already there */
+  if (!pool->whatprovides)
+    pool_createwhatprovides(pool);
 
   /* create obsolete index if needed */
-  if (solv->noupdateprovide && solv->installed->nsolvables)
+  if (solv->noupdateprovide)
     create_obsolete_index(solv);
 
   /*
    * create basic rule set of all involved packages
    * use addedmap bitmap to make sure we don't create rules twice
-   * 
+   *
    */
 
   map_init(&addedmap, pool->nsolvables);
@@ -2824,29 +3627,29 @@ solve(Solver *solv, Queue *job)
   solv->decisionmap[SYSTEMSOLVABLE] = 1;
 
   /*
-   * create rules for installed solvables -> keep them installed
+   * create rules for all package that could be involved with the solving
    * so called: rpm rules
-   * 
-   */
-
-  for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
-    addrpmrulesforsolvable(solv, pool->solvables + i, &addedmap);
-
-  /*
-   * create install rules
-   * 
-   * two passes, as we want to keep the rpm rules distinct from the job rules
-   * 
+   *
    */
+  if (installed)
+    {
+      oldnrules = solv->nrules;
+      POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
+      FOR_REPO_SOLVABLES(installed, p, s)
+       addrpmrulesforsolvable(solv, s, &addedmap);
+      POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
+      POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
+      oldnrules = solv->nrules;
+      FOR_REPO_SOLVABLES(installed, p, s)
+       addrpmrulesforupdaters(solv, s, &addedmap, 1);
+      POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
+    }
 
-  /*
-   * solvable rules
-   *  process job rules for solvables
-   */
-  
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for packages involved with a job ***\n");
+  oldnrules = solv->nrules;
   for (i = 0; i < job->count; i += 2)
     {
-      how = job->elements[i];
+      how = job->elements[i] & ~SOLVER_WEAK;
       what = job->elements[i + 1];
 
       switch(how)
@@ -2856,10 +3659,16 @@ solve(Solver *solv, Queue *job)
          break;
        case SOLVER_INSTALL_SOLVABLE_NAME:
        case SOLVER_INSTALL_SOLVABLE_PROVIDES:
+         name = (how == SOLVER_INSTALL_SOLVABLE_NAME) ? what : 0;
+         while (ISRELDEP(name))
+           {
+             Reldep *rd = GETRELDEP(pool, name);
+             name = rd->name;
+           }
          FOR_PROVIDES(p, pp, what)
            {
              /* if by name, ensure that the name matches */
-             if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
+             if (name && pool->solvables[p].name != name)
                continue;
              addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
            }
@@ -2868,16 +3677,22 @@ solve(Solver *solv, Queue *job)
          /* dont allow downgrade */
          addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
          break;
+       case SOLVER_INSTALL_SOLVABLE_ONE_OF:
+         pp = pool->whatprovidesdata + what;
+         while ((p = *pp++) != 0)
+           addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
+         break;
        }
     }
+  POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
 
-  for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
-    addrpmrulesforupdaters(solv, pool->solvables + i, &addedmap, 1);
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
 
+  oldnrules = solv->nrules;
   addrpmrulesforweak(solv, &addedmap);
+  POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
 
-#if 1
-  if (pool->verbose)
+  IF_POOLDEBUG (SAT_DEBUG_STATS)
     {
       int possible = 0, installable = 0;
       for (i = 1; i < pool->nsolvables; i++)
@@ -2887,9 +3702,8 @@ solve(Solver *solv, Queue *job)
          if (MAPTST(&addedmap, i))
            possible++;
        }
-      printf("%d of %d installable solvables used for solving\n", possible, installable);
+      POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
     }
-#endif
 
   /*
    * first pass done, we now have all the rpm rules we need.
@@ -2898,56 +3712,68 @@ solve(Solver *solv, Queue *job)
    * at this point the system is always solvable,
    * as an empty system (remove all packages) is a valid solution
    */
-  
+
   unifyrules(solv);    /* remove duplicate rpm rules */
+  solv->directdecisions = solv->decisionq.count;
 
-  if (pool->verbose) printf("decisions based on rpm rules: %d\n", solv->decisionq.count);
+  POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
+  IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
+    printdecisions (solv);
 
   /*
    * now add all job rules
    */
-  
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add JOB rules ***\n");
+
   solv->jobrules = solv->nrules;
 
   for (i = 0; i < job->count; i += 2)
     {
-      how = job->elements[i];
+      oldnrules = solv->nrules;
+
+      how = job->elements[i] & ~SOLVER_WEAK;
+      weak = job->elements[i] & SOLVER_WEAK;
       what = job->elements[i + 1];
       switch(how)
        {
        case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
          s = pool->solvables + what;
-         if (solv->rc_output)
-            {
-             printf(">!> Installing %s from channel %s\n", id2str(pool, s->name), repo_name(s->repo));
-           }
-         if (pool->verbose)
-           printf("job: install solvable %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall solvable %s\n", weak ? "weak " : "", solvable2str(pool, s));
           addrule(solv, what, 0);                      /* install by Id */
          queue_push(&solv->ruletojob, i);
+         if (weak)
+           queue_push(&solv->weakruleq, solv->nrules - 1);
          break;
        case SOLVER_ERASE_SOLVABLE:
          s = pool->solvables + what;
-         if (pool->verbose)
-           printf("job: erase solvable %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase solvable %s\n", weak ? "weak " : "", solvable2str(pool, s));
           addrule(solv, -what, 0);                     /* remove by Id */
          queue_push(&solv->ruletojob, i);
+         if (weak)
+           queue_push(&solv->weakruleq, solv->nrules - 1);
          break;
        case SOLVER_INSTALL_SOLVABLE_NAME:              /* install by capability */
        case SOLVER_INSTALL_SOLVABLE_PROVIDES:
-         if (pool->verbose && how == SOLVER_INSTALL_SOLVABLE_NAME)
-           printf("job: install name %s\n", id2str(pool, what));
-         if (pool->verbose && how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
-           printf("job: install provides %s\n", dep2str(pool, what));
+         if (how == SOLVER_INSTALL_SOLVABLE_NAME)
+           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall name %s\n", weak ? "weak " : "", dep2str(pool, what));
+         if (how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
+           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall provides %s\n", weak ? "weak " : "", dep2str(pool, what));
          queue_empty(&q);
+         name = (how == SOLVER_INSTALL_SOLVABLE_NAME) ? what : 0;
+         while (ISRELDEP(name))
+           {
+             Reldep *rd = GETRELDEP(pool, name);
+             name = rd->name;
+           }
          FOR_PROVIDES(p, pp, what)
            {
               /* if by name, ensure that the name matches */
-             if (how == SOLVER_INSTALL_SOLVABLE_NAME && pool->solvables[p].name != what)
+             if (name && pool->solvables[p].name != name)
                continue;
              queue_push(&q, p);
            }
-         if (!q.count) 
+         if (!q.count)
            {
              /* no provider, make this an impossible rule */
              queue_push(&q, -SYSTEMSOLVABLE);
@@ -2960,72 +3786,119 @@ solve(Solver *solv, Queue *job)
            d = pool_queuetowhatprovides(pool, &q);   /* get all providers */
          addrule(solv, p, d);         /* add 'requires' rule */
          queue_push(&solv->ruletojob, i);
+         if (weak)
+           queue_push(&solv->weakruleq, solv->nrules - 1);
          break;
        case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
        case SOLVER_ERASE_SOLVABLE_PROVIDES:
-         if (pool->verbose && how == SOLVER_ERASE_SOLVABLE_NAME)
-           printf("job: erase name %s\n", id2str(pool, what));
-         if (pool->verbose && how == SOLVER_ERASE_SOLVABLE_PROVIDES)
-           printf("job: erase provides %s\n", dep2str(pool, what));
+         if (how == SOLVER_ERASE_SOLVABLE_NAME)
+           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase name %s\n", weak ? "weak " : "", dep2str(pool, what));
+         if (how == SOLVER_ERASE_SOLVABLE_PROVIDES)
+           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase provides %s\n", weak ? "weak " : "", dep2str(pool, what));
+         name = (how == SOLVER_ERASE_SOLVABLE_NAME) ? what : 0;
+         while (ISRELDEP(name))
+           {
+             Reldep *rd = GETRELDEP(pool, name);
+             name = rd->name;
+           }
          FOR_PROVIDES(p, pp, what)
            {
              /* if by name, ensure that the name matches */
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && pool->solvables[p].name != what)
+             if (name && pool->solvables[p].name != name)
                continue;
              addrule(solv, -p, 0);  /* add 'remove' rule */
              queue_push(&solv->ruletojob, i);
+             if (weak)
+               queue_push(&solv->weakruleq, solv->nrules - 1);
            }
          break;
        case SOLVER_INSTALL_SOLVABLE_UPDATE:              /* find update for solvable */
          s = pool->solvables + what;
-         if (pool->verbose)
-           printf("job: update %s-%s.%s\n", id2str(pool, s->name), id2str(pool, s->evr), id2str(pool, s->arch));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solvable2str(pool, s));
          addupdaterule(solv, s, 0);
          queue_push(&solv->ruletojob, i);
+         if (weak)
+           queue_push(&solv->weakruleq, solv->nrules - 1);
+         break;
+       case SOLVER_INSTALL_SOLVABLE_ONE_OF:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sone of\n", weak ? "weak " : "");
+         for (pp = pool->whatprovidesdata + what; *pp; pp++)
+           POOL_DEBUG(SAT_DEBUG_JOB, "  %s\n", solvable2str(pool, pool->solvables + *pp));
+         addrule(solv, -SYSTEMSOLVABLE, what);
+         queue_push(&solv->ruletojob, i);
+         if (weak)
+           queue_push(&solv->weakruleq, solv->nrules - 1);
+         break;
+       case SOLVER_WEAKEN_SOLVABLE_DEPS:
+         s = pool->solvables + what;
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: weaken deps %s\n", solvable2str(pool, s));
+         weaken_solvable_deps(solv, what);
          break;
        }
+      IF_POOLDEBUG (SAT_DEBUG_JOB)
+       {
+         int j;
+         if (solv->nrules == oldnrules)
+           POOL_DEBUG(SAT_DEBUG_JOB, " - no rule created\n");
+         for (j = oldnrules; j < solv->nrules; j++)
+           {
+             POOL_DEBUG(SAT_DEBUG_JOB, " - job ");
+             printrule(solv, SAT_DEBUG_JOB, solv->rules + j);
+           }
+       }
     }
+  assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
 
-  if (solv->ruletojob.count != solv->nrules - solv->jobrules)
-    abort();
-
-  if (pool->verbose) printf("problems so far: %d\n", solv->problems.count);
-  
   /*
-   * now add policy rules
-   * 
+   * now add system rules
+   *
    */
-  
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add system rules ***\n");
+
+
   solv->systemrules = solv->nrules;
 
   /*
    * create rules for updating installed solvables
-   * 
+   *
    */
-  
-  if (!solv->allowuninstall)
+
+  if (installed && !solv->allowuninstall)
     {                                 /* loop over all installed solvables */
       /* we create all update rules, but disable some later on depending on the job */
-      for (i = solv->installed->start; i < solv->installed->start + solv->installed->nsolvables; i++)
-       addupdaterule(solv, pool->solvables + i, 0);
+      for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
+       {
+         /* no system rules for patch atoms */
+         if (s->freshens && !s->supplements)
+           {
+             const char *name = id2str(pool, s->name);
+             if (name[0] == 'a' && !strncmp(name, "atom:", 5))
+               {
+                 addrule(solv, 0, 0);
+                 continue;
+               }
+           }
+         if (s->repo == installed)
+           addupdaterule(solv, s, 0);  /* allowall = 0 */
+         else
+           addrule(solv, 0, 0);        /* create dummy rule */
+       }
       /* consistency check: we added a rule for _every_ system solvable */
-      if (solv->nrules - solv->systemrules != solv->installed->nsolvables)
-       abort();
+      assert(solv->nrules - solv->systemrules == installed->end - installed->start);
     }
 
-  if (pool->verbose) printf("problems so far: %d\n", solv->problems.count);
-
   /* create special weak system rules */
   /* those are used later on to keep a version of the installed packages in
      best effort mode */
-  if (solv->installed->nsolvables)
+  if (installed && installed->nsolvables)
     {
-      solv->weaksystemrules = xcalloc(solv->installed->nsolvables, sizeof(Id));
-      for (i = 0; i < solv->installed->nsolvables; i++)
+      solv->weaksystemrules = sat_calloc(installed->end - installed->start, sizeof(Id));
+      FOR_REPO_SOLVABLES(installed, p, s)
        {
-         policy_findupdatepackages(solv, pool->solvables + solv->installed->start + i, &q, 1);
+         policy_findupdatepackages(solv, s, &q, 1);
          if (q.count)
-           solv->weaksystemrules[i] = pool_queuetowhatprovides(pool, &q);
+           solv->weaksystemrules[p - installed->start] = pool_queuetowhatprovides(pool, &q);
        }
     }
 
@@ -3033,33 +3906,105 @@ solve(Solver *solv, Queue *job)
   map_free(&addedmap);
   queue_free(&q);
 
-  solv->weakrules = solv->nrules;
+  /* create weak map */
+  map_init(&solv->weakrulemap, solv->nrules);
+  for (i = 0; i < solv->weakruleq.count; i++)
+    {
+      p = solv->weakruleq.elements[i];
+      MAPSET(&solv->weakrulemap, p);
+    }
+
+  /* all new rules are learnt after this point */
+  solv->learntrules = solv->nrules;
+
+  /* disable system rules that conflict with our job */
+  disableupdaterules(solv, job, -1);
+
+  /* make decisions based on job/system assertions */
+  makeruledecisions(solv);
+
+  /* create watches chains */
+  makewatches(solv);
+
+  POOL_DEBUG(SAT_DEBUG_STATS, "problems so far: %d\n", solv->problems.count);
+
+  /* solve! */
+  run_solver(solv, 1, solv->dontinstallrecommended ? 0 : 1);
 
-  /* try real hard to keep packages installed */
-  if (0)
+  queue_init(&redoq);
+  gotweak = 0;
+  /* disable all weak erase rules for recommened/suggestes search */
+  for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
     {
-      for (i = 0; i < solv->installed->nsolvables; i++)
+      if (!MAPTST(&solv->weakrulemap, i))
+       continue;
+      if (!r->w1)
+       continue;
+      disablerule(solv, r);
+      gotweak++;
+    }
+  if (gotweak)
+    {
+      enabledisablelearntrules(solv);
+      removedisabledconflicts(solv, &redoq);
+    }
+
+  /* find recommended packages */
+  /* if q.count == 0 we already found all recommended in the
+   * solver run */
+  if (redoq.count || solv->dontinstallrecommended)
+    {
+      Id rec, *recp, p, *pp;
+
+      /* create map of all suggests that are still open */
+      solv->recommends_index = -1;
+      MAPZERO(&solv->recommendsmap);
+      for (i = 0; i < solv->decisionq.count; i++)
        {
-         /* FIXME: can't work with refine_suggestion! */
-          /* need to always add the rule but disable it */
-         if (MAPTST(&solv->noupdate, i))
+         p = solv->decisionq.elements[i];
+         if (p < 0)
            continue;
-         d = solv->weaksystemrules[i];
-         addrule(solv, solv->installed->start + i, d);
+         s = pool->solvables + p;
+         if (s->recommends)
+           {
+             recp = s->repo->idarraydata + s->recommends;
+             while ((rec = *recp++) != 0)
+               {
+                 FOR_PROVIDES(p, pp, rec)
+                   if (solv->decisionmap[p] > 0)
+                     break;
+                 if (p)
+                   continue;   /* p != 0: already fulfilled */
+                 FOR_PROVIDES(p, pp, rec)
+                   MAPSET(&solv->recommendsmap, p);
+               }
+           }
        }
+      for (i = 1; i < pool->nsolvables; i++)
+       {
+         if (solv->decisionmap[i] != 0)
+           continue;
+         s = pool->solvables + i;
+         if (!MAPTST(&solv->recommendsmap, i))
+           {
+             if (!s->supplements)
+               continue;
+             if (!pool_installable(pool, s))
+               continue;
+             if (!solver_is_supplementing(solv, s))
+               continue;
+           }
+         if (solv->dontinstallrecommended)
+           queue_push(&solv->recommendations, i);
+         else
+           queue_pushunique(&solv->recommendations, i);
+       }
+      /* we use MODE_SUGGEST here so that repo prio is ignored */
+      policy_filter_unwanted(solv, &solv->recommendations, 0, POLICY_MODE_SUGGEST);
     }
 
-  /*
-   * solve !
-   * 
-   */
-  
-  disableupdaterules(solv, job, -1);
-  makeruledecisions(solv);
-  run_solver(solv, 1, 1);
-
   /* find suggested packages */
-  if (!solv->problems.count)
+  if (1)
     {
       Id sug, *sugp, p, *pp;
 
@@ -3106,7 +4051,63 @@ solve(Solver *solv, Queue *job)
       policy_filter_unwanted(solv, &solv->suggestions, 0, POLICY_MODE_SUGGEST);
     }
 
+  if (redoq.count)
+    {
+      /* restore decisionmap */
+      for (i = 0; i < redoq.count; i += 2)
+       solv->decisionmap[redoq.elements[i]] = redoq.elements[i + 1];
+    }
+
+
   if (solv->problems.count)
-    problems_to_solutions(solv, job);
+    {
+      int recocount = solv->recommendations.count;
+      solv->recommendations.count = 0; /* so that revert() doesn't mess with it */
+      queue_empty(&redoq);
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         Id p = solv->decisionq.elements[i];
+         queue_push(&redoq, p);
+         queue_push(&redoq, solv->decisionq_why.elements[i]);
+         queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
+       }
+      problems_to_solutions(solv, job);
+      memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
+      queue_empty(&solv->decisionq);
+      queue_empty(&solv->decisionq_why);
+      for (i = 0; i < redoq.count; i += 3)
+       {
+         Id p = redoq.elements[i];
+         queue_push(&solv->decisionq, p);
+         queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
+         solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
+       }
+      solv->recommendations.count = recocount;
+    }
+  queue_free(&redoq);
+}
+
+/***********************************************************************/
+
+void
+solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
+{
+  Map installedmap;
+
+  solver_create_state_maps(solv, &installedmap, 0);
+  pool_calc_duchanges(solv->pool, solv->installed, &installedmap, mps, nmps);
+  map_free(&installedmap);
+}
+
+int
+solver_calc_installsizechange(Solver *solv)
+{
+  Map installedmap;
+  int change;
+
+  solver_create_state_maps(solv, &installedmap, 0);
+  change = pool_calc_installsizechange(solv->pool, solv->installed, &installedmap);
+  map_free(&installedmap);
+  return change;
 }