]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Rename merge state to "bits" and put it into the decision info
authorMichael Schroeder <mls@suse.de>
Wed, 7 Dec 2022 12:37:40 +0000 (13:37 +0100)
committerMichael Schroeder <mls@suse.de>
Wed, 7 Dec 2022 12:37:40 +0000 (13:37 +0100)
This makes the returned decision with extra data consist of:
(decision, reason, info, bits, type, from, to, dep)

Merging and printing needs the bits anyway, so providing it
right away makes things easier.

Also add a new SOLVER_DECISIONLIST_MERGEDINFO flag with returnes
"merged" decisions. This is just the "bits" part, the rest
of the decision data stays unchanged.

A new solver_decisionlist_solvables() helper can be used
to return all the decision solvables of a merged or unmerged decision.

src/decision.c
src/libsolv.ver
src/solver.h

index 4d34259d6aed9c176d18bcb730290945dca36daa..7a60b2d903182f2d404ef3b6bb20e818eac32a11 100644 (file)
@@ -255,14 +255,14 @@ decisionsort(const void *va, const void *vb, void *vd)
 {
   Solver *solv = vd;
   Pool *pool = solv->pool;
-  const Id *a = va, *b = vb;   /* (decision, reason, rid, type, from, to, dep) */
+  const Id *a = va, *b = vb;   /* (decision, reason, rid, bits, type, from, to, dep) */
   Solvable *as, *bs;
-  if (a[3] != b[3])    /* rule type */
-    return a[3] - b[3];
-  if (a[6] != b[6])    /* dep id */
-    return a[6] - b[6];
-  as = pool->solvables + a[4];
-  bs = pool->solvables + b[4];
+  if (a[4] != b[4])    /* type */
+    return a[4] - b[4];
+  if (a[7] != b[7])    /* dep id */
+    return a[7] - b[7];
+  as = pool->solvables + a[5];
+  bs = pool->solvables + b[5];
   if (as->name != bs->name)
     return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
   if (as->evr != bs->evr)
@@ -271,8 +271,8 @@ decisionsort(const void *va, const void *vb, void *vd)
       if (r)
        return r;
     }
-  as = pool->solvables + a[5];
-  bs = pool->solvables + b[5];
+  as = pool->solvables + a[6];
+  bs = pool->solvables + b[6];
   if (as->name != bs->name)
     return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
   if (as->evr != bs->evr)
@@ -284,13 +284,44 @@ decisionsort(const void *va, const void *vb, void *vd)
   return 0;
 }
 
+static void
+decisionmerge(Solver *solv, Queue *q)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+
+  for (i = 0; i < q->count; i += 8)
+    {
+      Id p = q->elements[i] >= 0 ? q->elements[i] : -q->elements[i];
+      int reason = q->elements[i + 1];
+      int bits = q->elements[i + 3];
+      Id name =  pool->solvables[p].name;
+      for (j = i + 8; j < q->count; j += 8)
+       {
+         int merged;
+         p = q->elements[j] >= 0 ? q->elements[j] : -q->elements[j];
+         if (reason != q->elements[j + 1] || name != pool->solvables[p].name)
+           break;
+         merged = solver_merge_decisioninfo_bits(solv, bits, q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7], q->elements[j + 3], q->elements[j + 4], q->elements[j + 5], q->elements[j + 6], q->elements[j + 7]);
+         if (!merged)
+           break;
+         bits = merged;
+       }
+      j -= 8;
+      if (j == i)
+       continue;
+      for (; i < j; i += 8)
+       q->elements[i + 3] = bits;
+    }
+}
+
 /* move a decison from position "from" to a smaller position "to" */
 static inline void
 move_decision(Queue *q, int to, int from)
 {
-  queue_insertn(q, to, 7, 0);
-  memmove(q->elements + to, q->elements + from + 7, 7 * sizeof(Id));
-  queue_deleten(q, from + 7, 7); 
+  queue_insertn(q, to, 8, 0);
+  memmove(q->elements + to, q->elements + from + 8, 8 * sizeof(Id));
+  queue_deleten(q, from + 8, 8); 
 }
 
 static void
@@ -366,6 +397,7 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
       queue_push(q, i > 0 ? q->elements[i - 1] : 0);
       queue_push(q, i > 0 ? SOLVER_REASON_UNIT_RULE : SOLVER_REASON_UNSOLVABLE);
       queue_push(q, rid);
+      queue_push(q, 0);                /* bits */
       queue_push(q, type);
       queue_push(q, from);
       queue_push(q, to);
