- split problem handling from solver.c
authorMichael Schroeder <mls@suse.de>
Tue, 26 May 2009 08:59:14 +0000 (10:59 +0200)
committerMichael Schroeder <mls@suse.de>
Tue, 26 May 2009 08:59:14 +0000 (10:59 +0200)
src/CMakeLists.txt
src/bitmap.c
src/bitmap.h
src/pool.c
src/problems.c [new file with mode: 0644]
src/problems.h [new file with mode: 0644]
src/queue.c
src/queue.h
src/solver.c
src/solver.h

index 7c0b0e7..925d92f 100644 (file)
@@ -3,7 +3,7 @@ SET(libsatsolver_SRCS
     bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c
     solver.c solverdebug.c repo_solv.c repo_helix.c evr.c pool.c
     queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
-    transaction.c rules.c)
+    transaction.c rules.c problems.c)
 
 ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS})
 
@@ -11,7 +11,7 @@ SET(libsatsolver_HEADERS
     bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
     poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
     repo.h repodata.h repopage.h repo_solv.h repo_helix.h util.h
-    strpool.h dirpool.h knownid.h transaction.h rules.h)
+    strpool.h dirpool.h knownid.h transaction.h rules.h problems.h)
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 
index f7ee3dd..c94afe0 100644 (file)
@@ -33,7 +33,7 @@ map_free(Map *m)
 
 // copy t <- s
 void
-map_clone(Map *t, Map *s)
+map_init_clone(Map *t, Map *s)
 {
   t->size = s->size;
   t->map = sat_malloc(s->size);
index 5c78c16..45cef21 100644 (file)
@@ -23,8 +23,14 @@ typedef struct _Map {
 #define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7))) // Reset Bit
 #define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7))) // Test Bit
 
+static inline void
+map_empty(Map *m)
+{
+  MAPZERO(m);
+}
+
 extern void map_init(Map *m, int n);
+extern void map_init_clone(Map *t, Map *s);
 extern void map_free(Map *m);
-extern void map_clone(Map *t, Map *s);
 
 #endif /* SATSOLVER_BITMAP_H */
index e375b91..0921904 100644 (file)
@@ -1620,7 +1620,7 @@ pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pk
        }
     }
   queue_free(res);
