concretizer: handle constraints on dependencies, adjust optimization

This needs more thought, as I am pretty sure the weights are not correct.
Or, at least, I'm not convinced that they do what we want in all cases.
See note in concretize.lp.
This commit is contained in:
Todd Gamblin 2019-10-17 09:47:32 -07:00
parent db62b00d58
commit 4d34363c1d
3 changed files with 49 additions and 10 deletions

View File

@ -16,6 +16,7 @@
import spack.cmd.common.arguments as arguments
import spack.package
import spack.solver.asp as asp
from spack.util.string import plural
description = "concretize a specs using an ASP solver"
section = 'developer'
@ -103,7 +104,7 @@ def solve(parser, args):
opt, i, answer = best
if not args.yaml:
tty.msg("Best of %d answers." % (i + 1))
tty.msg("Optimization %s" % opt)
tty.msg("Optimization: %s" % opt)
# iterate over roots from command line
for spec in specs:

View File

@ -346,6 +346,10 @@ def pkg_rules(self, pkg):
# dependencies
for name, conditions in pkg.dependencies.items():
for cond, dep in conditions.items():
named_cond = cond.copy()
if not named_cond.name:
named_cond.name = pkg.name
if cond == spack.spec.Spec():
for t in dep.type:
self.fact(
@ -354,9 +358,6 @@ def pkg_rules(self, pkg):
)
)
else:
named_cond = cond.copy()
if not named_cond.name:
named_cond.name = pkg.name
for t in dep.type:
self.rule(
fn.declared_dependency(
@ -367,6 +368,16 @@ def pkg_rules(self, pkg):
)
)
# add constraints on the dependency from dep spec.
for clause in self.spec_clauses(dep.spec):
self.rule(
clause,
self._and(
fn.depends_on(dep.pkg.name, dep.spec.name),
*self.spec_clauses(named_cond, body=True)
)
)
# virtual preferences
self.virtual_preferences(
pkg.name,

View File

@ -17,7 +17,6 @@ version_declared(P, V) :- version_declared(P, V, _).
version_possible(P, V) :- version_declared(P, V), not version_conflict(P, V).
version_weight(P, V, N) :- version(P, V), version_declared(P, V, N).
#minimize{ N@3,P,V : version_weight(P, V, N) }.
#defined version_conflict/2.
@ -54,9 +53,6 @@ provider_weight(D, 100)
not pkg_provider_preference(P, V, D, _),
not default_provider_preference(V, D, _).
% pick most preferred virtual providers
#minimize{ N@2,D : provider_weight(D, N) }.
% all nodes must be reachable from some root
needed(D) :- root(D), node(D).
needed(D) :- root(P), depends_on(P, D).
@ -100,8 +96,6 @@ variant_not_default(P, V, X, 0)
variant_default_value(P, V, X),
node(P).
#minimize { N@1,P,V,X : variant_not_default(P, V, X, N) }.
% suppress wranings about this atom being unset. It's only set if some
% spec or some package sets it, and without this, clingo will give
% warnings like 'info: atom does not occur in any rule head'.
@ -187,3 +181,36 @@ node_compiler_set(D, C)
node_compiler_version_set(D, C, V)
:- node(D), compiler(C), depends_on(P, D), node_compiler(D, C),
node_compiler_version_set(P, C, V).
%-----------------------------------------------------------------------------
% How to optimize the spec (high to low priority)
%-----------------------------------------------------------------------------
% weight root preferences higher
%
% TODO: how best to deal with this issue? It's not clear how best to
% weight all the constraints. Without this root preference, `spack solve
% hdf5` will pick mpich instead of openmpi, even if openmpi is the
% preferred provider, because openmpi has a version constraint on hwloc.
% It ends up choosing between settling for an old version of hwloc, or
% picking the second-best provider. This workaround weights root
% preferences higher so that hdf5's prefs are more important, but it's
% not clear this is a general solution. It would be nice to weight by
% distance to root, but that seems to slow down the solve a lot.
%
% One option is to make preferences hard constraints. Or maybe we need
% to look more closely at where a constraint came from and factor that
% into our weights. e.g., a non-default variant resulting from a version
% constraint counts like a version constraint. Needs more thought later.
%
root(D, 2) :- root(D), node(D).
root(D, 1) :- not root(D), node(D).
% pick most preferred virtual providers
#minimize{ N*R@3,D : provider_weight(D, N), root(P, R) }.
% prefer default variants
#minimize { N*R@2,P,V,X : variant_not_default(P, V, X, N), root(P, R) }.
% prefer more recent versions.
#minimize{ N@1,P,V : version_weight(P, V, N) }.