Parametrize all the logic program for multiple nodes
Introduce the concept of "condition sets", i.e. the set of packages on which a package can require / impose conditions. This currently maps to the link/run sub-dag of each package + its direct build dependencies. Parametrize the "condition" and "requirement" logic to multiple nodes.
This commit is contained in:
parent
c050b99a06
commit
22c95923e3
3 changed files with 184 additions and 76 deletions
|
@ -776,6 +776,7 @@ def visit(node):
|
||||||
|
|
||||||
# Load the file itself
|
# Load the file itself
|
||||||
self.control.load(os.path.join(parent_dir, "concretize.lp"))
|
self.control.load(os.path.join(parent_dir, "concretize.lp"))
|
||||||
|
self.control.load(os.path.join(parent_dir, "heuristic.lp"))
|
||||||
self.control.load(os.path.join(parent_dir, "os_compatibility.lp"))
|
self.control.load(os.path.join(parent_dir, "os_compatibility.lp"))
|
||||||
self.control.load(os.path.join(parent_dir, "display.lp"))
|
self.control.load(os.path.join(parent_dir, "display.lp"))
|
||||||
timer.stop("load")
|
timer.stop("load")
|
||||||
|
@ -1284,9 +1285,13 @@ def impose(self, condition_id, imposed_spec, node=True, name=None, body=False):
|
||||||
|
|
||||||
def package_provider_rules(self, pkg):
|
def package_provider_rules(self, pkg):
|
||||||
for provider_name in sorted(set(s.name for s in pkg.provided.keys())):
|
for provider_name in sorted(set(s.name for s in pkg.provided.keys())):
|
||||||
|
if provider_name not in self.possible_virtuals:
|
||||||
|
continue
|
||||||
self.gen.fact(fn.facts(pkg.name, fn.possible_provider(provider_name)))
|
self.gen.fact(fn.facts(pkg.name, fn.possible_provider(provider_name)))
|
||||||
|
|
||||||
for provided, whens in pkg.provided.items():
|
for provided, whens in pkg.provided.items():
|
||||||
|
if provided.name not in self.possible_virtuals:
|
||||||
|
continue
|
||||||
for when in whens:
|
for when in whens:
|
||||||
msg = "%s provides %s when %s" % (pkg.name, provided, when)
|
msg = "%s provides %s when %s" % (pkg.name, provided, when)
|
||||||
condition_id = self.condition(when, provided, pkg.name, msg)
|
condition_id = self.condition(when, provided, pkg.name, msg)
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
|
|
||||||
#const root_node_id = 0.
|
#const root_node_id = 0.
|
||||||
|
|
||||||
|
#const link_run = 0.
|
||||||
|
#const direct_build = 1.
|
||||||
|
|
||||||
% Allow clingo to create nodes
|
% Allow clingo to create nodes
|
||||||
{ attr("node", node(0..X-1, Package)) } :- max_nodes(Package, X), not virtual(Package).
|
{ attr("node", node(0..X-1, Package)) } :- max_nodes(Package, X), not virtual(Package).
|
||||||
|
|
||||||
|
@ -39,12 +42,42 @@ max_nodes(Package, 1) :- virtual(Package).
|
||||||
:- attr("node_flag_source", ParentNode, _, _), not attr("node", ParentNode).
|
:- attr("node_flag_source", ParentNode, _, _), not attr("node", ParentNode).
|
||||||
:- attr("node_flag_source", _, _, ChildNode), not attr("node", ChildNode).
|
:- attr("node_flag_source", _, _, ChildNode), not attr("node", ChildNode).
|
||||||
|
|
||||||
|
:- attr("virtual_node", VirtualNode), not provider(_, VirtualNode).
|
||||||
|
:- provider(_, VirtualNode), not attr("virtual_node", VirtualNode).
|
||||||
|
:- provider(PackageNode, _), not attr("node", PackageNode).
|
||||||
|
|
||||||
|
:- attr("root", node(ID, PackageNode)), ID> root_node_id.
|
||||||
|
|
||||||
|
% Root nodes cannot depend on non-root nodes if the dependency is "link" or "run"
|
||||||
|
:- attr("depends_on", node(root_node_id, _), node(ID, _), "link"), ID != root_node_id.
|
||||||
|
:- attr("depends_on", node(root_node_id, _), node(ID, _), "run"), ID != root_node_id.
|
||||||
|
|
||||||
% Rules on "unification sets", i.e. on sets of nodes allowing a single configuration of any given package
|
% Rules on "unification sets", i.e. on sets of nodes allowing a single configuration of any given package
|
||||||
unification_set("root", PackageNode) :- attr("root", PackageNode).
|
|
||||||
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, _), unification_set(SetID, ParentNode).
|
|
||||||
unify(SetID, PackageName) :- unification_set(SetID, node(_, PackageName)).
|
unify(SetID, PackageName) :- unification_set(SetID, node(_, PackageName)).
|
||||||
:- 2 { unification_set(SetID, node(_, PackageName)) }, unify(SetID, PackageName).
|
:- 2 { unification_set(SetID, node(_, PackageName)) }, unify(SetID, PackageName).
|
||||||
|
|
||||||
|
unification_set("root", PackageNode) :- attr("root", PackageNode).
|
||||||
|
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type != "build", unification_set(SetID, ParentNode).
|
||||||
|
unification_set(("build", ParentNode), ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type == "build", unification_set("root", ParentNode).
|
||||||
|
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type == "build", SetID != "root", unification_set(SetID, ParentNode).
|
||||||
|
unification_set(SetID, VirtualNode) :- provider(PackageNode, VirtualNode), unification_set(SetID, PackageNode).
|
||||||
|
|
||||||
|
%----
|
||||||
|
% Rules to break symmetry and speed-up searches
|
||||||
|
%----
|
||||||
|
|
||||||
|
% In the "root" unification set only ID = 0 are allowed
|
||||||
|
:- unification_set("root", node(ID, _)), ID != 0.
|
||||||
|
|
||||||
|
% Cannot have a node with an ID, if lower ID of the same package are not used
|
||||||
|
:- attr("node", node(ID1, Package)),
|
||||||
|
not attr("node", node(ID2, Package)),
|
||||||
|
max_nodes(Package, X), ID1=0..X-1, ID2=0..X-1, ID2 < ID1.
|
||||||
|
|
||||||
|
:- attr("virtual_node", node(ID1, Package)),
|
||||||
|
not attr("virtual_node", node(ID2, Package)),
|
||||||
|
max_nodes(Package, X), ID1=0..X-1, ID2=0..X-1, ID2 < ID1.
|
||||||
|
|
||||||
% Give clingo the choice to solve an input spec or not
|
% Give clingo the choice to solve an input spec or not
|
||||||
{ literal_solved(ID) } :- literal(ID).
|
{ literal_solved(ID) } :- literal(ID).
|
||||||
literal_not_solved(ID) :- not literal_solved(ID), literal(ID).
|
literal_not_solved(ID) :- not literal_solved(ID), literal(ID).
|
||||||
|
@ -63,15 +96,16 @@ opt_criterion(300, "number of input specs not concretized").
|
||||||
|
|
||||||
% TODO: literals, at the moment, can only influence the "root" unification set. This needs to be extended later.
|
% TODO: literals, at the moment, can only influence the "root" unification set. This needs to be extended later.
|
||||||
|
|
||||||
|
special_case("node_flag_source").
|
||||||
|
special_case("depends_on").
|
||||||
|
|
||||||
% Map constraint on the literal ID to facts on the node
|
% Map constraint on the literal ID to facts on the node
|
||||||
attr(Name, node(root_node_id, A1)) :- literal(LiteralID, Name, A1), literal_solved(LiteralID).
|
attr(Name, node(root_node_id, A1)) :- literal(LiteralID, Name, A1), literal_solved(LiteralID).
|
||||||
attr(Name, node(root_node_id, A1), A2) :- literal(LiteralID, Name, A1, A2), literal_solved(LiteralID).
|
attr(Name, node(root_node_id, A1), A2) :- literal(LiteralID, Name, A1, A2), literal_solved(LiteralID).
|
||||||
attr(Name, node(root_node_id, A1), A2, A3) :- literal(LiteralID, Name, A1, A2, A3), literal_solved(LiteralID), not literal_special_case(LiteralID, Name, A1, A2, A3).
|
attr(Name, node(root_node_id, A1), A2, A3) :- literal(LiteralID, Name, A1, A2, A3), literal_solved(LiteralID), not special_case(Name).
|
||||||
attr(Name, node(root_node_id, A1), A2, A3, A4) :- literal(LiteralID, Name, A1, A2, A3, A4), literal_solved(LiteralID).
|
attr(Name, node(root_node_id, A1), A2, A3, A4) :- literal(LiteralID, Name, A1, A2, A3, A4), literal_solved(LiteralID).
|
||||||
|
|
||||||
% Special cases where nodes occur in arguments other than A1
|
% Special cases where nodes occur in arguments other than A1
|
||||||
literal_special_case(LiteralID, Name, A1, A2, A3) :- literal(LiteralID, Name, A1, A2, A3), Name == "node_flag_source".
|
|
||||||
literal_special_case(LiteralID, Name, A1, A2, A3) :- literal(LiteralID, Name, A1, A2, A3), Name == "depends_on".
|
|
||||||
attr("node_flag_source", node(root_node_id, A1), A2, node(root_node_id, A3)) :- literal(LiteralID, "node_flag_source", A1, A2, A3), literal_solved(LiteralID).
|
attr("node_flag_source", node(root_node_id, A1), A2, node(root_node_id, A3)) :- literal(LiteralID, "node_flag_source", A1, A2, A3), literal_solved(LiteralID).
|
||||||
attr("depends_on", node(root_node_id, A1), node(root_node_id, A2), A3) :- literal(LiteralID, "depends_on", A1, A2, A3), literal_solved(LiteralID).
|
attr("depends_on", node(root_node_id, A1), node(root_node_id, A2), A3) :- literal(LiteralID, "depends_on", A1, A2, A3), literal_solved(LiteralID).
|
||||||
|
|
||||||
|
@ -213,30 +247,100 @@ attr("node_version_satisfies", node(ID, Package), Constraint)
|
||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
% conditions are specified with `condition_requirement` and hold when
|
% conditions are specified with `condition_requirement` and hold when
|
||||||
% corresponding spec attributes hold.
|
% corresponding spec attributes hold.
|
||||||
condition_holds(ID, node(root_node_id, Package)) :-
|
|
||||||
facts(Package, condition(ID));
|
% A "condition_set(PackageNode, _)" is the set of nodes on which PackageNode can require / impose conditions
|
||||||
attr(Name, node(root_node_id, A1)) : condition_requirement(ID, Name, A1);
|
% Currently, for a given node, this is the link-run sub-DAG of PackageNode and its direct build dependencies
|
||||||
attr(Name, node(root_node_id, A1), A2) : condition_requirement(ID, Name, A1, A2);
|
condition_set(PackageNode, PackageNode, link_run) :- attr("node", PackageNode).
|
||||||
attr(Name, node(root_node_id, A1), A2, A3) : condition_requirement(ID, Name, A1, A2, A3), Name != "node_flag_source";
|
|
||||||
attr(Name, node(root_node_id, A1), A2, A3, A4) : condition_requirement(ID, Name, A1, A2, A3, A4);
|
condition_set(PackageNode, PackageNode, link_run) :- provider(PackageNode, VirtualNode).
|
||||||
|
condition_set(PackageNode, VirtualNode, link_run) :- provider(PackageNode, VirtualNode).
|
||||||
|
|
||||||
|
:- condition_set(node(root_node_id, Package), node(ID, A1), link_run), ID > root_node_id.
|
||||||
|
|
||||||
|
condition_set(ID, DependencyNode, link_run)
|
||||||
|
:- condition_set(ID, PackageNode, link_run),
|
||||||
|
attr("depends_on", PackageNode, DependencyNode, Type),
|
||||||
|
Type != "build".
|
||||||
|
|
||||||
|
condition_set(PackageNode, DependencyNode, direct_build) :- condition_set(PackageNode, PackageNode, link_run), attr("depends_on", PackageNode, DependencyNode, "build").
|
||||||
|
condition_set(ID, VirtualNode, Type) :- condition_set(ID, PackageNode, Type), provider(PackageNode, VirtualNode).
|
||||||
|
|
||||||
|
condition_set(ID, PackageNode) :- condition_set(ID, PackageNode, _).
|
||||||
|
|
||||||
|
condition_packages(ID, A1) :- condition_requirement(ID, _, A1).
|
||||||
|
condition_packages(ID, A1) :- condition_requirement(ID, _, A1, _).
|
||||||
|
condition_packages(ID, A1) :- condition_requirement(ID, _, A1, _, _).
|
||||||
|
condition_packages(ID, A1) :- condition_requirement(ID, _, A1, _, _, _).
|
||||||
|
|
||||||
|
node_condition(ID, node(PackageID, Package)) :- facts(Package, condition(ID)), attr("node", node(PackageID, Package)).
|
||||||
|
node_condition(ID, node(PackageID, Package)) :- facts(Virtual, condition(ID)), provider(node(PackageID, Package), node(_, Virtual)).
|
||||||
|
|
||||||
|
condition_nodes(ConditionID, PackageNode, node(X, A1))
|
||||||
|
:- condition_packages(ConditionID, A1),
|
||||||
|
condition_set(PackageNode, node(X, A1)),
|
||||||
|
node_condition(ConditionID, PackageNode).
|
||||||
|
|
||||||
|
cannot_hold(ConditionID, PackageNode)
|
||||||
|
:- condition_packages(ConditionID, A1),
|
||||||
|
not condition_set(PackageNode, node(_, A1), _),
|
||||||
|
node_condition(ConditionID, PackageNode).
|
||||||
|
|
||||||
|
condition_holds(ID, PackageNode) :-
|
||||||
|
node_condition(ID, PackageNode);
|
||||||
|
attr(Name, node(X, A1)) : condition_requirement(ID, Name, A1), condition_nodes(ID, PackageNode, node(X, A1));
|
||||||
|
attr(Name, node(X, A1), A2) : condition_requirement(ID, Name, A1, A2), condition_nodes(ID, PackageNode, node(X, A1));
|
||||||
|
attr(Name, node(X, A1), A2, A3) : condition_requirement(ID, Name, A1, A2, A3), condition_nodes(ID, PackageNode, node(X, A1)), not special_case(Name);
|
||||||
|
attr(Name, node(X, A1), A2, A3, A4) : condition_requirement(ID, Name, A1, A2, A3, A4), condition_nodes(ID, PackageNode, node(X, A1));
|
||||||
% Special cases
|
% Special cases
|
||||||
attr("node_flag_source", node(root_node_id, Package), A2, node(root_node_id, A3)) : condition_requirement(ID, "node_flag_source", Package, A2, A3).
|
attr("node_flag_source", node(X, A1), A2, node(Y, A3)) : condition_requirement(ID, "node_flag_source", A1, A2, A3), condition_nodes(ID, PackageNode, node(X, A1)), condition_nodes(ID, PackageNode, node(Y, A3));
|
||||||
|
not cannot_hold(ID, PackageNode).
|
||||||
|
|
||||||
|
condition_holds(ID, node(VirtualID, Virtual))
|
||||||
|
:- condition_holds(ID, PackageNode),
|
||||||
|
facts(Virtual, condition(ID)),
|
||||||
|
provider(PackageNode, node(VirtualID, Virtual)).
|
||||||
|
|
||||||
% condition_holds(ID, node(ID, Package)) implies all imposed_constraints, unless do_not_impose(ID, node(ID, Package))
|
% condition_holds(ID, node(ID, Package)) implies all imposed_constraints, unless do_not_impose(ID, node(ID, Package))
|
||||||
% is derived. This allows imposed constraints to be canceled in special cases.
|
% is derived. This allows imposed constraints to be canceled in special cases.
|
||||||
impose(ID, PackageNode) :- condition_holds(ID, PackageNode), not do_not_impose(ID, PackageNode).
|
impose(ID, PackageNode) :- condition_holds(ID, PackageNode), node_condition(ID, PackageNode), not do_not_impose(ID, PackageNode).
|
||||||
|
|
||||||
|
imposed_packages(ID, A1) :- imposed_constraint(ID, _, A1).
|
||||||
|
imposed_packages(ID, A1) :- imposed_constraint(ID, _, A1, _).
|
||||||
|
imposed_packages(ID, A1) :- imposed_constraint(ID, _, A1, _, _).
|
||||||
|
imposed_packages(ID, A1) :- imposed_constraint(ID, _, A1, _, _, _).
|
||||||
|
imposed_packages(ID, A1) :- imposed_constraint(ID, "depends_on", _, A1, _).
|
||||||
|
|
||||||
|
imposed_nodes(ConditionID, PackageNode, node(X, A1))
|
||||||
|
:- imposed_packages(ConditionID, A1),
|
||||||
|
condition_set(PackageNode, node(X, A1), _),
|
||||||
|
node_condition(ConditionID, PackageNode).
|
||||||
|
|
||||||
|
imposed_nodes(ConditionID, PackageNode, node(X, A1))
|
||||||
|
:- imposed_packages(ConditionID, A1),
|
||||||
|
condition_set(PackageNode, node(X, A1), _),
|
||||||
|
attr("hash", PackageNode, ConditionID).
|
||||||
|
|
||||||
|
:- imposed_packages(ID, A1), impose(ID, PackageNode), not condition_set(PackageNode, node(_, A1)).
|
||||||
|
|
||||||
% Conditions that hold impose may impose constraints on other specs
|
% Conditions that hold impose may impose constraints on other specs
|
||||||
attr(Name, node(root_node_id, A1)) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, Name, A1).
|
attr(Name, node(X, A1)) :- impose(ID, PackageNode), imposed_constraint(ID, Name, A1), imposed_nodes(ID, PackageNode, node(X, A1)).
|
||||||
attr(Name, node(root_node_id, A1), A2) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, Name, A1, A2).
|
attr(Name, node(X, A1), A2) :- impose(ID, PackageNode), imposed_constraint(ID, Name, A1, A2), imposed_nodes(ID, PackageNode, node(X, A1)).
|
||||||
attr(Name, node(root_node_id, A1), A2, A3) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, Name, A1, A2, A3), not special_case(ID, Name, A1, A2, A3).
|
attr(Name, node(X, A1), A2, A3) :- impose(ID, PackageNode), imposed_constraint(ID, Name, A1, A2, A3), imposed_nodes(ID, PackageNode, node(X, A1)), not special_case(Name).
|
||||||
attr(Name, node(root_node_id, A1), A2, A3, A4) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, Name, A1, A2, A3, A4).
|
attr(Name, node(X, A1), A2, A3, A4) :- impose(ID, PackageNode), imposed_constraint(ID, Name, A1, A2, A3, A4), imposed_nodes(ID, PackageNode, node(X, A1)).
|
||||||
|
|
||||||
% Special cases
|
% For node flag sources we need to look at the condition_set of the source, since it is the dependent
|
||||||
special_case(ID, Name, A1, A2, A3) :- imposed_constraint(ID, Name, A1, A2, A3), Name == "node_flag_source".
|
% of the package on which I want to impose the constraint
|
||||||
special_case(ID, Name, A1, A2, A3) :- imposed_constraint(ID, Name, A1, A2, A3), Name == "depends_on".
|
attr("node_flag_source", node(X, A1), A2, node(Y, A3))
|
||||||
attr("node_flag_source", node(NodeID, Package), A2, node(0, A3)) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, "node_flag_source", Package, A2, A3).
|
:- impose(ID, node(X, A1)),
|
||||||
attr("depends_on", node(NodeID, Package), node(0, A2), A3) :- impose(ID, node(NodeID, Package)), imposed_constraint(ID, "depends_on", Package, A2, A3).
|
imposed_constraint(ID, "node_flag_source", A1, A2, A3),
|
||||||
|
condition_set(node(Y, A3), node(X, A1)).
|
||||||
|
|
||||||
|
% Here we can't use the condition set because it's a recursive definition, that doesn't define the
|
||||||
|
% node index, and leads to unsatisfiability. Hence we say that one and only one node index must
|
||||||
|
% satisfy the dependency.
|
||||||
|
1 { attr("depends_on", node(X, A1), node(0..Y-1, A2), A3) : max_nodes(A2, Y) } 1
|
||||||
|
:- impose(ID, node(X, A1)),
|
||||||
|
imposed_constraint(ID, "depends_on", A1, A2, A3).
|
||||||
|
|
||||||
% we cannot have additional variant values when we are working with concrete specs
|
% we cannot have additional variant values when we are working with concrete specs
|
||||||
:- attr("node", node(ID, Package)),
|
:- attr("node", node(ID, Package)),
|
||||||
|
@ -336,26 +440,22 @@ error(1, Msg)
|
||||||
% provider for that virtual then it depends on the provider
|
% provider for that virtual then it depends on the provider
|
||||||
attr("depends_on", PackageNode, ProviderNode, Type)
|
attr("depends_on", PackageNode, ProviderNode, Type)
|
||||||
:- dependency_holds(PackageNode, Virtual, Type),
|
:- dependency_holds(PackageNode, Virtual, Type),
|
||||||
provider(ProviderNode, node(0, Virtual)),
|
provider(ProviderNode, node(VirtualID, Virtual)),
|
||||||
not external(PackageNode).
|
not external(PackageNode).
|
||||||
|
|
||||||
attr("virtual_on_edge", PackageNode, ProviderNode, Virtual)
|
attr("virtual_on_edge", PackageNode, ProviderNode, Virtual)
|
||||||
:- dependency_holds(PackageNode, Virtual, Type),
|
:- dependency_holds(PackageNode, Virtual, Type),
|
||||||
provider(ProviderNode, node(0, Virtual)),
|
provider(ProviderNode, node(VirtualID, Virtual)),
|
||||||
not external(PackageNode).
|
not external(PackageNode).
|
||||||
|
|
||||||
% dependencies on virtuals also imply that the virtual is a virtual node
|
% dependencies on virtuals also imply that the virtual is a virtual node
|
||||||
attr("virtual_node", node(0, Virtual))
|
1 { attr("virtual_node", node(0..X-1, Virtual)) : max_nodes(Virtual, X) }
|
||||||
:- dependency_holds(PackageNode, Virtual, Type),
|
:- dependency_holds(PackageNode, Virtual, Type),
|
||||||
virtual(Virtual), not external(PackageNode).
|
virtual(Virtual), not external(PackageNode).
|
||||||
|
|
||||||
% If there's a virtual node, we must select one and only one provider.
|
% If there's a virtual node, we must select one and only one provider.
|
||||||
% The provider must be selected among the possible providers.
|
% The provider must be selected among the possible providers.
|
||||||
|
|
||||||
{ provider(node(0..X-1, Package), node(VirtualID, Virtual))
|
|
||||||
: facts(Package, possible_provider(Virtual)), max_nodes(Package, X) }
|
|
||||||
:- attr("virtual_node", node(VirtualID, Virtual)).
|
|
||||||
|
|
||||||
error(100, "Cannot find valid provider for virtual {0}", VirtualNode)
|
error(100, "Cannot find valid provider for virtual {0}", VirtualNode)
|
||||||
:- attr("virtual_node", VirtualNode),
|
:- attr("virtual_node", VirtualNode),
|
||||||
not provider(_, VirtualNode).
|
not provider(_, VirtualNode).
|
||||||
|
@ -376,10 +476,11 @@ attr("root", PackageNode) :- attr("virtual_root", VirtualNode), provider(Package
|
||||||
% for environments that are concretized together (e.g. where we
|
% for environments that are concretized together (e.g. where we
|
||||||
% asks to install "mpich" and "hdf5+mpi" and we want "mpich" to
|
% asks to install "mpich" and "hdf5+mpi" and we want "mpich" to
|
||||||
% be the mpi provider)
|
% be the mpi provider)
|
||||||
provider(PackageNode, node(0, Virtual)) :- attr("node", PackageNode), virtual_condition_holds(PackageNode, Virtual).
|
1 { provider(PackageNode, node(0..X-1, Virtual)) : max_nodes(Virtual, X) } 1 :- attr("node", PackageNode), virtual_condition_holds(PackageNode, Virtual).
|
||||||
|
:- 2 { provider(PackageNode, VirtualNode) }, attr("virtual_node", VirtualNode).
|
||||||
|
|
||||||
% The provider provides the virtual if some provider condition holds.
|
% The provider provides the virtual if some provider condition holds.
|
||||||
virtual_condition_holds(node(ProviderID, Provider), Virtual) :-virtual_condition_holds(ID, node(ProviderID, Provider), Virtual).
|
virtual_condition_holds(node(ProviderID, Provider), Virtual) :- virtual_condition_holds(ID, node(ProviderID, Provider), Virtual).
|
||||||
virtual_condition_holds(ID, node(ProviderID, Provider), Virtual) :-
|
virtual_condition_holds(ID, node(ProviderID, Provider), Virtual) :-
|
||||||
facts(Provider, provider_condition(ID, Virtual)),
|
facts(Provider, provider_condition(ID, Virtual)),
|
||||||
condition_holds(ID, node(ProviderID, Provider)),
|
condition_holds(ID, node(ProviderID, Provider)),
|
||||||
|
@ -387,7 +488,7 @@ virtual_condition_holds(ID, node(ProviderID, Provider), Virtual) :-
|
||||||
|
|
||||||
% A package cannot be the actual provider for a virtual if it does not
|
% A package cannot be the actual provider for a virtual if it does not
|
||||||
% fulfill the conditions to provide that virtual
|
% fulfill the conditions to provide that virtual
|
||||||
:- provider(PackageNode, node(0, Virtual)),
|
:- provider(PackageNode, node(VirtualID, Virtual)),
|
||||||
not virtual_condition_holds(PackageNode, Virtual),
|
not virtual_condition_holds(PackageNode, Virtual),
|
||||||
internal_error("Virtual when provides not respected").
|
internal_error("Virtual when provides not respected").
|
||||||
|
|
||||||
|
@ -398,13 +499,10 @@ virtual_condition_holds(ID, node(ProviderID, Provider), Virtual) :-
|
||||||
% A provider may have different possible weights depending on whether it's an external
|
% A provider may have different possible weights depending on whether it's an external
|
||||||
% or not, or on preferences expressed in packages.yaml etc. This rule ensures that
|
% or not, or on preferences expressed in packages.yaml etc. This rule ensures that
|
||||||
% we select the weight, among the possible ones, that minimizes the overall objective function.
|
% we select the weight, among the possible ones, that minimizes the overall objective function.
|
||||||
1 { provider_weight(DependencyNode, VirtualNode, Weight, Reason) :
|
1 { provider_weight(DependencyNode, VirtualNode, Weight) :
|
||||||
possible_provider_weight(DependencyNode, VirtualNode, Weight, Reason) } 1
|
possible_provider_weight(DependencyNode, VirtualNode, Weight, _) } 1
|
||||||
:- provider(DependencyNode, VirtualNode), internal_error("Package provider weights must be unique").
|
:- provider(DependencyNode, VirtualNode), internal_error("Package provider weights must be unique").
|
||||||
|
|
||||||
% Get rid or the reason for enabling the possible weight (useful for debugging)
|
|
||||||
provider_weight(DependencyNode, VirtualNode, Weight) :- provider_weight(DependencyNode, VirtualNode, Weight, _).
|
|
||||||
|
|
||||||
% A provider that is an external can use a weight of 0
|
% A provider that is an external can use a weight of 0
|
||||||
possible_provider_weight(DependencyNode, VirtualNode, 0, "external")
|
possible_provider_weight(DependencyNode, VirtualNode, 0, "external")
|
||||||
:- provider(DependencyNode, VirtualNode),
|
:- provider(DependencyNode, VirtualNode),
|
||||||
|
@ -412,15 +510,15 @@ possible_provider_weight(DependencyNode, VirtualNode, 0, "external")
|
||||||
|
|
||||||
% A provider mentioned in packages.yaml can use a weight
|
% A provider mentioned in packages.yaml can use a weight
|
||||||
% according to its priority in the list of providers
|
% according to its priority in the list of providers
|
||||||
possible_provider_weight(node(DependencyID, Dependency), node(0, Virtual), Weight, "packages_yaml")
|
possible_provider_weight(node(DependencyID, Dependency), node(VirtualID, Virtual), Weight, "packages_yaml")
|
||||||
:- provider(node(DependencyID, Dependency), node(0, Virtual)),
|
:- provider(node(DependencyID, Dependency), node(VirtualID, Virtual)),
|
||||||
depends_on(node(ID, Package), node(DependencyID, Dependency)),
|
depends_on(node(ID, Package), node(DependencyID, Dependency)),
|
||||||
facts(Package, provider_preference(Virtual, Dependency, Weight)).
|
facts(Package, provider_preference(Virtual, Dependency, Weight)).
|
||||||
|
|
||||||
% A provider mentioned in the default configuration can use a weight
|
% A provider mentioned in the default configuration can use a weight
|
||||||
% according to its priority in the list of providers
|
% according to its priority in the list of providers
|
||||||
possible_provider_weight(node(DependencyID, Dependency), node(0, Virtual), Weight, "default")
|
possible_provider_weight(node(DependencyID, Dependency), node(VirtualID, Virtual), Weight, "default")
|
||||||
:- provider(node(DependencyID, Dependency), node(0, Virtual)),
|
:- provider(node(DependencyID, Dependency), node(VirtualID, Virtual)),
|
||||||
default_provider_preference(Virtual, Dependency, Weight).
|
default_provider_preference(Virtual, Dependency, Weight).
|
||||||
|
|
||||||
% Any provider can use 100 as a weight, which is very high and discourage its use
|
% Any provider can use 100 as a weight, which is very high and discourage its use
|
||||||
|
@ -718,14 +816,14 @@ external_with_variant_set(node(NodeID, Package), Variant, Value)
|
||||||
variant_default_value(Package, Variant, Value)
|
variant_default_value(Package, Variant, Value)
|
||||||
:- facts(Package, variant_default_value_from_package_py(Variant, Value)),
|
:- facts(Package, variant_default_value_from_package_py(Variant, Value)),
|
||||||
not variant_default_value_from_packages_yaml(Package, Variant, _),
|
not variant_default_value_from_packages_yaml(Package, Variant, _),
|
||||||
not attr("variant_default_value_from_cli", node(0, Package), Variant, _).
|
not attr("variant_default_value_from_cli", node(root_node_id, Package), Variant, _).
|
||||||
|
|
||||||
variant_default_value(Package, Variant, Value)
|
variant_default_value(Package, Variant, Value)
|
||||||
:- variant_default_value_from_packages_yaml(Package, Variant, Value),
|
:- variant_default_value_from_packages_yaml(Package, Variant, Value),
|
||||||
not attr("variant_default_value_from_cli", node(0, Package), Variant, _).
|
not attr("variant_default_value_from_cli", node(root_node_id, Package), Variant, _).
|
||||||
|
|
||||||
variant_default_value(Package, Variant, Value) :-
|
variant_default_value(Package, Variant, Value) :-
|
||||||
attr("variant_default_value_from_cli", node(0, Package), Variant, Value).
|
attr("variant_default_value_from_cli", node(root_node_id, Package), Variant, Value).
|
||||||
|
|
||||||
% Treat 'none' in a special way - it cannot be combined with other
|
% Treat 'none' in a special way - it cannot be combined with other
|
||||||
% values even if the variant is multi-valued
|
% values even if the variant is multi-valued
|
||||||
|
@ -883,12 +981,12 @@ node_target_weight(node(ID, Package), Weight)
|
||||||
|
|
||||||
% compatibility rules for targets among nodes
|
% compatibility rules for targets among nodes
|
||||||
node_target_match(ParentNode, DependencyNode)
|
node_target_match(ParentNode, DependencyNode)
|
||||||
:- depends_on(ParentNode, DependencyNode),
|
:- attr("depends_on", ParentNode, DependencyNode, Type), Type != "build",
|
||||||
attr("node_target", ParentNode, Target),
|
attr("node_target", ParentNode, Target),
|
||||||
attr("node_target", DependencyNode, Target).
|
attr("node_target", DependencyNode, Target).
|
||||||
|
|
||||||
node_target_mismatch(ParentNode, DependencyNode)
|
node_target_mismatch(ParentNode, DependencyNode)
|
||||||
:- depends_on(ParentNode, DependencyNode),
|
:- attr("depends_on", ParentNode, DependencyNode, Type), Type != "build",
|
||||||
not node_target_match(ParentNode, DependencyNode).
|
not node_target_match(ParentNode, DependencyNode).
|
||||||
|
|
||||||
% disallow reusing concrete specs that don't have a compatible target
|
% disallow reusing concrete specs that don't have a compatible target
|
||||||
|
@ -1186,9 +1284,14 @@ build_priority(PackageNode, 0) :- attr("node", PackageNode), not optimize_for_
|
||||||
% is displayed (clingo doesn't display sums over empty sets by default)
|
% is displayed (clingo doesn't display sums over empty sets by default)
|
||||||
|
|
||||||
% Try hard to reuse installed packages (i.e., minimize the number built)
|
% Try hard to reuse installed packages (i.e., minimize the number built)
|
||||||
opt_criterion(100, "number of packages to build (vs. reuse)").
|
opt_criterion(110, "number of packages to build (vs. reuse)").
|
||||||
|
#minimize { 0@110: #true }.
|
||||||
|
#minimize { 1@110,PackageNode : build(PackageNode), optimize_for_reuse() }.
|
||||||
|
|
||||||
|
opt_criterion(100, "number of nodes from the same package").
|
||||||
#minimize { 0@100: #true }.
|
#minimize { 0@100: #true }.
|
||||||
#minimize { 1@100,PackageNode : build(PackageNode), optimize_for_reuse() }.
|
#minimize { ID@100,Package : attr("node", node(ID, Package)) }.
|
||||||
|
#minimize { ID@100,Package : attr("virtual_node", node(ID, Package)) }.
|
||||||
#defined optimize_for_reuse/0.
|
#defined optimize_for_reuse/0.
|
||||||
|
|
||||||
% A condition group specifies one or more specs that must be satisfied.
|
% A condition group specifies one or more specs that must be satisfied.
|
||||||
|
@ -1369,34 +1472,6 @@ opt_criterion(5, "non-preferred targets").
|
||||||
build_priority(PackageNode, Priority)
|
build_priority(PackageNode, Priority)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
%-----------------
|
|
||||||
% Domain heuristic
|
|
||||||
%-----------------
|
|
||||||
#heuristic literal_solved(ID) : literal(ID). [1, sign]
|
|
||||||
#heuristic literal_solved(ID) : literal(ID). [50, init]
|
|
||||||
#heuristic attr("hash", PackageNode, Hash) : attr("root", PackageNode). [45, init]
|
|
||||||
|
|
||||||
#heuristic attr("version", node(0, Package), Version) : facts(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [40, true]
|
|
||||||
#heuristic version_weight(node(0, Package), 0) : facts(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [40, true]
|
|
||||||
#heuristic attr("variant_value", node(0, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", node(0, Package)). [40, true]
|
|
||||||
#heuristic attr("node_target", node(0, Package), Target) : facts(Package, target_weight(Target, 0)), attr("root", node(0, Package)). [40, true]
|
|
||||||
#heuristic node_target_weight(node(0, Package), 0) : attr("root", node(0, Package)). [40, true]
|
|
||||||
#heuristic node_compiler(node(0, Package), CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("root", node(0, Package)). [40, true]
|
|
||||||
|
|
||||||
#heuristic provider(PackageNode, VirtualNode) : possible_provider_weight(PackageNode, VirtualNode, 0, _), attr("virtual_node", VirtualNode). [30, true]
|
|
||||||
#heuristic provider_weight(Package, Virtual, 0, R) : possible_provider_weight(Package, Virtual, 0, R), attr("virtual_node", Virtual). [30, true]
|
|
||||||
#heuristic attr("node", Package) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [30, true]
|
|
||||||
|
|
||||||
#heuristic attr("version", node(ID, Package), Version) : facts(Package, version_declared(Version, 0)), attr("node", node(ID, Package)). [20, true]
|
|
||||||
#heuristic version_weight(node(ID, Package), 0) : facts(Package, version_declared(Version, 0)), attr("node", node(ID, Package)). [20, true]
|
|
||||||
|
|
||||||
#heuristic attr("node_target", node(ID, Package), Target) : facts(Package, target_weight(Target, 0)), attr("node", node(ID, Package)). [20, true]
|
|
||||||
#heuristic node_target_weight(Package, 0) : attr("node", Package). [20, true]
|
|
||||||
#heuristic node_compiler(node(ID, Package), ID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("node", node(NodeID, Package)). [15, true]
|
|
||||||
|
|
||||||
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)). [10, true]
|
|
||||||
#heuristic attr("node_os", PackageNode, OS) : buildable_os(OS). [10, true]
|
|
||||||
|
|
||||||
%-----------
|
%-----------
|
||||||
% Notes
|
% Notes
|
||||||
%-----------
|
%-----------
|
||||||
|
|
28
lib/spack/spack/solver/heuristic.lp
Normal file
28
lib/spack/spack/solver/heuristic.lp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
% Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
|
||||||
|
% Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
%
|
||||||
|
% SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
%-----------------
|
||||||
|
% Domain heuristic
|
||||||
|
%-----------------
|
||||||
|
#heuristic literal_solved(ID) : literal(ID). [1, sign]
|
||||||
|
#heuristic literal_solved(ID) : literal(ID). [50, init]
|
||||||
|
|
||||||
|
#heuristic attr("hash", node(0, Package), Hash) : literal(_, "root", Package). [45, init]
|
||||||
|
#heuristic attr("root", node(0, Package)) : literal(_, "root", Package). [45, true]
|
||||||
|
#heuristic attr("node", node(0, Package)) : literal(_, "root", Package). [45, true]
|
||||||
|
#heuristic attr("node", node(0, Package)) : literal(_, "node", Package). [45, true]
|
||||||
|
|
||||||
|
#heuristic attr("version", node(0, Package), Version) : facts(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [40, true]
|
||||||
|
#heuristic version_weight(node(0, Package), 0) : facts(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [40, true]
|
||||||
|
#heuristic attr("variant_value", node(0, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", node(0, Package)). [40, true]
|
||||||
|
#heuristic attr("node_target", node(0, Package), Target) : facts(Package, target_weight(Target, 0)), attr("root", node(0, Package)). [40, true]
|
||||||
|
#heuristic node_target_weight(node(0, Package), 0) : attr("root", node(0, Package)). [40, true]
|
||||||
|
#heuristic node_compiler(node(0, Package), CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("root", node(0, Package)). [40, true]
|
||||||
|
|
||||||
|
#heuristic version_weight(node(0, Package), 0) : attr("node", node(0, Package)). [20, true]
|
||||||
|
|
||||||
|
#heuristic attr("node_target", node(0, Package), Target) : facts(Package, target_weight(Target, 0)), attr("node", node(0, Package)). [20, true]
|
||||||
|
#heuristic node_target_weight(PackageNode, 0) : attr("node", PackageNode). [20, true]
|
||||||
|
#heuristic node_compiler(node(0, Package), ID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("node", node(0, Package)). [15, true]
|
Loading…
Reference in a new issue