-  queue_clone(res, pkgs);
+  queue_init_clone(res, pkgs);
   for (i = 0; i < pkgs->count; i++)
     {
       m = map[pkgs->elements[i]];
diff --git a/src/problems.c b/src/problems.c
new file mode 100644 (file)
index 0000000..f76a761
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * problems.c
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "evr.h"
+#include "solverdebug.h"
+
+
+/**********************************************************************************/
+
+/* a problem is an item on the solver's problem list. It can either be >0, in that
+ * case it is a update/infarch/dup rule, or it can be <0, which makes it refer to a job
+ * consisting of multiple job rules.
+ */
+
+void
+solver_disableproblem(Solver *solv, Id v)
+{
+  Rule *r;
+  int i;
+  Id *jp;
+
+  if (v > 0)
+    {
+      if (v >= solv->infarchrules && v < solv->infarchrules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_disablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->duprules && v < solv->duprules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_disablerule(solv, solv->rules + v);
+         return;
+       }
+      solver_disablerule(solv, solv->rules + v);
+#if 0
+      /* XXX: doesn't work */
+      if (v >= solv->updaterules && v < solv->updaterules_end)
+       {
+         /* enable feature rule if we disabled the update rule */
+         r = solv->rules + (v - solv->updaterules + solv->featurerules);
+         if (r->p)
+           solver_enablerule(solv, r);
+       }
+#endif
+      return;
+    }
+  v = -(v + 1);
+  jp = solv->ruletojob.elements;
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+    if (*jp == v)
+      solver_disablerule(solv, r);
+}
+
+/*-------------------------------------------------------------------
+ * enableproblem
+ */
+
+void
+solver_enableproblem(Solver *solv, Id v)
+{
+  Rule *r;
+  int i;
+  Id *jp;
+
+  if (v > 0)
+    {
+      if (v >= solv->infarchrules && v < solv->infarchrules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_enablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->duprules && v < solv->duprules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_enablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->featurerules && v < solv->featurerules_end)
+       {
+         /* do not enable feature rule if update rule is enabled */
+         r = solv->rules + (v - solv->featurerules + solv->updaterules);
+         if (r->d >= 0)
+           return;
+       }
+      solver_enablerule(solv, solv->rules + v);
+      if (v >= solv->updaterules && v < solv->updaterules_end)
+       {
+         /* disable feature rule when enabling update rule */
+         r = solv->rules + (v - solv->updaterules + solv->featurerules);
+         if (r->p)
+           solver_disablerule(solv, r);
+       }
+      return;
+    }
+  v = -(v + 1);
+  jp = solv->ruletojob.elements;
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+    if (*jp == v)
+      solver_enablerule(solv, r);
+}
+
+
+/*-------------------------------------------------------------------
+ * enable weak rules
+ * 
+ * Reenable all disabled weak rules (marked in weakrulemap)
+ * 
+ */
+
+static void
+enableweakrules(Solver *solv)
+{
+  int i;
+  Rule *r;
+
+  for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
+    {
+      if (r->d >= 0) /* already enabled? */
+       continue;
+      if (!MAPTST(&solv->weakrulemap, i))
+       continue;
+      solver_enablerule(solv, r);
+    }
+}
+
+
+/*-------------------------------------------------------------------
+ * 
+ * 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
+refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Id v;
+  Queue disabled;
+  int disabledcnt;
+
+  IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+    {
+      POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
+      for (i = 0; problem[i]; i++)
+       {
+         if (problem[i] == sug)
+           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
+         solver_printproblem(solv, problem[i]);
+       }
+    }
+  queue_empty(refined);
+  if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
+    return;
+  queue_init(&disabled);
+  queue_push(refined, sug);
+
+  /* re-enable all problem rules with the exception of "sug"(gestion) */
+  solver_reset(solv);
+
+  for (i = 0; problem[i]; i++)
+    if (problem[i] != sug)
+      solver_enableproblem(solv, problem[i]);
+
+  if (sug < 0)
+    solver_reenablepolicyrules(solv, -(sug + 1));
+  else if (sug >= solv->updaterules && sug < solv->updaterules_end)
+    {
+      /* enable feature rule */
+      Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
+      if (r->p)
+       solver_enablerule(solv, r);
+    }
+
+  enableweakrules(solv);
+
+  for (;;)
+    {
+      int njob, nfeature, nupdate;
+      queue_empty(&solv->problems);
+      solver_reset(solv);
+
+      if (!solv->problems.count)
+        solver_run_sat(solv, 0, 0);
+
+      if (!solv->problems.count)
+       {
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
+         IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
+           solver_printdecisions(solv);
+         break;                /* great, no more problems */
+       }
+      disabledcnt = disabled.count;
+      /* start with 1 to skip over proof index */
+      njob = nfeature = nupdate = 0;
+      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;
+         if (problem[j])
+           continue;
+         if (v >= solv->featurerules && v < solv->featurerules_end)
+           nfeature++;
+         else if (v > 0)
+           nupdate++;
+         else
+           {
+             if (!essentialok && (solv->job.elements[-v -1] & SOLVER_ESSENTIAL) != 0)
+               continue;       /* not that one! */
+             njob++;
+           }
+         queue_push(&disabled, v);
+       }
+      if (disabled.count == disabledcnt)
+       {
+         /* no solution found, this was an invalid suggestion! */
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
+         refined->count = 0;
+         break;
+       }
+      if (!njob && nupdate && nfeature)
+       {
+         /* got only update rules, filter out feature rules */
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "throwing away feature rules\n");
+         for (i = j = disabledcnt; i < disabled.count; i++)
+           {
+             v = disabled.elements[i];
+             if (v < solv->featurerules || v >= solv->featurerules_end)
+               disabled.elements[j++] = v;
+           }
+         disabled.count = j;
+         nfeature = 0;
+       }
+      if (disabled.count == disabledcnt + 1)
+       {
+         /* just one suggestion, add it to refined list */
+         v = disabled.elements[disabledcnt];
+         if (!nfeature)
+           queue_push(refined, v);     /* do not record feature rules */
+         solver_disableproblem(solv, v);
+         if (v >= solv->updaterules && v < solv->updaterules_end)
+           {
+             Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
+             if (r->p)
+               solver_enablerule(solv, r);     /* enable corresponding feature rule */
+           }
+         if (v < 0)
+           solver_reenablepolicyrules(solv, -(v + 1));
+       }
+      else
+       {
+         /* more than one solution, disable all */
+         /* do not push anything on refine list, as we do not know which solution to choose */
+         /* thus, the user will get another problem if he selects this solution, where he
+           * can choose the right one */
+         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
+             for (i = disabledcnt; i < disabled.count; i++)
+               solver_printproblem(solv, disabled.elements[i]);
+           }
+         for (i = disabledcnt; i < disabled.count; i++)
+           {
+             v = disabled.elements[i];
+             solver_disableproblem(solv, v);
+             if (v >= solv->updaterules && v < solv->updaterules_end)
+               {
+                 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
+                 if (r->p)
+                   solver_enablerule(solv, r);
+               }
+           }
+       }
+    }
+  /* all done, get us back into the same state as before */
+  /* enable refined rules again */
+  for (i = 0; i < disabled.count; i++)
+    solver_enableproblem(solv, disabled.elements[i]);
+  queue_free(&disabled);
+  /* reset policy rules */
+  for (i = 0; problem[i]; i++)
+    solver_enableproblem(solv, problem[i]);
+  solver_disablepolicyrules(solv);
+  /* disable problem rules again */
+  for (i = 0; problem[i]; i++)
+    solver_disableproblem(solv, problem[i]);
+  POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
+}
+
+
+/*-------------------------------------------------------------------
+ * sorting helper for problems
+ *
+ * bring update rules before job rules
+ * make essential job rules last
+ */
+
+static int
+problems_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Queue *job = dp;
+  Id a = *(Id *)ap, b = *(Id *)bp;
+  if (a < 0 && b > 0)
+    return 1;
+  if (a > 0 && b < 0)
+    return -1;
+  if (a < 0 && b < 0)
+    {
+      int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
+      int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
+      int x = af - bf;
+      if (x)
+       return x;
+    }
+  return a - b;
+}
+
+/*
+ * convert a solution rule into a job modifier
+ */
+static void
+convertsolution(Solver *solv, Id why, Queue *solutionq)
+{
+  Pool *pool = solv->pool;
+  if (why < 0)
+    {
+      queue_push(solutionq, 0);
+      queue_push(solutionq, -why);
+      return;
+    }
+  if (why >= solv->infarchrules && why < solv->infarchrules_end)
+    {
+      Id p, name;
+      /* infarch rule, find replacement */
+      assert(solv->rules[why].p < 0);
+      name = pool->solvables[-solv->rules[why].p].name;
+      while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+       why--;
+      p = 0;
+      for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+       if (solv->decisionmap[-solv->rules[why].p] > 0)
+         {
+           p = -solv->rules[why].p;
+           break;
+         }
+      if (!p)
+       p = -solv->rules[why].p; /* XXX: what to do here? */
+      queue_push(solutionq, SOLVER_SOLUTION_INFARCH);
+      queue_push(solutionq, p);
+      return;
+    }
+  if (why >= solv->duprules && why < solv->duprules_end)
+    {
+      Id p, name;
+      /* dist upgrade rule, find replacement */
+      assert(solv->rules[why].p < 0);
+      name = pool->solvables[-solv->rules[why].p].name;
+      while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
+       why--;
+      p = 0;
+      for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+       if (solv->decisionmap[-solv->rules[why].p] > 0)
+         {
+           p = -solv->rules[why].p;
+           break;
+         }
+      if (!p)
+       p = -solv->rules[why].p; /* XXX: what to do here? */
+      queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
+      queue_push(solutionq, p);
+      return;
+    }
+  if (why >= solv->updaterules && why < solv->updaterules_end)
+    {
+      /* update rule, find replacement package */
+      Id p, *dp, rp = 0;
+      Rule *rr;
+
+      assert(why >= solv->updaterules && why < solv->updaterules_end);
+      /* check if this is a false positive, i.e. the update rule is fulfilled */
+      rr = solv->rules + why;
+      FOR_RULELITERALS(p, dp, rr)
+       if (p > 0 && solv->decisionmap[p] > 0)
+         break;
+      if (p)
+       return;         /* false alarm */
+
+      p = solv->installed->start + (why - solv->updaterules);
+      rr = solv->rules + solv->featurerules + (why - solv->updaterules);
+      if (!rr->p)
+       rr = solv->rules + why;
+      if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
+       {
+         /* distupgrade case, allow to keep old package */
+         queue_push(solutionq, p);
+         queue_push(solutionq, p);
+         return;
+       }
+      if (solv->decisionmap[p] > 0)
+       return;         /* false alarm, turned out we can keep the package */
+      if (rr->w2)
+       {
+         int mvrp = 0;         /* multi-version replacement */
+         FOR_RULELITERALS(rp, dp, rr)
+           {
+             if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
+               {
+                 mvrp = rp;
+                 if (!(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, rp)))
+                   break;
+               }
+           }
+         if (!rp && mvrp)
+           {
+             /* found only multi-version replacements */
+             /* have to split solution into two parts */
+             queue_push(solutionq, p);
+             queue_push(solutionq, mvrp);
+           }
+       }
+      queue_push(solutionq, p);
+      queue_push(solutionq, rp);
+      return;
+    }
+}
+
+/*
+ * convert problem data into a form usable for refining.
+ * Returns the number of problems.
+ */
+int
+solver_prepare_solutions(Solver *solv)
+{
+  int i, j = 1, idx = 1;  
+
+  if (!solv->problems.count)
+    return 0;
+  queue_push(&solv->solutions, 0); 
+  queue_push(&solv->solutions, -1); /* unrefined */
+  for (i = 1; i < solv->problems.count; i++) 
+    {   
+      Id p = solv->problems.elements[i];
+      queue_push(&solv->solutions, p); 
+      if (p) 
+        continue;
+      solv->problems.elements[j++] = idx; 
+      if (i + 1 >= solv->problems.count)
+        break;
+      solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
+      idx = solv->solutions.count;
+      queue_push(&solv->solutions, -1); 
+    }   
+  solv->problems.count = j;  
+  return j / 2;
+}
+
+/*
+ * refine the simple solution rule list provided by
+ * the solver into multiple lists of job modifiers.
+ */
+static void
+create_solutions(Solver *solv, int probnr, int solidx)
+{
+  Pool *pool = solv->pool;
+  Queue redoq;
+  Queue problem, solution, problems_save;
+  int i, j, nsol;
+  int essentialok;
+  int recocount;
+  unsigned int now;
+
+  now = sat_timems(0);
+  recocount = solv->recommendations.count;
+  solv->recommendations.count = 0;     /* so that revert() doesn't mess with it later */
+  queue_init(&redoq);
+  /* save decisionq, decisionq_why, decisionmap */
+  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]);
+    }
+  /* save problems queue */
+  problems_save = solv->problems;
+  memset(&solv->problems, 0, sizeof(solv->problems));
+
+  /* extract problem from queue */
+  queue_init(&problem);
+  for (i = solidx + 1; i < solv->solutions.count; i++)
+    {
+      Id v = solv->solutions.elements[i];
+      if (!v)
+       break;
+      queue_push(&problem, v);
+    }
+  if (problem.count > 1)
+    sat_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
+  queue_push(&problem, 0);     /* mark end for refine_suggestion */
+  problem.count--;
+#if 0
+  for (i = 0; i < problem.count; i++)
+    printf("PP %d %d\n", i, problem.elements[i]);
+#endif
+
+  /* refine each solution element */
+  nsol = 0;
+  essentialok = 0;
+  queue_init(&solution);
+  for (i = 0; i < problem.count; i++)
+    {
+      int solstart = solv->solutions.count;
+      refine_suggestion(solv, problem.elements, problem.elements[i], &solution, essentialok);
+      queue_push(&solv->solutions, 0); /* reserve room for number of elements */
+      for (j = 0; j < solution.count; j++)
+       convertsolution(solv, solution.elements[j], &solv->solutions);
+      if (solv->solutions.count == solstart + 1)
+       {
+         solv->solutions.count--;
+         if (!essentialok && i + 1 == problem.count)
+           {
+             /* nothing found, start over */
+             essentialok = 1;
+             i = -1;
+           }
+         continue;
+       }
+      /* patch in number of solution elements */
+      solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
+      queue_push(&solv->solutions, 0); /* add end marker */
+      queue_push(&solv->solutions, 0); /* add end marker */
+      solv->solutions.elements[solidx + 1 + nsol++] = solstart;
+    }
+  solv->solutions.elements[solidx + 1 + nsol] = 0;     /* end marker */
+  solv->solutions.elements[solidx] = nsol;
+  queue_free(&problem);
+  queue_free(&solution);
+
+  /* restore decisions */
+  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);
+  /* restore problems */
+  queue_free(&solv->problems);
+  solv->problems = problems_save;
+  POOL_DEBUG(SAT_DEBUG_STATS, "create_solutions for problem #%d took %d ms\n", probnr, sat_timems(now));
+}
+
+
+/**************************************************************************/
+
+Id
+solver_problem_count(Solver *solv)
+{
+  return solv->problems.count / 2;
+}
+
+Id
+solver_next_problem(Solver *solv, Id problem)
+{
+  if (!problem)
+    return solv->problems.count ? 1 : 0;
+  return (problem + 1) * 2 - 1 < solv->problems.count ? problem + 1 : 0;
+}
+
+Id
+solver_solution_count(Solver *solv, Id problem)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  if (solv->solutions.elements[solidx] < 0)
+    create_solutions(solv, problem, solidx);
+  return solv->solutions.elements[solidx];
+}
+
+Id
+solver_next_solution(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  if (solv->solutions.elements[solidx] < 0)
+    create_solutions(solv, problem, solidx);
+  return solv->solutions.elements[solidx + solution + 1] ? solution + 1 : 0;
+}
+
+Id
+solver_solutionelement_count(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  return solv->solutions.elements[solidx];
+}
+
+
+/*
+ *  return the next item of the proposed solution
+ *  here are the possibilities for p / rp and what
+ *  the solver expects the application to do:
+ *    p                             rp
+ *  -------------------------------------------------------
+ *    SOLVER_SOLUTION_INFARCH       pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_DISTUPGRADE   pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_JOB           jobidx
+ *    -> remove job (jobidx - 1, jobidx) from job queue
+ *    pkgid (> 0)                   0
+ *    -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
+ *    pkgid (> 0)                   pkgid (> 0)
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *       (this will replace package p)
+ *         
+ * Thus, the solver will either ask the application to remove
+ * a specific job from the job queue, or ask to add an install/erase
+ * job to it.
+ *
+ */
+
+Id
+solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  if (!solidx)
+    return 0;
+  solidx += 1 + element * 2;
+  if (!solv->solutions.elements[solidx] && !solv->solutions.elements[solidx + 1])
+    return 0;
+  *p = solv->solutions.elements[solidx];
+  *rp = solv->solutions.elements[solidx + 1];
+  return element + 1;
+}
+
+/*-------------------------------------------------------------------
+ * 
+ * find problem rule
+ */
+
+static void
+findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
+{
+  Id rid, d;
+  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->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end))
+       {
+         if (!*jobrp)
+           *jobrp = rid;
+       }
+      else if (rid >= solv->updaterules && rid < solv->updaterules_end)
+       {
+         if (!*sysrp)
+           *sysrp = rid;
+       }
+      else
+       {
+         assert(rid < solv->rpmrules_end);
+         r = solv->rules + rid;
+         d = r->d < 0 ? -r->d - 1 : r->d;
+         if (!d && r->w2 < 0)
+           {
+             if (!*conrp)
+               *conrp = rid;
+           }
+         else
+           {
+             if (!d && r->w2 == 0 && !reqassert)
+               {
+                 if (*reqrp > 0 && r->p < -1)
+                   {
+                     Id op = -solv->rules[*reqrp].p;
+                     if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
+                       continue;       /* different arch, skip */
+                   }
+                 /* prefer assertions */
+                 *reqrp = rid;
+                 reqassert = 1;
+               }
+             if (!*reqrp)
+               *reqrp = rid;
+             else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && !reqassert)
+               {
+                 /* prefer rules of installed packages */
+                 *reqrp = rid;
+               }
+           }
+       }
+    }
+  if (!*reqrp && lreqr)
+    *reqrp = lreqr;
+  if (!*conrp && lconr)
+    *conrp = lconr;
+  if (!*jobrp && ljobr)
+    *jobrp = ljobr;
+  if (!*sysrp && lsysr)
+    *sysrp = lsysr;
+}
+
+/* 
+ * find problem rule
+ *
+ * search for a rule that describes the problem to the
+ * user. Actually a pretty hopeless task that may leave the user
+ * puzzled. To get all of the needed information use
+ * solver_findallproblemrules() instead.
+ */
+
+Id
+solver_findproblemrule(Solver *solv, Id problem)
+{
+  Id reqr, conr, sysr, jobr;
+  Id idx = solv->problems.elements[2 * problem - 2];
+  reqr = conr = sysr = jobr = 0;
+  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
+  if (reqr)
+    return reqr;       /* some requires */
+  if (conr)
+    return conr;       /* some conflict */
+  if (sysr)
+    return sysr;       /* an update rule */
+  if (jobr)
+    return jobr;       /* a user request */
+  assert(0);
+}
+
+/*-------------------------------------------------------------------*/
+
+static void
+findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
+{
+  Id rid;
+  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
+    {
+      if (rid >= solv->learntrules)
+        {
+         findallproblemrules_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], rules);
+          continue;
+       }
+      queue_pushunique(rules, rid);
+    }
+}
+
+/*
+ * find all problem rule
+ *
+ * return all rules that lead to the problem. This gives the user
+ * all of the information to understand the problem, but the result
+ * can be a large number of rules.
+ */
+
+void
+solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
+{
+  queue_empty(rules);
+  findallproblemrules_internal(solv, solv->problems.elements[2 * problem - 2], rules);
+}
+
+/* obsolete function */
+SolverRuleinfo
+solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
+{
+  return solver_ruleinfo(solv, rid, sourcep, targetp, depp);
+}
+
+/* EOF */
diff --git a/src/problems.h b/src/problems.h
new file mode 100644 (file)
index 0000000..fad8834
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * problems.h
+ *
+ */
+
+#ifndef SATSOLVER_PROBLEMS_H
+#define SATSOLVER_PROBLEMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct _Solver;
+
+#define SOLVER_SOLUTION_JOB             (0)
+#define SOLVER_SOLUTION_DISTUPGRADE     (-1)
+#define SOLVER_SOLUTION_INFARCH         (-2)
+
+void solver_disableproblem(struct _Solver *solv, Id v);
+void solver_enableproblem(struct _Solver *solv, Id v);
+int solver_prepare_solutions(struct _Solver *solv);
+
+Id solver_problem_count(struct _Solver *solv);
+Id solver_next_problem(struct _Solver *solv, Id problem);
+Id solver_solution_count(struct _Solver *solv, Id problem);
+Id solver_next_solution(struct _Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_count(struct _Solver *solv, Id problem, Id solution);
+Id solver_next_solutionelement(struct _Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
+
+Id solver_findproblemrule(struct _Solver *solv, Id problem);
+void solver_findallproblemrules(struct _Solver *solv, Id problem, Queue *rules);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 6740371..345050f 100644 (file)
@@ -17,7 +17,7 @@
 #include "util.h"
 
 void
-queue_clone(Queue *t, Queue *s)
+queue_init_clone(Queue *t, Queue *s)
 {
   t->alloc = t->elements = sat_malloc2(s->count + 8, sizeof(Id));
   if (s->count)
index 4350d92..4b3f9eb 100644 (file)
 #include "pooltypes.h"
 
 typedef struct _Queue {
-  Id *elements;                // current elements
-  int count;           // current number of elements (minimal size for elements pointer)
-  Id *alloc;           // this is whats actually allocated, elements > alloc if shifted
-  int left;            // space left in alloc *after* elements+count
+  Id *elements;                /* pointer to elements */
+  int count;           /* current number of elements in queue */
+  Id *alloc;           /* this is whats actually allocated, elements > alloc if shifted */
+  int left;            /* space left in alloc *after* elements+count */
 } Queue;
 
 
 extern void queue_alloc_one(Queue *q);
 
-// clear queue
+/* clear queue */
 static inline void
 queue_empty(Queue *q)
 {
@@ -48,6 +48,33 @@ queue_shift(Queue *q)
   return *q->elements++;
 }
 
+static inline Id
+queue_pop(Queue *q)
+{
+  if (!q->count)
+    return 0;
+  q->left++;
+  return q->elements[--q->count];
+}
+
+static inline void
+queue_unshift(Queue *q, Id id)
+{
+  if (q->alloc && q->alloc != q->elements)
+    {
+      *--q->elements = id;
+      q->count++;
+      return;
+    }
+  if (!q->left)
+    queue_alloc_one(q);
+  if (q->count)
+    memmove(q->elements + 1, q->elements, sizeof(Id) * q->count);
+  q->count++;
+  q->elements[0] = id;
+  q->left--;
+}
+
 static inline void
 queue_push(Queue *q, Id id)
 {
@@ -67,9 +94,16 @@ queue_pushunique(Queue *q, Id id)
   queue_push(q, id);
 }
 
-extern void queue_clone(Queue *t, Queue *s);
+static inline void
+queue_push2(Queue *q, Id id1, Id id2)
+{
+  queue_push(q, id1);
+  queue_push(q, id2);
+}
+
 extern void queue_init(Queue *q);
 extern void queue_init_buffer(Queue *q, Id *buf, int size);
+extern void queue_init_clone(Queue *t, Queue *s);
 extern void queue_free(Queue *q);
 
 #endif /* SATSOLVER_QUEUE_H */
index 8762540..5854e1e 100644 (file)
@@ -27,8 +27,6 @@
 
 #define RULES_BLOCK 63
 
-static void reenablepolicyrules(Solver *solv, int jobidx);
-
 /********************************************************************
  *
  * dependency check helpers
@@ -98,110 +96,6 @@ solver_dep_installed(Solver *solv, Id dep)
 
 
 
-/**********************************************************************************/
-
-/* a problem is an item on the solver's problem list. It can either be >0, in that
- * case it is a update/infarch/dup rule, or it can be <0, which makes it refer to a job
- * consisting of multiple job rules.
- */
-
-static void
-disableproblem(Solver *solv, Id v)
-{
-  Rule *r;
-  int i;
-  Id *jp;
-
-  if (v > 0)
-    {
-      if (v >= solv->infarchrules && v < solv->infarchrules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_disablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->duprules && v < solv->duprules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_disablerule(solv, solv->rules + v);
-         return;
-       }
-      solver_disablerule(solv, solv->rules + v);
-      return;
-    }
-  v = -(v + 1);
-  jp = solv->ruletojob.elements;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
-    if (*jp == v)
-      solver_disablerule(solv, r);
-}
-
-/*-------------------------------------------------------------------
- * enableproblem
- */
-
-static void
-enableproblem(Solver *solv, Id v)
-{
-  Rule *r;
-  int i;
-  Id *jp;
-
-  if (v > 0)
-    {
-      if (v >= solv->infarchrules && v < solv->infarchrules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_enablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->duprules && v < solv->duprules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_enablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->featurerules && v < solv->featurerules_end)
-       {
-         /* do not enable feature rule if update rule is enabled */
-         r = solv->rules + (v - solv->featurerules + solv->updaterules);
-         if (r->d >= 0)
-           return;
-       }
-      solver_enablerule(solv, solv->rules + v);
-      if (v >= solv->updaterules && v < solv->updaterules_end)
-       {
-         /* disable feature rule when enabling update rule */
-         r = solv->rules + (v - solv->updaterules + solv->featurerules);
-         if (r->p)
-           solver_disablerule(solv, r);
-       }
-      return;
-    }
-  v = -(v + 1);
-  jp = solv->ruletojob.elements;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
-    if (*jp == v)
-      solver_enablerule(solv, r);
-}
-
-
 /************************************************************************/
 
 /*
@@ -313,7 +207,7 @@ makeruledecisions(Solver *solv)
          v = ri;
        queue_push(&solv->problems, v);
        queue_push(&solv->problems, 0);
-       disableproblem(solv, v);
+       solver_disableproblem(solv, v);
        continue;
       }
 
@@ -338,7 +232,7 @@ makeruledecisions(Solver *solv)
            v = ri;
          queue_push(&solv->problems, v);
          queue_push(&solv->problems, 0);
-         disableproblem(solv, v);
+         solver_disableproblem(solv, v);
          continue;
        }
 
@@ -380,7 +274,7 @@ makeruledecisions(Solver *solv)
            v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
            
          queue_push(&solv->problems, v);
-         disableproblem(solv, v);
+         solver_disableproblem(solv, v);
        }
       queue_push(&solv->problems, 0);
 
@@ -445,9 +339,9 @@ makeruledecisions(Solver *solv)
        v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
       else
        v = ri;
-      disableproblem(solv, v);
+      solver_disableproblem(solv, v);
       if (v < 0)
-       reenablepolicyrules(solv, -(v + 1));
+       solver_reenablepolicyrules(solv, -(v + 1));
     }
   
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- makeruledecisions end; size decisionq: %d -----\n",solv->decisionq.count);
@@ -503,30 +397,6 @@ enabledisablelearntrules(Solver *solv)
 
 
 /*-------------------------------------------------------------------
- * enable weak rules
- * 
- * Reenable all disabled weak rules (marked in weakrulemap)
- * 
- */
-
-static void
-enableweakrules(Solver *solv)
-{
-  int i;
-  Rule *r;
-
-  for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
-    {
-      if (r->d >= 0) /* already enabled? */
-       continue;
-      if (!MAPTST(&solv->weakrulemap, i))
-       continue;
-      solver_enablerule(solv, r);
-    }
-}
-
-
-/*-------------------------------------------------------------------
  * policy rule enabling/disabling
  *
  * we need to disable policy rules that conflict with our job list, and
@@ -750,8 +620,8 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
 }
 
 /* disable all policy rules that are in conflict with our job list */
-static void
-disablepolicyrules(Solver *solv)
+void
+solver_disablepolicyrules(Solver *solv)
 {
   Queue *job = &solv->job;
   int i, j;
@@ -797,8 +667,8 @@ disablepolicyrules(Solver *solv)
 
 /* we just disabled job #jobidx, now reenable all policy rules that were
  * disabled because of this job */
-static void
-reenablepolicyrules(Solver *solv, int jobidx)
+void
+solver_reenablepolicyrules(Solver *solv, int jobidx)
 {
   Queue *job = &solv->job;
   int i, j;
@@ -1371,14 +1241,14 @@ l1retry:
 
 /*-------------------------------------------------------------------
  * 
- * reset_solver
+ * solver_reset
  * 
  * reset the solver decisions to right after the rpm rules.
  * called after rules have been enabled/disabled
  */
 
-static void
-reset_solver(Solver *solv)
+void
+solver_reset(Solver *solv)
 {
   Pool *pool = solv->pool;
   int i;
@@ -1394,6 +1264,8 @@ reset_solver(Solver *solv)
   solv->decisionq.count = 0;
   solv->recommends_index = -1;
   solv->propagate_index = 0;
+  solv->recommendations.count = 0;
+  solv->branches.count = 0;
 
   /* adapt learnt rule status to new set of enabled/disabled rules */
   enabledisablelearntrules(solv);
@@ -1565,10 +1437,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
         v = lastweak;
       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling ");
       solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, solv->rules + lastweak);
-      disableproblem(solv, v);
+      solver_disableproblem(solv, v);
       if (v < 0)
-       reenablepolicyrules(solv, -(v + 1));
-      reset_solver(solv);
+       solver_reenablepolicyrules(solv, -(v + 1));
+      solver_reset(solv);
       return 1;
     }
 
@@ -1579,9 +1451,9 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
   if (disablerules)
     {
       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
-        disableproblem(solv, solv->problems.elements[i]);
+        solver_disableproblem(solv, solv->problems.elements[i]);
       /* XXX: might want to enable all weak rules again */
-      reset_solver(solv);
+      solver_reset(solv);
       return 1;
     }
   POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
@@ -1888,14 +1760,14 @@ solver_free(Solver *solv)
 
 /*-------------------------------------------------------------------
  * 
- * run_solver
+ * solver_run_sat
  *
  * all rules have been set up, now actually run the solver
  *
  */
 
-static void
-run_solver(Solver *solv, int disablerules, int doweak)
+void
+solver_run_sat(Solver *solv, int disablerules, int doweak)
 {
   Queue dq;            /* local decisionqueue */
   Queue dqs;           /* local decisionqueue for supplements */
@@ -2593,665 +2465,6 @@ run_solver(Solver *solv, int disablerules, int doweak)
 
 /*-------------------------------------------------------------------
  * 
- * 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
-refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Id v;
-  Queue disabled;
-  int disabledcnt;
-
-  IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
-    {
-      POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion start\n");
-      for (i = 0; problem[i]; i++)
-       {
-         if (problem[i] == sug)
-           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "=> ");
-         solver_printproblem(solv, problem[i]);
-       }
-    }
-  queue_empty(refined);
-  if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
-    return;
-  queue_init(&disabled);
-  queue_push(refined, sug);
-
-  /* re-enable all problem rules with the exception of "sug"(gestion) */
-  revert(solv, 1);
-  reset_solver(solv);
-
-  for (i = 0; problem[i]; i++)
-    if (problem[i] != sug)
-      enableproblem(solv, problem[i]);
-
-  if (sug < 0)
-    reenablepolicyrules(solv, -(sug + 1));
-  else if (sug >= solv->updaterules && sug < solv->updaterules_end)
-    {
-      /* enable feature rule */
-      Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
-      if (r->p)
-       solver_enablerule(solv, r);
-    }
-
-  enableweakrules(solv);
-
-  for (;;)
-    {
-      int njob, nfeature, nupdate;
-      queue_empty(&solv->problems);
-      revert(solv, 1);         /* XXX no longer needed? */
-      reset_solver(solv);
-
-      if (!solv->problems.count)
-        run_solver(solv, 0, 0);
-
-      if (!solv->problems.count)
-       {
-         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no more problems!\n");
-         IF_POOLDEBUG (SAT_DEBUG_SCHUBI)
-           solver_printdecisions(solv);
-         break;                /* great, no more problems */
-       }
-      disabledcnt = disabled.count;
-      /* start with 1 to skip over proof index */
-      njob = nfeature = nupdate = 0;
-      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;
-         if (problem[j])
-           continue;
-         if (v >= solv->featurerules && v < solv->featurerules_end)
-           nfeature++;
-         else if (v > 0)
-           nupdate++;
-         else
-           {
-             if (!essentialok && (solv->job.elements[-v -1] & SOLVER_ESSENTIAL) != 0)
-               continue;       /* not that one! */
-             njob++;
-           }
-         queue_push(&disabled, v);
-       }
-      if (disabled.count == disabledcnt)
-       {
-         /* no solution found, this was an invalid suggestion! */
-         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "no solution found!\n");
-         refined->count = 0;
-         break;
-       }
-      if (!njob && nupdate && nfeature)
-       {
-         /* got only update rules, filter out feature rules */
-         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "throwing away feature rules\n");
-         for (i = j = disabledcnt; i < disabled.count; i++)
-           {
-             v = disabled.elements[i];
-             if (v < solv->featurerules || v >= solv->featurerules_end)
-               disabled.elements[j++] = v;
-           }
-         disabled.count = j;
-         nfeature = 0;
-       }
-      if (disabled.count == disabledcnt + 1)
-       {
-         /* just one suggestion, add it to refined list */
-         v = disabled.elements[disabledcnt];
-         if (!nfeature)
-           queue_push(refined, v);     /* do not record feature rules */
-         disableproblem(solv, v);
-         if (v >= solv->updaterules && v < solv->updaterules_end)
-           {
-             Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
-             if (r->p)
-               solver_enablerule(solv, r);     /* enable corresponding feature rule */
-           }
-         if (v < 0)
-           reenablepolicyrules(solv, -(v + 1));
-       }
-      else
-       {
-         /* more than one solution, disable all */
-         /* do not push anything on refine list, as we do not know which solution to choose */
-         /* thus, the user will get another problem if he selects this solution, where he
-           * can choose the right one */
-         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "more than one solution found:\n");
-             for (i = disabledcnt; i < disabled.count; i++)
-               solver_printproblem(solv, disabled.elements[i]);
-           }
-         for (i = disabledcnt; i < disabled.count; i++)
-           {
-             v = disabled.elements[i];
-             disableproblem(solv, v);
-             if (v >= solv->updaterules && v < solv->updaterules_end)
-               {
-                 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
-                 if (r->p)
-                   solver_enablerule(solv, r);
-               }
-           }
-       }
-    }
-  /* all done, get us back into the same state as before */
-  /* enable refined rules again */
-  for (i = 0; i < disabled.count; i++)
-    enableproblem(solv, disabled.elements[i]);
-  queue_free(&disabled);
-  /* reset policy rules */
-  for (i = 0; problem[i]; i++)
-    enableproblem(solv, problem[i]);
-  disablepolicyrules(solv);
-  /* disable problem rules again */
-  for (i = 0; problem[i]; i++)
-    disableproblem(solv, problem[i]);
-  POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "refine_suggestion end\n");
-}
-
-
-/*-------------------------------------------------------------------
- * sorting helper for problems
- *
- * bring update rules before job rules
- * make essential job rules last
- */
-
-static int
-problems_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Queue *job = dp;
-  Id a = *(Id *)ap, b = *(Id *)bp;
-  if (a < 0 && b > 0)
-    return 1;
-  if (a > 0 && b < 0)
-    return -1;
-  if (a < 0 && b < 0)
-    {
-      int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
-      int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
-      int x = af - bf;
-      if (x)
-       return x;
-    }
-  return a - b;
-}
-
-/*
- * convert a solution rule into a job modifier
- */
-static void
-convertsolution(Solver *solv, Id why, Queue *solutionq)
-{
-  Pool *pool = solv->pool;
-  if (why < 0)
-    {
-      queue_push(solutionq, 0);
-      queue_push(solutionq, -why);
-      return;
-    }
-  if (why >= solv->infarchrules && why < solv->infarchrules_end)
-    {
-      Id p, name;
-      /* infarch rule, find replacement */
-      assert(solv->rules[why].p < 0);
-      name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-      p = 0;
-      for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
-       if (solv->decisionmap[-solv->rules[why].p] > 0)
-         {
-           p = -solv->rules[why].p;
-           break;
-         }
-      if (!p)
-       p = -solv->rules[why].p; /* XXX: what to do here? */
-      queue_push(solutionq, SOLVER_SOLUTION_INFARCH);
-      queue_push(solutionq, p);
-      return;
-    }
-  if (why >= solv->duprules && why < solv->duprules_end)
-    {
-      Id p, name;
-      /* dist upgrade rule, find replacement */
-      assert(solv->rules[why].p < 0);
-      name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-      p = 0;
-      for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
-       if (solv->decisionmap[-solv->rules[why].p] > 0)
-         {
-           p = -solv->rules[why].p;
-           break;
-         }
-      if (!p)
-       p = -solv->rules[why].p; /* XXX: what to do here? */
-      queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
-      queue_push(solutionq, p);
-      return;
-    }
-  if (why >= solv->updaterules && why < solv->updaterules_end)
-    {
-      /* update rule, find replacement package */
-      Id p, *dp, rp = 0;
-      Rule *rr;
-
-      assert(why >= solv->updaterules && why < solv->updaterules_end);
-      /* check if this is a false positive, i.e. the update rule is fulfilled */
-      rr = solv->rules + why;
-      FOR_RULELITERALS(p, dp, rr)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (p)
-       return;         /* false alarm */
-
-      p = solv->installed->start + (why - solv->updaterules);
-      rr = solv->rules + solv->featurerules + (why - solv->updaterules);
-      if (!rr->p)
-       rr = solv->rules + why;
-      if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
-       {
-         /* distupgrade case, allow to keep old package */
-         queue_push(solutionq, p);
-         queue_push(solutionq, p);
-         return;
-       }
-      if (solv->decisionmap[p] > 0)
-       return;         /* false alarm, turned out we can keep the package */
-      if (rr->w2)
-       {
-         int mvrp = 0;         /* multi-version replacement */
-         FOR_RULELITERALS(rp, dp, rr)
-           {
-             if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
-               {
-                 mvrp = rp;
-                 if (!(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, rp)))
-                   break;
-               }
-           }
-         if (!rp && mvrp)
-           {
-             /* found only multi-version replacements */
-             /* have to split solution into two parts */
-             queue_push(solutionq, p);
-             queue_push(solutionq, mvrp);
-           }
-       }
-      queue_push(solutionq, p);
-      queue_push(solutionq, rp);
-      return;
-    }
-}
-
-/*
- * convert problem data into a form usable for refining.
- * Returns the number of problems.
- */
-static int
-prepare_solutions(Solver *solv)
-{
-  int i, j = 1, idx = 1;  
-
-  if (!solv->problems.count)
-    return 0;
-  queue_push(&solv->solutions, 0); 
-  queue_push(&solv->solutions, -1); /* unrefined */
-  for (i = 1; i < solv->problems.count; i++) 
-    {   
-      Id p = solv->problems.elements[i];
-      queue_push(&solv->solutions, p); 
-      if (p) 
-        continue;
-      solv->problems.elements[j++] = idx; 
-      if (i + 1 >= solv->problems.count)
-        break;
-      solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
-      idx = solv->solutions.count;
-      queue_push(&solv->solutions, -1); 
-    }   
-  solv->problems.count = j;  
-  return j / 2;
-}
-
-/*
- * refine the simple solution rule list provided by
- * the solver into multiple lists of job modifiers.
- */
-static void
-create_solutions(Solver *solv, int probnr, int solidx)
-{
-  Pool *pool = solv->pool;
-  Queue redoq;
-  Queue problem, solution, problems_save;
-  int i, j, nsol;
-  int essentialok;
-  int recocount;
-  unsigned int now;
-
-  now = sat_timems(0);
-  recocount = solv->recommendations.count;
-  solv->recommendations.count = 0;     /* so that revert() doesn't mess with it */
-  queue_init(&redoq);
-  /* save decisionq, decisionq_why, decisionmap */
-  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]);
-    }
-  /* save problems queue */
-  problems_save = solv->problems;
-  memset(&solv->problems, 0, sizeof(solv->problems));
-
-  /* extract problem from queue */
-  queue_init(&problem);
-  for (i = solidx + 1; i < solv->solutions.count; i++)
-    {
-      Id v = solv->solutions.elements[i];
-      if (!v)
-       break;
-      queue_push(&problem, v);
-    }
-  if (problem.count > 1)
-    sat_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
-  queue_push(&problem, 0);     /* mark end for refine_suggestion */
-  problem.count--;
-#if 0
-  for (i = 0; i < problem.count; i++)
-    printf("PP %d %d\n", i, problem.elements[i]);
-#endif
-
-  /* refine each solution element */
-  nsol = 0;
-  essentialok = 0;
-  queue_init(&solution);
-  for (i = 0; i < problem.count; i++)
-    {
-      int solstart = solv->solutions.count;
-      refine_suggestion(solv, problem.elements, problem.elements[i], &solution, essentialok);
-      queue_push(&solv->solutions, 0); /* reserve room for number of elements */
-      for (j = 0; j < solution.count; j++)
-       convertsolution(solv, solution.elements[j], &solv->solutions);
-      if (solv->solutions.count == solstart + 1)
-       {
-         solv->solutions.count--;
-         if (!essentialok && i + 1 == problem.count)
-           {
-             /* nothing found, start over */
-             essentialok = 1;
-             i = -1;
-           }
-         continue;
-       }
-      /* patch in number of solution elements */
-      solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
-      queue_push(&solv->solutions, 0); /* add end marker */
-      queue_push(&solv->solutions, 0); /* add end marker */
-      solv->solutions.elements[solidx + 1 + nsol++] = solstart;
-    }
-  solv->solutions.elements[solidx + 1 + nsol] = 0;     /* end marker */
-  solv->solutions.elements[solidx] = nsol;
-  queue_free(&problem);
-  queue_free(&solution);
-
-  /* restore decisions */
-  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);
-  /* restore problems */
-  queue_free(&solv->problems);
-  solv->problems = problems_save;
-  POOL_DEBUG(SAT_DEBUG_STATS, "create_solutions for problem #%d took %d ms\n", probnr, sat_timems(now));
-}
-
-
-/**************************************************************************/
-
-Id
-solver_problem_count(Solver *solv)
-{
-  return solv->problems.count / 2;
-}
-
-Id
-solver_next_problem(Solver *solv, Id problem)
-{
-  if (!problem)
-    return solv->problems.count ? 1 : 0;
-  return (problem + 1) * 2 - 1 < solv->problems.count ? problem + 1 : 0;
-}
-
-Id
-solver_solution_count(Solver *solv, Id problem)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  if (solv->solutions.elements[solidx] < 0)
-    create_solutions(solv, problem, solidx);
-  return solv->solutions.elements[solidx];
-}
-
-Id
-solver_next_solution(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  if (solv->solutions.elements[solidx] < 0)
-    create_solutions(solv, problem, solidx);
-  return solv->solutions.elements[solidx + solution + 1] ? solution + 1 : 0;
-}
-
-Id
-solver_solutionelement_count(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  return solv->solutions.elements[solidx];
-}
-
-
-/*
- *  return the next item of the proposed solution
- *  here are the possibilities for p / rp and what
- *  the solver expects the application to do:
- *    p                             rp
- *  -------------------------------------------------------
- *    SOLVER_SOLUTION_INFARCH       pkgid
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *    SOLVER_SOLUTION_DISTUPGRADE   pkgid
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *    SOLVER_SOLUTION_JOB           jobidx
- *    -> remove job (jobidx - 1, jobidx) from job queue
- *    pkgid (> 0)                   0
- *    -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
- *    pkgid (> 0)                   pkgid (> 0)
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *       (this will replace package p)
- *         
- * Thus, the solver will either ask the application to remove
- * a specific job from the job queue, or ask to add an install/erase
- * job to it.
- *
- */
-
-Id
-solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  if (!solidx)
-    return 0;
-  solidx += 1 + element * 2;
-  if (!solv->solutions.elements[solidx] && !solv->solutions.elements[solidx + 1])
-    return 0;
-  *p = solv->solutions.elements[solidx];
-  *rp = solv->solutions.elements[solidx + 1];
-  return element + 1;
-}
-
-/*-------------------------------------------------------------------
- * 
- * find problem rule
- */
-
-static void
-findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp)
-{
-  Id rid, d;
-  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->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end))
-       {
-         if (!*jobrp)
-           *jobrp = rid;
-       }
-      else if (rid >= solv->updaterules && rid < solv->updaterules_end)
-       {
-         if (!*sysrp)
-           *sysrp = rid;
-       }
-      else
-       {
-         assert(rid < solv->rpmrules_end);
-         r = solv->rules + rid;
-         d = r->d < 0 ? -r->d - 1 : r->d;
-         if (!d && r->w2 < 0)
-           {
-             if (!*conrp)
-               *conrp = rid;
-           }
-         else
-           {
-             if (!d && r->w2 == 0 && !reqassert)
-               {
-                 if (*reqrp > 0 && r->p < -1)
-                   {
-                     Id op = -solv->rules[*reqrp].p;
-                     if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
-                       continue;       /* different arch, skip */
-                   }
-                 /* prefer assertions */
-                 *reqrp = rid;
-                 reqassert = 1;
-               }
-             if (!*reqrp)
-               *reqrp = rid;
-             else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && !reqassert)
-               {
-                 /* prefer rules of installed packages */
-                 *reqrp = rid;
-               }
-           }
-       }
-    }
-  if (!*reqrp && lreqr)
-    *reqrp = lreqr;
-  if (!*conrp && lconr)
-    *conrp = lconr;
-  if (!*jobrp && ljobr)
-    *jobrp = ljobr;
-  if (!*sysrp && lsysr)
-    *sysrp = lsysr;
-}
-
-/* 
- * find problem rule
- *
- * search for a rule that describes the problem to the
- * user. Actually a pretty hopeless task that may leave the user
- * puzzled. To get all of the needed information use
- * solver_findallproblemrules() instead.
- */
-
-Id
-solver_findproblemrule(Solver *solv, Id problem)
-{
-  Id reqr, conr, sysr, jobr;
-  Id idx = solv->problems.elements[2 * problem - 2];
-  reqr = conr = sysr = jobr = 0;
-  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
-  if (reqr)
-    return reqr;       /* some requires */
-  if (conr)
-    return conr;       /* some conflict */
-  if (sysr)
-    return sysr;       /* an update rule */
-  if (jobr)
-    return jobr;       /* a user request */
-  assert(0);
-}
-
-/*-------------------------------------------------------------------*/
-
-static void
-findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
-{
-  Id rid;
-  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
-    {
-      if (rid >= solv->learntrules)
-        {
-         findallproblemrules_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], rules);
-          continue;
-       }
-      queue_pushunique(rules, rid);
-    }
-}
-
-/*
- * find all problem rule
- *
- * return all rules that lead to the problem. This gives the user
- * all of the information to understand the problem, but the result
- * can be a large number of rules.
- */
-
-void
-solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
-{
-  queue_empty(rules);
-  findallproblemrules_internal(solv, solv->problems.elements[2 * problem - 2], rules);
-}
-
-
-/*-------------------------------------------------------------------
- * 
  * remove disabled conflicts
  *
  * purpose: update the decisionmap after some rules were disabled.
@@ -3831,7 +3044,7 @@ solver_solve(Solver *solv, Queue *job)
 
   /* remember job */
   queue_free(&solv->job);
