ASP-based solver: add a generic rule for propagation (#44870)

This adds a generic propagate/2 rule to propagate any
fact to children in the DAG.
This commit is contained in:
Massimiliano Culpo 2024-06-26 16:02:00 +02:00 committed by Harmen Stoppels
parent 8628add66b
commit 249dcb49e2
2 changed files with 44 additions and 41 deletions

View file

@ -1878,11 +1878,8 @@ def _spec_clauses(
) )
clauses.append(f.variant_value(spec.name, vname, value)) clauses.append(f.variant_value(spec.name, vname, value))
if variant.propagate: if variant.propagate:
clauses.append( clauses.append(f.propagate(spec.name, fn.variant_value(vname, value)))
f.variant_propagation_candidate(spec.name, vname, value, spec.name)
)
# Tell the concretizer that this is a possible value for the # Tell the concretizer that this is a possible value for the
# variant, to account for things like int/str values where we # variant, to account for things like int/str values where we
@ -2737,7 +2734,7 @@ class _Head:
node_flag = fn.attr("node_flag_set") node_flag = fn.attr("node_flag_set")
node_flag_source = fn.attr("node_flag_source") node_flag_source = fn.attr("node_flag_source")
node_flag_propagate = fn.attr("node_flag_propagate") node_flag_propagate = fn.attr("node_flag_propagate")
variant_propagation_candidate = fn.attr("variant_propagation_candidate") propagate = fn.attr("propagate")
class _Body: class _Body:
@ -2754,7 +2751,7 @@ class _Body:
node_flag = fn.attr("node_flag") node_flag = fn.attr("node_flag")
node_flag_source = fn.attr("node_flag_source") node_flag_source = fn.attr("node_flag_source")
node_flag_propagate = fn.attr("node_flag_propagate") node_flag_propagate = fn.attr("node_flag_propagate")
variant_propagation_candidate = fn.attr("variant_propagation_candidate") propagate = fn.attr("propagate")
class ProblemInstanceBuilder: class ProblemInstanceBuilder:

View file