@@ -374,17 +406,17 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
   queue_deleten(q, 0, cnt);
 
   /* switch last two decisions if the unsolvable rule is of type SOLVER_RULE_RPM_SAME_NAME */
-  if (q->count >= 14 && q->elements[q->count - 7 + 2] == SOLVER_RULE_RPM_SAME_NAME && q->elements[q->count - 14] > 0)
+  if (q->count >= 16 && q->elements[q->count - 8 + 3] == SOLVER_RULE_RPM_SAME_NAME && q->elements[q->count - 16] > 0)
     {
-      Rule *r = solv->rules + q->elements[q->count - 7 + 1];
+      Rule *r = solv->rules + q->elements[q->count - 8 + 1];
       /* make sure that the rule is a binary conflict and it matches the installed element */
       if (r->p < 0 && (r->d == 0 || r->d == -1) && r->w2 < 0
-        && (q->elements[q->count - 14] == -r->p || q->elements[q->count - 14] -r->w2))
+        && (q->elements[q->count - 16] == -r->p || q->elements[q->count - 16] -r->w2))
        {
          /* looks good! swap decisions and fixup truelit entries */
-         move_decision(q, q->count - 14, q->count - 7);
-         q->elements[q->count - 14] = -q->elements[q->count - 7];
-         q->elements[q->count - 7] = 0;
+         move_decision(q, q->count - 16, q->count - 8);
+         q->elements[q->count - 16] = -q->elements[q->count - 8];
+         q->elements[q->count - 8] = 0;
        }
     }
 
@@ -399,15 +431,15 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
       i = 0;
       FOR_RULELITERALS(p, pp, r)
        {
-         queue_insertn(q, i, 7, 0);
+         queue_insertn(q, i, 8, 0);
          q->elements[i] = -p;
          q->elements[i + 1] = SOLVER_REASON_PREMISE;
-         q->elements[i + 4] = p >= 0 ? p : -p;
+         q->elements[i + 5] = p >= 0 ? p : -p;
          MAPSET(&seen, p >= 0 ? p : -p);
-         i += 7;
+         i += 8;
        }
-      if (i > 7)
-       solv_sort(q->elements, i / 7, 7 * sizeof(Id), decisionsort, solv);
+      if (i > 8)
+       solv_sort(q->elements, i / 8, 8 * sizeof(Id), decisionsort, solv);
     }
 
   if (flags & SOLVER_DECISIONLIST_SORTED)
@@ -417,10 +449,10 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
        *   if a package is conflicted, move requires right after
        */
       doing = 1;
-      while (i < q->count - 7)
+      while (i < q->count - 8)
        {
          doing ^= 1;
-         for (j = k = i; j < q->count - 7; j += 7)
+         for (j = k = i; j < q->count - 8; j += 8)
            {
              Rule *or;
              Id p, pp;
@@ -435,13 +467,13 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
                continue;       /* not unit yet */
              if (j > k)
                move_decision(q, k, j);
-             k += 7;
+             k += 8;
            }
          if (k == i)
            continue;
-         if (i + 7 < k)
-           solv_sort(q->elements + i, (k - i) / 7, 7 * sizeof(Id), decisionsort, solv);
-         for (; i < k; i += 7)
+         if (i + 8 < k)
+           solv_sort(q->elements + i, (k - i) / 8, 8 * sizeof(Id), decisionsort, solv);
+         for (; i < k; i += 8)
            {
              Id truelit = q->elements[i];
              MAPSET(&seen, truelit >= 0 ? truelit : -truelit);
@@ -455,7 +487,7 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
   if (!(flags & SOLVER_DECISIONLIST_WITHINFO))
     {
       int j;
-      for (i = j = 0; i < q->count; i += 7)
+      for (i = j = 0; i < q->count; i += 8)
        {
          q->elements[j++] = q->elements[i];
          q->elements[j++] = q->elements[i + 1];
@@ -463,6 +495,14 @@ solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
        }
       queue_truncate(q, j);
     }
+  else
+    {
+      /* set bits */
+      for (i = 0; i < q->count; i += 8)
+       q->elements[i + 3] = solver_calc_decisioninfo_bits(solv, q->elements[i], q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7]);
+      if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
+       decisionmerge(solv, q);
+    }
 }
 
 void