-  queue_clone(&solv->job, job);
+  queue_init_clone(&solv->job, job);
 
   /*
    * create basic rule set of all involved packages
@@ -3841,7 +3054,7 @@ solver_solve(Solver *solv, Queue *job)
   /* create noobsolete map if needed */
   for (i = 0; i < job->count; i += 2)
     {
-      how = job->elements[i] & ~SOLVER_WEAK;
+      how = job->elements[i];
       if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
        continue;
       what = job->elements[i + 1];
@@ -3910,16 +3123,23 @@ solver_solve(Solver *solv, Queue *job)
     }
   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
 
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for recommended/suggested packages ***\n");
-
-  oldnrules = solv->nrules;
     
-    /*
-     * add rules for suggests, enhances
-     */
+  /*
+   * add rules for suggests, enhances
+   */
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for suggested/enhanced packages ***\n");
+  oldnrules = solv->nrules;
   solver_addrpmrulesforweak(solv, &addedmap);
   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
 
+  /*
+   * first pass done, we now have all the rpm rules we need.
+   * unify existing rules before going over all job rules and
+   * policy rules.
+   * at this point the system is always solvable,
+   * as an empty system (remove all packages) is a valid solution
+   */
+
   IF_POOLDEBUG (SAT_DEBUG_STATS)
     {
       int possible = 0, installable = 0;
@@ -3933,16 +3153,7 @@ solver_solve(Solver *solv, Queue *job)
       POOL_DEBUG(SAT_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
     }
 
-  /*
-   * first pass done, we now have all the rpm rules we need.
-   * unify existing rules before going over all job rules and
-   * policy rules.
-   * at this point the system is always solvable,
-   * as an empty system (remove all packages) is a valid solution
-   */
-
   solver_unifyrules(solv);                          /* remove duplicate rpm rules */
-
   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
 
   POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule memory usage: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
@@ -3969,7 +3180,7 @@ solver_solve(Solver *solv, Queue *job)
   solv->featurerules = solv->nrules;              /* mark start of feature rules */
   if (installed)
     {
-       /* foreach possibly installed solvable */
+      /* foreach possibly installed solvable */
       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
        {
          if (s->repo != installed)
@@ -3979,11 +3190,7 @@ solver_solve(Solver *solv, Queue *job)
            }
          addupdaterule(solv, s, 1);    /* allow s to be updated */
        }
-       /*
-        * assert one rule per installed solvable,
-        * either an assertion (A)
-        * or a possible update (A|update1(A)|update2(A)|...)
-        */
+      /* make sure we accounted for all rules */
       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
     }
   solv->featurerules_end = solv->nrules;
