From 249dcb49e2f2faecf72a0383f20fab0203a71370 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 26 Jun 2024 16:02:00 +0200 Subject: [PATCH] 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. --- lib/spack/spack/solver/asp.py | 9 ++-- lib/spack/spack/solver/concretize.lp | 76 +++++++++++++++------------- 2 files changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 68a36a07d4..b875c9e986 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1878,11 +1878,8 @@ def _spec_clauses( ) clauses.append(f.variant_value(spec.name, vname, value)) - if variant.propagate: - clauses.append( - f.variant_propagation_candidate(spec.name, vname, value, spec.name) - ) + clauses.append(f.propagate(spec.name, fn.variant_value(vname, value))) # Tell the concretizer that this is a possible value for the # 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_source = fn.attr("node_flag_source") node_flag_propagate = fn.attr("node_flag_propagate") - variant_propagation_candidate = fn.attr("variant_propagation_candidate") + propagate = fn.attr("propagate") class _Body: @@ -2754,7 +2751,7 @@ class _Body: node_flag = fn.attr("node_flag") node_flag_source = fn.attr("node_flag_source") node_flag_propagate = fn.attr("node_flag_propagate") - variant_propagation_candidate = fn.attr("variant_propagation_candidate") + propagate = fn.attr("propagate") class ProblemInstanceBuilder: diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 20bcd46ad6..f437725bd7 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -811,37 +811,6 @@ node_has_variant(node(ID, Package), Variant) :- pkg_fact(Package, variant(Variant)), 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 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), @@ -919,7 +888,7 @@ variant_not_default(node(ID, Package), Variant, Value) % variants set explicitly on the CLI don't count as non-default not attr("variant_set", node(ID, Package), Variant, Value), % 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 % this makes spack prefer to use an external over rebuilding with the % default configuration @@ -932,7 +901,7 @@ variant_default_not_used(node(ID, Package), Variant, Value) :- variant_default_value(Package, Variant, Value), node_has_variant(node(ID, Package), Variant), 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)). % 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_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 %----------------------------------------------------------------------------- @@ -1496,7 +1502,7 @@ opt_criterion(45, "preferred providers (non-roots)"). }. % 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@40: #true }. #minimize{ @@ -1506,7 +1512,7 @@ opt_criterion(40, "compiler mismatches that are not from CLI"). 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@39: #true }. #minimize{