@@ -564,16 +604,16 @@ getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
        }
       if (flags & (SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO))
        {
-         queue_insertn(decisionlistq, 0, 4, 0);
+         queue_insertn(decisionlistq, 0, 5, 0);
          if (reason == SOLVER_REASON_WEAKDEP)
            {
              solver_allweakdepinfos(solv, v, &iq);
              if (iq.count)
                {
-                 decisionlistq->elements[0] = iq.elements[0];
-                 decisionlistq->elements[1] = iq.elements[1];
-                 decisionlistq->elements[2] = iq.elements[2];
-                 decisionlistq->elements[3] = iq.elements[3];
+                 decisionlistq->elements[1] = iq.elements[0];
+                 decisionlistq->elements[2] = iq.elements[1];
+                 decisionlistq->elements[3] = iq.elements[2];
+                 decisionlistq->elements[4] = iq.elements[3];
                }
            }
          else if (info > 0)
@@ -587,10 +627,10 @@ getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
                  if (rid2)
                    type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
                }
-             decisionlistq->elements[0] = type;
-             decisionlistq->elements[1] = from;
-             decisionlistq->elements[2] = to;
-             decisionlistq->elements[3] = dep;
+             decisionlistq->elements[1] = type;
+             decisionlistq->elements[2] = from;
+             decisionlistq->elements[3] = to;
+             decisionlistq->elements[4] = dep;
            }
        }
       queue_unshift(decisionlistq, info);
@@ -638,7 +678,7 @@ getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
   if ((flags & (SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO)) == SOLVER_DECISIONLIST_SORTED)
     {
       int j;
-      for (i = j = 0; i < decisionlistq->count; i += 7)
+      for (i = j = 0; i < decisionlistq->count; i += 8)
        {
          decisionlistq->elements[j++] = decisionlistq->elements[i];
          decisionlistq->elements[j++] = decisionlistq->elements[i + 1];
@@ -646,6 +686,14 @@ getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
        }
       queue_truncate(decisionlistq, j);
     }
+  else
+    {
+      /* set bits */
+      for (i = 0; i < decisionlistq->count; i += 8)
+       decisionlistq->elements[i + 3] = solver_calc_decisioninfo_bits(solv, decisionlistq->elements[i], decisionlistq->elements[i + 4], decisionlistq->elements[i + 5], decisionlistq->elements[i + 6], decisionlistq->elements[i + 7]);
+      if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
+       decisionmerge(solv, decisionlistq);
+    }
 }
 
 void
@@ -664,6 +712,7 @@ solver_get_decisionlist(Solver *solv, Id id, int flags, Queue *decisionlistq)
       queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
       if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
        {
+         queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -id, 0, 0, 0, 0));
          queue_push2(decisionlistq, 0, 0);
          queue_push2(decisionlistq, 0, 0);
        }
@@ -697,6 +746,7 @@ solver_get_decisionlist_multiple(Solver *solv, Queue *idq, int flags, Queue *dec
       queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
       if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
        {
+         queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -p, 0, 0, 0, 0));
          queue_push2(decisionlistq, 0, 0);
          queue_push2(decisionlistq, 0, 0);
        }
@@ -747,8 +797,8 @@ solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
       int type = solver_weakdepinfo(solv, decision, &from, &to, &dep);
       if (type)
        {
-         int state = solver_init_decisioninfo(solv, decision, type, from, to, dep);
-         return solver_decisioninfo2str(solv, state, type, from, to, dep);
+         int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
+         return solver_decisioninfo2str(solv, bits, type, from, to, dep);
        }
     }
   if ((reason == SOLVER_REASON_RESOLVE_JOB || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE || reason == SOLVER_REASON_UNSOLVABLE) && info > 0)
@@ -763,15 +813,15 @@ solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
               type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
              if (type)
                {
-                 int state = solver_init_decisioninfo(solv, decision, type, from, to, dep);
-                 return pool_tmpappend(solv->pool, solver_decisioninfo2str(solv, state, type, from, to, dep), " (limited)", 0);
+                 int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
+                 return pool_tmpappend(solv->pool, solver_decisioninfo2str(solv, bits, type, from, to, dep), " (limited)", 0);
                }
             }
        }
       if (type)
        {
-         int state = solver_init_decisioninfo(solv, decision, type, from, to, dep);
-         return solver_decisioninfo2str(solv, state, type, from, to, dep);
+         int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
+         return solver_decisioninfo2str(solv, bits, type, from, to, dep);
        }
     }
   return solver_reason2str(solv, reason);
@@ -781,16 +831,18 @@ solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
 #define DMS_INITED             (1 << 0)
 #define DMS_IDENTICAL_FROM     (1 << 1)
 #define DMS_IDENTICAL_TO       (1 << 2)