@@ -4011,9 +3218,9 @@ solver_solve(Solver *solv, Queue *job)
              continue;
            }
          addupdaterule(solv, s, 0);    /* allowall = 0: downgrades not allowed */
-           /*
-            * check for and remove duplicate
-            */
+         /*
+          * check for and remove duplicate
+          */
          r = solv->rules + solv->nrules - 1;           /* r: update rule */
          sr = r - (installed->end - installed->start); /* sr: feature rule */
          /* it's orphaned if there is no feature rule or the feature rule
@@ -4244,7 +3451,7 @@ solver_solve(Solver *solv, Queue *job)
       queue_push(&solv->ruleassertions, i);
 
   /* disable update rules that conflict with our job */
-  disablepolicyrules(solv);
+  solver_disablepolicyrules(solv);
 
   /* make decisions based on job/update assertions */
   makeruledecisions(solv);
@@ -4257,7 +3464,7 @@ solver_solve(Solver *solv, Queue *job)
    */
     
   now = sat_timems(0);
-  run_solver(solv, 1, solv->dontinstallrecommended ? 0 : 1);
+  solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
   POOL_DEBUG(SAT_DEBUG_STATS, "solver took %d ms\n", sat_timems(now));
 
   /*
@@ -4268,7 +3475,7 @@ solver_solve(Solver *solv, Queue *job)
   /*
    * prepare solution queue if there were problems
    */
