solver: permutate each preferred solution first
The first found solution is the most preferred one then.cute-signatures
parent
034c02f0de
commit
ad45a6de17
114
src/solver.c
114
src/solver.c
|
@ -38,7 +38,6 @@ struct apk_package_state {
|
||||||
struct apk_name_state {
|
struct apk_name_state {
|
||||||
struct list_head unsolved_list;
|
struct list_head unsolved_list;
|
||||||
struct apk_package *chosen;
|
struct apk_package *chosen;
|
||||||
struct apk_package *preferred;
|
|
||||||
unsigned short requirers;
|
unsigned short requirers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,53 +81,62 @@ static int foreach_dependency(struct apk_solver_state *ss, struct apk_dependency
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculate_preferred(struct apk_database *db,
|
static int inline can_consider_package(struct apk_solver_state *ss, struct apk_package *pkg)
|
||||||
struct apk_name *name,
|
|
||||||
struct apk_name_state *ns)
|
|
||||||
{
|
{
|
||||||
struct apk_package *installed = NULL, *latest = NULL;
|
struct apk_package_state *ps = &ss->pkg_state[pkg->topology_sort];
|
||||||
|
if (pkg->topology_sort >= ss->topology_position)
|
||||||
|
return FALSE;
|
||||||
|
if (ps->conflicts)
|
||||||
|
return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_pkg_preferred(struct apk_solver_state *ss, struct apk_package *pkg)
|
||||||
|
{
|
||||||
|
struct apk_name *name = pkg->name;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Get latest and installed packages */
|
if (!(apk_flags & APK_UPGRADE)) {
|
||||||
|
/* not upgrading, prefer the installed package; unless we
|
||||||
|
* need additional availability checks */
|
||||||
|
if (pkg->ipkg != NULL) {
|
||||||
|
if (pkg->repos != 0 ||
|
||||||
|
!(apk_flags & APK_PREFER_AVAILABLE))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the suggested package is the most preferred one of
|
||||||
|
* available packages for the name */
|
||||||
for (i = 0; i < name->pkgs->num; i++) {
|
for (i = 0; i < name->pkgs->num; i++) {
|
||||||
struct apk_package *pkg = name->pkgs->item[i];
|
struct apk_package *pkg0 = name->pkgs->item[i];
|
||||||
|
|
||||||
if (pkg->ipkg != NULL)
|
if (pkg0 == pkg || !can_consider_package(ss, pkg0))
|
||||||
installed = pkg;
|
|
||||||
else if (!pkg_available(db, pkg))
|
|
||||||
continue;
|
|
||||||
if (latest == NULL) {
|
|
||||||
latest = pkg;
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (apk_flags & APK_PREFER_AVAILABLE) {
|
||||||
|
/* pkg available, pkg0 not */
|
||||||
|
if (pkg->repos != 0 && pkg0->repos == 0)
|
||||||
|
continue;
|
||||||
|
/* pkg0 available, pkg not */
|
||||||
|
if (pkg0->repos != 0 && pkg->repos == 0)
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((apk_flags & APK_PREFER_AVAILABLE) ||
|
if (!(apk_flags & APK_UPGRADE)) {
|
||||||
(name->flags & APK_NAME_REINSTALL)) {
|
/* not upgrading, prefer the installed package */
|
||||||
if (latest->repos != 0 && pkg->repos == 0)
|
if (pkg0->ipkg != NULL)
|
||||||
continue;
|
return FALSE;
|
||||||
if (latest->repos == 0 && pkg->repos != 0) {
|
|
||||||
latest = pkg;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Otherwise both are not available, or both are
|
|
||||||
* available and we just compare the versions then */
|
|
||||||
}
|
}
|
||||||
if (apk_pkg_version_compare(pkg, latest) == APK_VERSION_GREATER)
|
|
||||||
latest = pkg;
|
/* upgrading, or neither of the package is installed, so
|
||||||
}
|
* we just fall back comparing to versions */
|
||||||
|
if (apk_pkg_version_compare(pkg0, pkg) == APK_VERSION_GREATER)
|
||||||
/* Choose the best looking candidate. */
|
return FALSE;
|
||||||
if (apk_flags & APK_UPGRADE) {
|
|
||||||
ns->preferred = latest;
|
|
||||||
} else {
|
|
||||||
if (installed != NULL &&
|
|
||||||
(installed->repos != 0 ||
|
|
||||||
!(name->flags & APK_NAME_REINSTALL)))
|
|
||||||
ns->preferred = installed;
|
|
||||||
else
|
|
||||||
ns->preferred = latest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no package greater than the selected */
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int update_name_state(struct apk_solver_state *ss,
|
static int update_name_state(struct apk_solver_state *ss,
|
||||||
|
@ -139,10 +147,8 @@ static int update_name_state(struct apk_solver_state *ss,
|
||||||
|
|
||||||
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 = &ss->pkg_state[pkg0->topology_sort];
|
|
||||||
|
|
||||||
if (pkg0->topology_sort >= ss->topology_position ||
|
if (!can_consider_package(ss, pkg0))
|
||||||
ps0->conflicts != 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
options++;
|
options++;
|
||||||
|
@ -274,12 +280,8 @@ static int apply_constraint(struct apk_solver_state *ss, struct apk_dependency *
|
||||||
struct apk_package *pkg0 = name->pkgs->item[i];
|
struct apk_package *pkg0 = name->pkgs->item[i];
|
||||||
struct apk_package_state *ps0 = &ss->pkg_state[pkg0->topology_sort];
|
struct apk_package_state *ps0 = &ss->pkg_state[pkg0->topology_sort];
|
||||||
|
|
||||||
if (pkg0->topology_sort >= ss->topology_position) {
|
if (pkg0->topology_sort >= ss->topology_position)
|
||||||
dbg_printf(PKG_VER_FMT ": topology skip %d > %d\n",
|
|
||||||
PKG_VER_PRINTF(pkg0),
|
|
||||||
pkg0->topology_sort, ss->topology_position);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (!apk_dep_is_satisfied(dep, pkg0)) {
|
if (!apk_dep_is_satisfied(dep, pkg0)) {
|
||||||
ps0->conflicts++;
|
ps0->conflicts++;
|
||||||
|
@ -407,14 +409,10 @@ static int expand_branch(struct apk_solver_state *ss)
|
||||||
ns = &ss->name_state[pkg0->name->id];
|
ns = &ss->name_state[pkg0->name->id];
|
||||||
dbg_printf("expand_branch: %s %d\n", pkg0->name->name, pkg0->topology_sort);
|
dbg_printf("expand_branch: %s %d\n", pkg0->name->name, pkg0->topology_sort);
|
||||||
|
|
||||||
/* Is there something we can still use? */
|
|
||||||
if (ns->preferred == NULL)
|
|
||||||
calculate_preferred(ss->db, pkg0->name, ns);
|
|
||||||
|
|
||||||
r = push_decision(ss, pkg0,
|
r = push_decision(ss, pkg0,
|
||||||
(pkg0 == ns->preferred) ?
|
is_pkg_preferred(ss, pkg0) ?
|
||||||
(APK_PKGSTF_INSTALL | APK_PKGSTF_BRANCH) :
|
(APK_PKGSTF_INSTALL | APK_PKGSTF_BRANCH) :
|
||||||
(APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH));
|
(APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH));
|
||||||
|
|
||||||
if (/*no_error_reporting &&*/ r)
|
if (/*no_error_reporting &&*/ r)
|
||||||
return r;
|
return r;
|
||||||
|
@ -462,14 +460,14 @@ int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world
|
||||||
r = foreach_dependency(ss, world, apply_constraint);
|
r = foreach_dependency(ss, world, apply_constraint);
|
||||||
while (r == 0) {
|
while (r == 0) {
|
||||||
if (expand_branch(ss) == 0) {
|
if (expand_branch(ss) == 0) {
|
||||||
/* found solution*/
|
/* found solution - it is optimal because we permutate
|
||||||
/* FIXME: we should check other permutations if they
|
* each preferred local option first, and permutations
|
||||||
* have smaller cost to find optimal changeset */
|
* happen in topologally sorted order. */
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
/* conflicting constraints -- backtrack */
|
|
||||||
r = next_branch(ss);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* conflicting constraints -- backtrack */
|
||||||
|
r = next_branch(ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect packages */
|
/* collect packages */
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
C:Q1EyN5AdpAOBJWKMR89pdfC66o+OE=
|
||||||
|
P:a
|
||||||
|
V:2
|
||||||
|
S:1
|
||||||
|
I:1
|
||||||
|
D:b
|
||||||
|
|
||||||
|
C:Q1C4uoV7SdMdDdfg4OCVmI71D8HIA=
|
||||||
|
P:b
|
||||||
|
V:2
|
||||||
|
S:1
|
||||||
|
I:1
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Replacing a (2 -> 2)
|
||||||
|
Replacing b (2 -> 2)
|
|
@ -0,0 +1 @@
|
||||||
|
--raw-repository basic.repo --installed basic.installed2 -a a
|
|
@ -0,0 +1 @@
|
||||||
|
--raw-repository basic.repo --installed basic.installed2 a
|
Loading…
Reference in New Issue