-#define DMS_MULTIPLE           (1 << 3)
+#define DMS_MERGED             (1 << 3)
 #define DMS_NEGATIVE           (1 << 4)
 #define DMS_NOMERGE            (1 << 5)
 
-/* add some bits about the decision to the ruleinfo type so we can joint decisions */
+/* add some bits about the decision and the ruleinfo so we can join decisions */
 int
-solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
+solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
 {
   Id decisionpkg = decision >= 0 ? decision : -decision;
-  int state = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0);
+  int bits = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0);
+  if (!decision)
+    return bits | DMS_NOMERGE;
   switch (type)
     {
     case SOLVER_RULE_DISTUPGRADE:
@@ -804,7 +856,7 @@ solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id
     case SOLVER_RULE_PKG_RECOMMENDS:
     case SOLVER_RULE_PKG_SUPPLEMENTS:
       if (decisionpkg == from)
-       state |= DMS_IDENTICAL_FROM;
+       bits |= DMS_IDENTICAL_FROM;
       break;
     case SOLVER_RULE_PKG_SAME_NAME:
     case SOLVER_RULE_PKG_CONFLICTS:
@@ -813,54 +865,56 @@ solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id
     case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
     case SOLVER_RULE_PKG_CONSTRAINS:
       if (decisionpkg == from)
-       state |= DMS_IDENTICAL_FROM;
+       bits |= DMS_IDENTICAL_FROM;
       else if (decisionpkg == to)
-       state |= DMS_IDENTICAL_TO;
+       bits |= DMS_IDENTICAL_TO;
       break;
     default:
       break;
     }
-  if (!decision)
-    state |= DMS_NOMERGE;
-  return state;
+  return bits;
 }
 
 /* try to merge the ruleinfos of two decisions */
 int