@ -811,37 +811,6 @@ node_has_variant(node(ID, Package), Variant) :-
pkg_fact(Package, variant(Variant)), pkg_fact(Package, variant(Variant)),
attr("node", node(ID, Package)). attr("node", node(ID, Package)).
% Variant propagation is forwarded to dependencies
attr("variant_propagation_candidate", PackageNode, Variant, Value, Source) :-
attr("node", PackageNode),
depends_on(ParentNode, PackageNode),
attr("variant_value", node(_, Source), Variant, Value),
attr("variant_propagation_candidate", ParentNode, Variant, _, Source).
% If the node is a candidate, and it has the variant and value,
% then those variant and value should be propagated
attr("variant_propagate", node(ID, Package), Variant, Value, Source) :-
attr("variant_propagation_candidate", node(ID, Package), Variant, Value, Source),
node_has_variant(node(ID, Package), Variant),
pkg_fact(Package, variant_possible_value(Variant, Value)),
not attr("variant_set", node(ID, Package), Variant).
% Propagate the value, if there is the corresponding attribute
attr("variant_value", PackageNode, Variant, Value) :- attr("variant_propagate", PackageNode, Variant, Value, _).
% If a variant is propagated, we cannot have extraneous values (this is for multi valued variants)
variant_is_propagated(PackageNode, Variant) :- attr("variant_propagate", PackageNode, Variant, _, _).
:- variant_is_propagated(PackageNode, Variant),
attr("variant_value", PackageNode, Variant, Value),
not attr("variant_propagate", PackageNode, Variant, Value, _).
% Cannot receive different values from different sources on the same variant
error(100, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
attr("variant_propagate", node(X, Package), Variant, Value1, Source1),
attr("variant_propagate", node(X, Package), Variant, Value2, Source2),
node_has_variant(node(X, Package), Variant),
Value1 < Value2, Source1 < Source2.
% a variant cannot be set if it is not a variant on the package % a variant cannot be set if it is not a variant on the package
error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package) error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
:- attr("variant_set", node(X, Package), Variant), :- attr("variant_set", node(X, Package), Variant),
@ -919,7 +888,7 @@ variant_not_default(node(ID, Package), Variant, Value)
% variants set explicitly on the CLI don't count as non-default % variants set explicitly on the CLI don't count as non-default
not attr("variant_set", node(ID, Package), Variant, Value), not attr("variant_set", node(ID, Package), Variant, Value),
% variant values forced by propagation don't count as non-default % variant values forced by propagation don't count as non-default
not attr("variant_propagate", node(ID, Package), Variant, Value, _), not propagate(node(ID, Package), variant_value(Variant, Value)),
% variants set on externals that we could use don't count as non-default % variants set on externals that we could use don't count as non-default
% this makes spack prefer to use an external over rebuilding with the % this makes spack prefer to use an external over rebuilding with the
% default configuration % default configuration
@ -932,7 +901,7 @@ variant_default_not_used(node(ID, Package), Variant, Value)
:- variant_default_value(Package, Variant, Value), :- variant_default_value(Package, Variant, Value),
node_has_variant(node(ID, Package), Variant), node_has_variant(node(ID, Package), Variant),
not attr("variant_value", node(ID, Package), Variant, Value), not attr("variant_value", node(ID, Package), Variant, Value),
not attr("variant_propagate", node(ID, Package), Variant, _, _), not propagate(node(ID, Package), variant_value(Variant, _)),
attr("node", node(ID, Package)). attr("node", node(ID, Package)).
% The variant is set in an external spec % The variant is set in an external spec
@ -989,6 +958,43 @@ pkg_fact(Package, variant_single_value("dev_path"))
#defined variant_default_value/3. #defined variant_default_value/3.
#defined variant_default_value_from_packages_yaml/3. #defined variant_default_value_from_packages_yaml/3.
%-----------------------------------------------------------------------------
% Propagation semantics
%-----------------------------------------------------------------------------
% Propagation roots have a corresponding attr("propagate", ...)
propagate(RootNode, PropagatedAttribute) :- attr("propagate", RootNode, PropagatedAttribute).
% Propagate an attribute along edges to child nodes
propagate(ChildNode, PropagatedAttribute) :-
propagate(ParentNode, PropagatedAttribute),
depends_on(ParentNode, ChildNode).
%-----------------------------------------------------------------------------
% Activation of propagated values
%-----------------------------------------------------------------------------
%----
% Variants
%----
% If a variant is propagated, and can be accepted, set its value
attr("variant_value", node(ID, Package), Variant, Value) :-
propagate(node(ID, Package), variant_value(Variant, Value)),
node_has_variant(node(ID, Package), Variant),
pkg_fact(Package, variant_possible_value(Variant, Value)),
not attr("variant_set", node(ID, Package), Variant).
% If a variant is propagated, we cannot have extraneous values
variant_is_propagated(PackageNode, Variant) :-
attr("variant_value", PackageNode, Variant, Value),
propagate(PackageNode, variant_value(Variant, Value)),
not attr("variant_set", PackageNode, Variant).
:- variant_is_propagated(PackageNode, Variant),
attr("variant_value", PackageNode, Variant, Value),
not propagate(PackageNode, variant_value(Variant, Value)).
%----------------------------------------------------------------------------- %-----------------------------------------------------------------------------
% Platform semantics % Platform semantics
%----------------------------------------------------------------------------- %-----------------------------------------------------------------------------
@ -1496,7 +1502,7 @@ opt_criterion(45, "preferred providers (non-roots)").
}. }.
% Try to minimize the number of compiler mismatches in the DAG. % Try to minimize the number of compiler mismatches in the DAG.
opt_criterion(40, "compiler mismatches that are not from CLI"). opt_criterion(40, "compiler mismatches that are not required").
#minimize{ 0@240: #true }. #minimize{ 0@240: #true }.
#minimize{ 0@40: #true }. #minimize{ 0@40: #true }.
#minimize{ #minimize{
@ -1506,7 +1512,7 @@ opt_criterion(40, "compiler mismatches that are not from CLI").
not runtime(Dependency) not runtime(Dependency)
}. }.
opt_criterion(39, "compiler mismatches that are not from CLI"). opt_criterion(39, "compiler mismatches that are required").
#minimize{ 0@239: #true }. #minimize{ 0@239: #true }.
#minimize{ 0@39: #true }. #minimize{ 0@39: #true }.
#minimize{ #minimize{