/*
* decision.c
*
- * solver decision introspection code
+ * solver decision and alternative introspection code
*/
#include <stdio.h>
return "unsupported decision merge?";
return solver_ruleinfo2str(solv, type, from, to, dep);
}
+
+int
+solver_alternatives_count(Solver *solv)
+{
+ Id *elements = solv->branches.elements;
+ int res, count;
+ for (res = 0, count = solv->branches.count; count; res++)
+ count -= elements[count - 2];
+ return res;
+}
+
+int
+solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
+{
+ int cnt = solver_alternatives_count(solv);
+ int count = solv->branches.count;
+ Id *elements = solv->branches.elements;
+ if (choices)
+ queue_empty(choices);
+ if (alternative <= 0 || alternative > cnt)
+ return 0;
+ elements += count;
+ for (; cnt > alternative; cnt--)
+ elements -= elements[-2];
+ if (levelp)
+ *levelp = elements[-1];
+ if (fromp)
+ *fromp = elements[-4];
+ if (idp)
+ *idp = elements[-3];
+ if (chosenp)
+ {
+ int i;
+ *chosenp = 0;
+ for (i = elements[-2]; i > 4; i--)
+ {
+ Id p = -elements[-i];
+ if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
+ {
+ *chosenp = p;
+ break;
+ }
+ }
+ }
+ if (choices)
+ queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
+ return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
+}
+
+static int
+find_alternative_rule_from_learnt_rec(Solver *solv, int rid, Map *m, int cnt)
+{
+ Pool *pool = solv->pool;
+ int why = solv->learnt_why.elements[rid - solv->learntrules];
+ while ((rid = solv->learnt_pool.elements[why++]) != 0)
+ {
+ Rule *r = solv->rules + rid;
+ Id p, pp;
+ int c;
+ if (rid >= solv->learntrules)
+ {
+ if ((rid = find_alternative_rule_from_learnt_rec(solv, rid, m, cnt)))
+ return rid;
+ continue;
+ }
+ c = 0;
+ FOR_RULELITERALS(p, pp, r)
+ if (p > 0 && MAPTST(m, p))
+ c++;
+ if (c == cnt) /* all bits hit */
+ return rid;
+ }
+ return 0;
+}
+
+static int
+find_alternative_rule_from_learnt(Solver *solv, int rid)
+{
+ Pool *pool = solv->pool;
+ Map m;
+ int i, count, cnt;
+ Id *elements = solv->branches.elements;
+
+ /* find alternative by rule id */
+ for (count = solv->branches.count; count; count -= elements[count - 2])
+ if (elements[count - 4] == 0 && elements[count - 3] == rid)
+ break;
+ if (!count)
+ return 0;
+ map_init(&m, pool->nsolvables);
+ cnt = 0;
+ for (i = count - elements[count - 2]; i < count - 4; i++)
+ if (elements[i] > 0)
+ {
+ MAPSET(&m, elements[i]);
+ cnt++;
+ }
+ rid = find_alternative_rule_from_learnt_rec(solv, rid, &m, cnt);
+ map_free(&m);
+ return rid;
+}
+
+int
+solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp)
+{
+ if (fromp)
+ *fromp = 0;
+ if (top)
+ *top = 0;
+ if (depp)
+ *depp = 0;
+ if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+ {
+ if (fromp)
+ *fromp = from;
+ if (depp)
+ *depp = id;
+ return SOLVER_RULE_PKG_RECOMMENDS;
+ }
+ else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+ {
+ int rclass = solver_ruleclass(solv, id);
+ if (rclass == SOLVER_RULE_LEARNT)
+ {
+ id = find_alternative_rule_from_learnt(solv, id);
+ if (!id)
+ return SOLVER_RULE_LEARNT;
+ rclass = solver_ruleclass(solv, id);
+ }
+ if (rclass == SOLVER_RULE_CHOICE || rclass == SOLVER_RULE_RECOMMENDS)
+ id = solver_rule2pkgrule(solv, id);
+ else if (rclass == SOLVER_RULE_BEST)
+ {
+ Id info = solv->bestrules_info[id - solv->bestrules];
+ if (info > 0)
+ {
+ /* best update */
+ if (fromp)
+ *fromp = info;
+ return SOLVER_RULE_UPDATE;
+ }
+ id = -info; /* best job, delegate to job rule */
+ }
+ return solver_ruleinfo(solv, id, fromp, top, depp);
+ }
+ return 0;
+}
+
+const char *
+solver_alternative2str(Solver *solv, int type, Id id, Id from)
+{
+ const char *s;
+ Pool *pool = solv->pool;
+ Id to, dep;
+ type = solver_alternativeinfo(solv, type, id, from, &from, &to, &dep);
+ switch (type)
+ {
+ case SOLVER_RULE_PKG_RECOMMENDS:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_PKG_REQUIRES:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_PKG_CONFLICTS:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", conflicted by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_YUMOBS:
+ return pool_tmpjoin(pool, pool_id2str(pool, pool->solvables[to].name), ", obsoleting ", pool_dep2str(pool, dep));;
+ case SOLVER_RULE_JOB:
+ if ((to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES || (to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME)
+ return pool_dep2str(pool, dep);
+ return solver_select2str(pool, to & SOLVER_SELECTMASK, dep);
+ case SOLVER_RULE_UPDATE:
+ case SOLVER_RULE_FEATURE:
+ return pool_solvid2str(pool, from);
+ default:
+ break;
+ }
+ return solver_ruleinfo2str(solv, type, from, to, dep);
+}
+
return 1;
}
-int
-solver_alternatives_count(Solver *solv)
-{
- Id *elements = solv->branches.elements;
- int res, count;
- for (res = 0, count = solv->branches.count; count; res++)
- count -= elements[count - 2];
- return res;
-}
-
-int
-solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
-{
- int cnt = solver_alternatives_count(solv);
- int count = solv->branches.count;
- Id *elements = solv->branches.elements;
- if (choices)
- queue_empty(choices);
- if (alternative <= 0 || alternative > cnt)
- return 0;
- elements += count;
- for (; cnt > alternative; cnt--)
- elements -= elements[-2];
- if (levelp)
- *levelp = elements[-1];
- if (fromp)
- *fromp = elements[-4];
- if (idp)
- *idp = elements[-3];
- if (chosenp)
- {
- int i;
- *chosenp = 0;
- for (i = elements[-2]; i > 4; i--)
- {
- Id p = -elements[-i];
- if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
- {
- *chosenp = p;
- break;
- }
- }
- }
- if (choices)
- queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
- return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
-}
-
-static int
-find_alternative_rule_from_learnt_rec(Solver *solv, int rid, Map *m, int cnt)
-{
- Pool *pool = solv->pool;
- int why = solv->learnt_why.elements[rid - solv->learntrules];
- while ((rid = solv->learnt_pool.elements[why++]) != 0)
- {
- Rule *r = solv->rules + rid;
- Id p, pp;
- int c;
- if (rid >= solv->learntrules)
- {
- if ((rid = find_alternative_rule_from_learnt_rec(solv, rid, m, cnt)))
- return rid;
- continue;
- }
- c = 0;
- FOR_RULELITERALS(p, pp, r)
- if (p > 0 && MAPTST(m, p))
- c++;
- if (c == cnt) /* all bits hit */
- return rid;
- }
- return 0;
-}
-
-static int
-find_alternative_rule_from_learnt(Solver *solv, int rid)
-{
- Pool *pool = solv->pool;
- Map m;
- int i, count, cnt;
- Id *elements = solv->branches.elements;
-
- /* find alternative by rule id */
- for (count = solv->branches.count; count; count -= elements[count - 2])
- if (elements[count - 4] == 0 && elements[count - 3] == rid)
- break;
- if (!count)
- return 0;
- map_init(&m, pool->nsolvables);
- cnt = 0;
- for (i = count - elements[count - 2]; i < count - 4; i++)
- if (elements[i] > 0)
- {
- MAPSET(&m, elements[i]);
- cnt++;
- }
- rid = find_alternative_rule_from_learnt_rec(solv, rid, &m, cnt);
- map_free(&m);
- return rid;
-}
-
-int
-solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp)
-{
- if (fromp)
- *fromp = 0;
- if (top)
- *top = 0;
- if (depp)
- *depp = 0;
- if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
- {
- if (fromp)
- *fromp = from;
- if (depp)
- *depp = id;
- return SOLVER_RULE_PKG_RECOMMENDS;
- }
- else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
- {
- int rclass = solver_ruleclass(solv, id);
- if (rclass == SOLVER_RULE_LEARNT)
- {
- id = find_alternative_rule_from_learnt(solv, id);
- if (!id)
- return SOLVER_RULE_LEARNT;
- rclass = solver_ruleclass(solv, id);
- }
- if (rclass == SOLVER_RULE_CHOICE || rclass == SOLVER_RULE_RECOMMENDS)
- id = solver_rule2pkgrule(solv, id);
- else if (rclass == SOLVER_RULE_BEST)
- {
- Id info = solv->bestrules_info[id - solv->bestrules];
- if (info > 0)
- {
- /* best update */
- if (fromp)
- *fromp = info;
- return SOLVER_RULE_UPDATE;
- }
- id = -info; /* best job, delegate to job rule */
- }
- return solver_ruleinfo(solv, id, fromp, top, depp);
- }
- return 0;
-}
-
const char *
solver_select2str(Pool *pool, Id select, Id what)
{
return pool_tmpappend(pool, s, "]", 0);
}
-const char *
-solver_alternative2str(Solver *solv, int type, Id id, Id from)
-{
- const char *s;
- Pool *pool = solv->pool;
- Id to, dep;
- type = solver_alternativeinfo(solv, type, id, from, &from, &to, &dep);
- switch (type)
- {
- case SOLVER_RULE_PKG_RECOMMENDS:
- s = pool_dep2str(pool, dep);
- if (from)
- s = pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
- return s;
- case SOLVER_RULE_PKG_REQUIRES:
- s = pool_dep2str(pool, dep);
- if (from)
- s = pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, from));
- return s;
- case SOLVER_RULE_JOB:
- if ((to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
- return pool_dep2str(pool, dep);
- return solver_select2str(pool, to & SOLVER_SELECTMASK, dep);
- case SOLVER_RULE_UPDATE:
- case SOLVER_RULE_FEATURE:
- return pool_solvid2str(pool, from);
- default:
- break;
- }
- return solver_ruleinfo2str(solv, type, from, to, dep);
-}
-