solver: get rid of saved score in backtracking
also, discover late if package is needed or not.cute-signatures
parent
4bc8add78d
commit
15c920ab90
100
src/solver.c
100
src/solver.c
|
@ -35,7 +35,6 @@ struct apk_score {
|
||||||
struct apk_package_state {
|
struct apk_package_state {
|
||||||
struct apk_package *backtrack;
|
struct apk_package *backtrack;
|
||||||
unsigned int topology_soft;
|
unsigned int topology_soft;
|
||||||
struct apk_score saved_score;
|
|
||||||
unsigned short conflicts;
|
unsigned short conflicts;
|
||||||
unsigned availability_checked : 1;
|
unsigned availability_checked : 1;
|
||||||
unsigned unavailable : 1;
|
unsigned unavailable : 1;
|
||||||
|
@ -441,7 +440,7 @@ static int install_if_missing(struct apk_solver_state *ss, struct apk_package *p
|
||||||
return missing;
|
return missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_if_package_unavailable(struct apk_solver_state *ss, struct apk_package *pkg)
|
static int check_if_package_unavailable(struct apk_solver_state *ss, struct apk_package *pkg, int do_check)
|
||||||
{
|
{
|
||||||
struct apk_name *name = pkg->name;
|
struct apk_name *name = pkg->name;
|
||||||
struct apk_package_state *ps = pkg_to_ps(pkg);
|
struct apk_package_state *ps = pkg_to_ps(pkg);
|
||||||
|
@ -454,7 +453,7 @@ static int check_if_package_unavailable(struct apk_solver_state *ss, struct apk_
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* done already? */
|
/* done already? */
|
||||||
if (ps->availability_checked)
|
if (ps->availability_checked && !do_check)
|
||||||
return ps->unavailable;
|
return ps->unavailable;
|
||||||
|
|
||||||
/* and it's not available, we can't use it */
|
/* and it's not available, we can't use it */
|
||||||
|
@ -499,7 +498,7 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name)
|
||||||
if (ps0 == NULL ||
|
if (ps0 == NULL ||
|
||||||
ss->topology_position < pkg0->topology_hard ||
|
ss->topology_position < pkg0->topology_hard ||
|
||||||
ps0->locked ||
|
ps0->locked ||
|
||||||
check_if_package_unavailable(ss, pkg0))
|
check_if_package_unavailable(ss, pkg0, 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
options++;
|
options++;
|
||||||
|
@ -600,21 +599,21 @@ static solver_result_t apply_decision(struct apk_solver_state *ss,
|
||||||
{
|
{
|
||||||
struct apk_name *name = pkg->name;
|
struct apk_name *name = pkg->name;
|
||||||
struct apk_name_state *ns = name_to_ns(name);
|
struct apk_name_state *ns = name_to_ns(name);
|
||||||
|
unsigned short preference;
|
||||||
|
|
||||||
dbg_printf("-->apply_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
dbg_printf("-->apply_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
||||||
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
||||||
|
|
||||||
if (ps->flags & APK_PKGSTF_INSTALL) {
|
if (ps->flags & APK_PKGSTF_INSTALL) {
|
||||||
unsigned short preference;
|
|
||||||
|
|
||||||
subscore(&ss->minimum_penalty, &ns->minimum_penalty);
|
subscore(&ss->minimum_penalty, &ns->minimum_penalty);
|
||||||
ns->minimum_penalty = (struct apk_score) { 0, 0 };
|
ns->minimum_penalty = (struct apk_score) { 0, 0 };
|
||||||
|
|
||||||
preference = get_preference(ss, pkg, FALSE);
|
preference = get_preference(ss, pkg, FALSE);
|
||||||
ss->score.unsatisfiable += ps->conflicts;
|
ss->score.unsatisfiable += ps->conflicts;
|
||||||
ss->score.preference += preference;
|
ss->score.preference += preference;
|
||||||
if (cmpscore2(&ss->score, &ss->minimum_penalty, &ss->best_score) >= 0) {
|
if (cmpscore2(&ss->score, &ss->minimum_penalty, &ss->best_score) >= 0 ||
|
||||||
dbg_printf("install causing {%d,%d}, penalty too big: {%d,%d}+{%d,%d}>={%d,%d}\n",
|
check_if_package_unavailable(ss, pkg, 1)) {
|
||||||
|
dbg_printf("install causing {%d,%d}, penalty too big (or unavailable %d): {%d,%d}+{%d,%d}>={%d,%d}\n",
|
||||||
ps->conflicts, preference,
|
ps->conflicts, preference,
|
||||||
ss->score.unsatisfiable, ss->score.preference,
|
ss->score.unsatisfiable, ss->score.preference,
|
||||||
ss->minimum_penalty.unsatisfiable, ss->minimum_penalty.preference,
|
ss->minimum_penalty.unsatisfiable, ss->minimum_penalty.preference,
|
||||||
|
@ -639,7 +638,7 @@ static solver_result_t apply_decision(struct apk_solver_state *ss,
|
||||||
foreach_dependency(ss, pkg->depends, apply_constraint);
|
foreach_dependency(ss, pkg->depends, apply_constraint);
|
||||||
foreach_rinstall_if_pkg(ss, pkg, trigger_install_if);
|
foreach_rinstall_if_pkg(ss, pkg, trigger_install_if);
|
||||||
} else {
|
} else {
|
||||||
if (ns->locked == 0 && update_name_state(ss, pkg->name) == 0) {
|
if (update_name_state(ss, pkg->name) == 0) {
|
||||||
subscore(&ss->minimum_penalty, &ns->minimum_penalty);
|
subscore(&ss->minimum_penalty, &ns->minimum_penalty);
|
||||||
ns->minimum_penalty = (struct apk_score) { 0, 0 };
|
ns->minimum_penalty = (struct apk_score) { 0, 0 };
|
||||||
|
|
||||||
|
@ -668,7 +667,8 @@ static void undo_decision(struct apk_solver_state *ss,
|
||||||
struct apk_package *pkg,
|
struct apk_package *pkg,
|
||||||
struct apk_package_state *ps)
|
struct apk_package_state *ps)
|
||||||
{
|
{
|
||||||
struct apk_name_state *ns = name_to_ns(pkg->name);
|
struct apk_name *name = pkg->name;
|
||||||
|
struct apk_name_state *ns = name_to_ns(name);
|
||||||
|
|
||||||
dbg_printf("-->undo_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
dbg_printf("-->undo_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
||||||
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
||||||
|
@ -680,22 +680,28 @@ static void undo_decision(struct apk_solver_state *ss,
|
||||||
|
|
||||||
if (ps->flags & APK_PKGSTF_INSTALL) {
|
if (ps->flags & APK_PKGSTF_INSTALL) {
|
||||||
if (ps->install_applied) {
|
if (ps->install_applied) {
|
||||||
|
unsigned short preference;
|
||||||
|
|
||||||
ps->install_applied = 0;
|
ps->install_applied = 0;
|
||||||
ss->assigned_names--;
|
ss->assigned_names--;
|
||||||
foreach_rinstall_if_pkg(ss, pkg, untrigger_install_if);
|
foreach_rinstall_if_pkg(ss, pkg, untrigger_install_if);
|
||||||
foreach_dependency(ss, pkg->depends, undo_constraint);
|
foreach_dependency(ss, pkg->depends, undo_constraint);
|
||||||
|
|
||||||
|
preference = get_preference(ss, pkg, FALSE);
|
||||||
|
ss->score.unsatisfiable -= ps->conflicts;
|
||||||
|
ss->score.preference -= preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
ns->locked = 0;
|
|
||||||
ns->chosen = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
/* UNINSTALL decision removed - either name is unlocked
|
if (ns->locked) {
|
||||||
* or locked to none */
|
/* UNINSTALL decision removed - either name is unlocked
|
||||||
ns->locked = 0;
|
* or locked to none */
|
||||||
ns->chosen = NULL;
|
ss->score.unsatisfiable -= ns->requirers;
|
||||||
|
ss->score.preference -= name->pkgs->num;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ns->locked = 0;
|
||||||
|
ns->chosen = NULL;
|
||||||
|
|
||||||
ss->score = ps->saved_score;
|
|
||||||
update_name_state(ss, pkg->name);
|
update_name_state(ss, pkg->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,16 +711,15 @@ static solver_result_t push_decision(struct apk_solver_state *ss, struct apk_pac
|
||||||
struct apk_package_state *ps = pkg_to_ps(pkg);
|
struct apk_package_state *ps = pkg_to_ps(pkg);
|
||||||
|
|
||||||
ps->backtrack = ss->latest_decision;
|
ps->backtrack = ss->latest_decision;
|
||||||
ps->locked = 1;
|
|
||||||
ps->flags = flags;
|
ps->flags = flags;
|
||||||
ps->saved_score = ss->score;
|
ps->locked = 1;
|
||||||
|
ps->handle_install_if = 0;
|
||||||
|
|
||||||
if (ps->topology_soft < ss->topology_position) {
|
if (ps->topology_soft < ss->topology_position) {
|
||||||
if (flags & APK_PKGSTF_INSTALL)
|
if (flags & APK_PKGSTF_INSTALL)
|
||||||
ps->handle_install_if = 1;
|
ps->handle_install_if = 1;
|
||||||
ss->topology_position = ps->topology_soft;
|
ss->topology_position = ps->topology_soft;
|
||||||
} else {
|
} else {
|
||||||
ps->handle_install_if = 0;
|
|
||||||
ss->topology_position = pkg->topology_hard;
|
ss->topology_position = pkg->topology_hard;
|
||||||
}
|
}
|
||||||
ss->latest_decision = pkg;
|
ss->latest_decision = pkg;
|
||||||
|
@ -814,14 +819,19 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
|
||||||
if (ns->locked) {
|
if (ns->locked) {
|
||||||
if (ns->chosen)
|
if (ns->chosen)
|
||||||
dbg_printf("%s: locked to " PKG_VER_FMT " already\n",
|
dbg_printf("%s: locked to " PKG_VER_FMT " already\n",
|
||||||
dep->name->name, PKG_VER_PRINTF(ns->chosen));
|
name->name, PKG_VER_PRINTF(ns->chosen));
|
||||||
else
|
else
|
||||||
dbg_printf("%s: locked to empty\n",
|
dbg_printf("%s: locked to empty\n",
|
||||||
dep->name->name);
|
name->name);
|
||||||
if (!apk_dep_is_satisfied(dep, ns->chosen))
|
if (!apk_dep_is_satisfied(dep, ns->chosen))
|
||||||
ss->score.unsatisfiable++;
|
ss->score.unsatisfiable++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (name->pkgs->num == 0) {
|
||||||
|
if (!dep->optional)
|
||||||
|
ss->score.unsatisfiable++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (dep->repository_tag) {
|
if (dep->repository_tag) {
|
||||||
dbg_printf("%s: adding pinnings %d\n",
|
dbg_printf("%s: adding pinnings %d\n",
|
||||||
|
@ -830,6 +840,12 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
|
||||||
ns->allowed_pinning |= BIT(dep->repository_tag);
|
ns->allowed_pinning |= BIT(dep->repository_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ss->latest_decision != NULL) {
|
||||||
|
dbg_printf("%s: inheriting flags and pinning from %s\n",
|
||||||
|
name->name, ss->latest_decision->name->name);
|
||||||
|
inherit_name_state(name, ss->latest_decision->name);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < name->pkgs->num; i++) {
|
for (i = 0; i < name->pkgs->num; i++) {
|
||||||
struct apk_package *pkg0 = name->pkgs->item[i];
|
struct apk_package *pkg0 = name->pkgs->item[i];
|
||||||
struct apk_package_state *ps0 = pkg_to_ps(pkg0);
|
struct apk_package_state *ps0 = pkg_to_ps(pkg0);
|
||||||
|
@ -846,12 +862,6 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ss->latest_decision != NULL) {
|
|
||||||
dbg_printf("%s: inheriting flags and pinning from %s\n",
|
|
||||||
name->name, ss->latest_decision->name->name);
|
|
||||||
inherit_name_state(name, ss->latest_decision->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dep->optional)
|
if (!dep->optional)
|
||||||
ns->requirers++;
|
ns->requirers++;
|
||||||
|
|
||||||
|
@ -867,11 +877,18 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
|
||||||
if (ns->locked) {
|
if (ns->locked) {
|
||||||
if (ns->chosen != NULL) {
|
if (ns->chosen != NULL) {
|
||||||
dbg_printf(PKG_VER_FMT " selected already for %s\n",
|
dbg_printf(PKG_VER_FMT " selected already for %s\n",
|
||||||
PKG_VER_PRINTF(ns->chosen), dep->name->name);
|
PKG_VER_PRINTF(ns->chosen), name->name);
|
||||||
} else {
|
} else {
|
||||||
dbg_printf("%s selected to not be satisfied\n",
|
dbg_printf("%s selected to not be satisfied\n",
|
||||||
dep->name->name);
|
name->name);
|
||||||
}
|
}
|
||||||
|
if (!apk_dep_is_satisfied(dep, ns->chosen))
|
||||||
|
ss->score.unsatisfiable--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name->pkgs->num == 0) {
|
||||||
|
if (!dep->optional)
|
||||||
|
ss->score.unsatisfiable--;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,13 +936,6 @@ static int expand_branch(struct apk_solver_state *ss)
|
||||||
pkg0 = ns->chosen, topology0 = pkg0->topology_hard;
|
pkg0 = ns->chosen, topology0 = pkg0->topology_hard;
|
||||||
}
|
}
|
||||||
if (pkg0 == NULL) {
|
if (pkg0 == NULL) {
|
||||||
list_for_each_entry(ns, &ss->unsolved_list_head, unsolved_list) {
|
|
||||||
if (ns->locked)
|
|
||||||
continue;
|
|
||||||
ss->score.unsatisfiable += ns->requirers;
|
|
||||||
ss->score.preference += ns->name->pkgs->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg_printf("expand_branch: list is empty (%d unsatisfied)\n",
|
dbg_printf("expand_branch: list is empty (%d unsatisfied)\n",
|
||||||
ss->score.unsatisfiable);
|
ss->score.unsatisfiable);
|
||||||
return SOLVERR_SOLUTION;
|
return SOLVERR_SOLUTION;
|
||||||
|
@ -1011,7 +1021,6 @@ static void record_solution(struct apk_solver_state *ss)
|
||||||
pkg = ps->backtrack;
|
pkg = ps->backtrack;
|
||||||
}
|
}
|
||||||
apk_solution_array_resize(&ss->best_solution, i);
|
apk_solution_array_resize(&ss->best_solution, i);
|
||||||
ss->best_score = ss->score;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_solution_entry(const void *p1, const void *p2)
|
static int compare_solution_entry(const void *p1, const void *p2)
|
||||||
|
@ -1185,14 +1194,21 @@ int apk_solver_solve(struct apk_database *db,
|
||||||
/* need EXPAND if here, can return SOLUTION|PRUNED|EXPAND */
|
/* need EXPAND if here, can return SOLUTION|PRUNED|EXPAND */
|
||||||
r = expand_branch(ss);
|
r = expand_branch(ss);
|
||||||
if (r == SOLVERR_SOLUTION) {
|
if (r == SOLVERR_SOLUTION) {
|
||||||
|
struct apk_score score;
|
||||||
|
|
||||||
dbg_printf("solution with: %d unsatisfiable, %d preference\n",
|
dbg_printf("solution with: %d unsatisfiable, %d preference\n",
|
||||||
ss->score.unsatisfiable,
|
ss->score.unsatisfiable,
|
||||||
ss->score.preference);
|
ss->score.preference);
|
||||||
|
|
||||||
if (cmpscore(&ss->score, &ss->best_score) < 0)
|
score = ss->score;
|
||||||
record_solution(ss);
|
addscore(&score, &ss->minimum_penalty);
|
||||||
|
|
||||||
if (cmpscore(&zero_score, &ss->score) >= 0) {
|
if (cmpscore(&score, &ss->best_score) < 0) {
|
||||||
|
record_solution(ss);
|
||||||
|
ss->best_score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmpscore(&zero_score, &score) >= 0) {
|
||||||
/* found solution - it is optimal because we permutate
|
/* found solution - it is optimal because we permutate
|
||||||
* each preferred local option first, and permutations
|
* each preferred local option first, and permutations
|
||||||
* happen in topologally sorted order. */
|
* happen in topologally sorted order. */
|
||||||
|
|
Loading…
Reference in New Issue