-  prepare_solutions(solv);
+  solver_prepare_solutions(solv);
 
   /*
    * finally prepare transaction info
@@ -4558,12 +3765,3 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
 }
 #endif
 
-
-/* obsolete function */
-SolverRuleinfo
-solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
-{
-  return solver_ruleinfo(solv, rid, sourcep, targetp, depp);
-}
-
-/* EOF */
index 446d106..aaf0bea 100644 (file)
@@ -24,6 +24,7 @@ extern "C" {
 #include "bitmap.h"
 #include "transaction.h"
 #include "rules.h"
+#include "problems.h"
 
 /*
  * Callback definitions in order to "overwrite" the policies by an external application.
@@ -264,26 +265,19 @@ typedef struct _Solver {
 #define SOLVER_PROBLEM_INFARCH_RULE            SOLVER_RULE_INFARCH
 
 
-#define SOLVER_SOLUTION_JOB            (0)
-#define SOLVER_SOLUTION_DISTUPGRADE    (-1)
-#define SOLVER_SOLUTION_INFARCH                (-2)
-
 extern Solver *solver_create(Pool *pool);
 extern void solver_free(Solver *solv);
 extern void solver_solve(Solver *solv, Queue *job);
 
+extern void solver_run_sat(Solver *solv, int disablerules, int doweak);
+extern void solver_reset(Solver *solv);
+extern void solver_reenablepolicyrules(Solver *solv, int jobidx);
+extern void solver_disablepolicyrules(Solver *solv);
+
 extern int solver_dep_installed(Solver *solv, Id dep);
 extern int solver_splitprovides(Solver *solv, Id dep);
 
-extern Id solver_problem_count(Solver *solv);
-extern Id solver_next_problem(Solver *solv, Id problem);
-extern Id solver_solution_count(Solver *solv, Id problem);
-extern Id solver_next_solution(Solver *solv, Id problem, Id solution);
-extern Id solver_solutionelement_count(Solver *solv, Id problem, Id solution);
-extern Id solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
-extern Id solver_findproblemrule(Solver *solv, Id problem);
-extern void solver_findallproblemrules(Solver *solv, Id problem, Queue *rules);
-
+/* obsolete */
 extern SolverRuleinfo solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp);
 
 /* XXX: why is this not static? */