-solver_merge_decisioninfo(Solver *solv, int *statep, int oldtype, Id oldfrom, Id oldto, Id olddep, Id decision, int type, Id from, Id to, Id dep)
+solver_merge_decisioninfo_bits(Solver *solv, int bits1, int type1, Id from1, Id to1, Id dep1, int bits2, int type2, Id from2, Id to2, Id dep2)
 {
-  int state = *statep, newstate;
-  Id decisionpkg = decision >= 0 ? decision : -decision;
-  if (!state || (state & DMS_NOMERGE) != 0 || !type || type != oldtype)
+  int merged = 0;
+  if (type1 != type2 || dep1 != dep2)
     return 0;
-  if (!decision || (decision > 0 && (state & DMS_NEGATIVE) != 0) || (decision < 0 && (state & DMS_NEGATIVE) == 0))
+  if (!bits1 || !bits2 || ((bits1 | bits2) & DMS_NOMERGE) != 0 || ((bits1 ^ bits2) & DMS_NEGATIVE) != 0)
     return 0;
-  newstate = (state & ~(DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | DMS_MULTIPLE;
-  if (decisionpkg == from && (state & DMS_IDENTICAL_FROM) != 0)
-    newstate |= DMS_IDENTICAL_FROM;
-  else if (oldfrom != from)
+  merged = (((bits1 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | (bits2 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO))) ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | DMS_MERGED;
+  if (((bits1 & DMS_MERGED) != 0 && bits1 != merged) || ((bits2 & DMS_MERGED) != 0 && bits2 != merged))
     return 0;
-  if (decisionpkg == to && (state & DMS_IDENTICAL_TO) != 0)
-    newstate |= DMS_IDENTICAL_TO;
-  else if (oldto != to)
+  if (((merged & DMS_IDENTICAL_FROM) == 0 && from1 != from2) || ((merged & DMS_IDENTICAL_TO) == 0 && to1 != to2))
     return 0;
-  /* if MULTIPLE is set we need to keep the identical from/to bits */
-  if ((state & DMS_MULTIPLE) != 0 && ((state ^ newstate) & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0)
-    return 0;
-  *statep = newstate;
-  return 1;
+  return merged;
+}
+
+void
+solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q)
+{
+  queue_empty(q);
+  for (; pos < decisionlistq->count; pos += 8)
+    {
+      Id p = decisionlistq->elements[pos];
+      queue_push(q, p > 0 ? p : -p);
+      if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
+       break;
+    }
 }
 
 /* special version of solver_ruleinfo2str which supports merged decisions */
 const char *
-solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id dep)
+solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep)
 {
   Pool *pool = solv->pool;
   const char *s;
-  int multiple = state & DMS_MULTIPLE;
+  int multiple = bits & DMS_MERGED;
 
   /* use it/they variants if DMS_IDENTICAL_FROM is set */
-  if ((state & DMS_IDENTICAL_FROM) != 0)
+  if ((bits & DMS_IDENTICAL_FROM) != 0)
     {
       switch (type)
        {
@@ -921,7 +975,7 @@ solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id de
     }
 
   /* in some cases we can drop the "to" part if DMS_IDENTICAL_TO is set */
-  if ((state & DMS_IDENTICAL_TO) != 0)
+  if ((bits & DMS_IDENTICAL_TO) != 0)
     {
       switch (type)
        {
@@ -932,7 +986,7 @@ solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id de
        case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
        case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
        case SOLVER_RULE_PKG_CONSTRAINS:
-         state &= ~DMS_IDENTICAL_TO;
+         bits &= ~DMS_IDENTICAL_TO;
          to = 0;
          break;
        default:
@@ -941,7 +995,7 @@ solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id de
     }
 
   /* fallback to solver_ruleinfo2str if we can */
-  if (multiple && (state & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0)
+  if (multiple && (bits & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0)
       return "unsupported decision merge?";
   return solver_ruleinfo2str(solv, type, from, to, dep);
 }
index d8a8496d1f527653c31ffb9d2b4d4d929e2669b1..2eeec6cd38bfb6bb0e39196f9c5a0b09970ef36d 100644 (file)
@@ -346,6 +346,7 @@ SOLV_1.0 {
                solver_allweakdepinfos;
                solver_alternative2str;
                solver_alternatives_count;
+               solver_calc_decisioninfo_bits;
                solver_calc_duchanges;
                solver_calc_installsizechange;
                solver_calculate_multiversionmap;
@@ -354,6 +355,7 @@ SOLV_1.0 {
                solver_create_state_maps;
                solver_create_transaction;
                solver_decisioninfo2str;
+               solver_decisionlist_solvables;
                solver_decisionreason2str;
                solver_describe_decision;
                solver_describe_weakdep_decision;
@@ -374,8 +376,7 @@ SOLV_1.0 {
                solver_get_recommendations;
                solver_get_unneeded;
                solver_get_userinstalled;
-               solver_init_decisioninfo;
-               solver_merge_decisioninfo;
+               solver_merge_decisioninfo_bits;
                solver_next_problem;
                solver_next_solution;
                solver_next_solutionelement;
index 24221ce4385a4fe3044d1a002134877455abe43d..c9f70c4d18268db0f94d9a0a4e25b8ebbf7cf88a 100644 (file)
@@ -352,6 +352,7 @@ typedef struct s_Solver Solver;
 #define SOLVER_DECISIONLIST_LEARNTRULE         (1 << 3)
 #define SOLVER_DECISIONLIST_WITHINFO           (1 << 8)
 #define SOLVER_DECISIONLIST_SORTED             (1 << 9)
+#define SOLVER_DECISIONLIST_MERGEDINFO         (1 << 10)
 
 #define SOLVER_DECISIONLIST_TYPEMASK           (0xff)
 
@@ -379,6 +380,7 @@ extern int  solver_describe_decision(Solver *solv, Id p, Id *infop);
 extern void solver_get_decisionlist(Solver *solv, Id p, int flags, Queue *decisionlistq);
 extern void solver_get_decisionlist_multiple(Solver *solv, Queue *pq, int flags, Queue *decisionlistq);
 extern void solver_get_learnt(Solver *solv, Id id, int flags, Queue *q);
+extern void solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q);
 
 extern int solver_alternatives_count(Solver *solv);
 extern int solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp);
@@ -394,15 +396,15 @@ extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
 extern int  pool_isemptyupdatejob(Pool *pool, Id how, Id what);
 
 /* decisioninfo merging */
-extern int solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id dep);
-extern int solver_merge_decisioninfo(Solver *solv, int *statep, int oldtype, Id oldfrom, Id oldto, Id olddep, Id decision, int type, Id from, Id to, Id dep);
+extern int solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep);
+extern int solver_merge_decisioninfo_bits(Solver *solv, int state1, int type1, Id from1, Id to1, Id dep1, int state2, int type2, Id from2, Id to2, Id dep2);
 
 extern const char *solver_select2str(Pool *pool, Id select, Id what);
 extern const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
 extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from);
 extern const char *solver_reason2str(Solver *solv, int reason);
 extern const char *solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info);
-extern const char *solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id dep);
+extern const char *solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep);
 
 
 /* deprecated, use solver_allweakdepinfos/solver_weakdepinfo instead */