ASP-based solver: reduce input facts and add heuristic (#28848)
* Remove node_target_satisfies/3 in favor of target_satisfies/2 When emitting input facts we don't need to couple target with packages, but we can emit fewer facts independently and let the grounder combine them. * Remove compiler_version_satisfies/4 in favor of compiler_version_satisfies/3 When emitting input facts we don't need to couple compilers with packages, but we can emit fewer facts independently and let the grounder combine them. * Introduce heuristic in the ASP-program With heuristic we can drive clingo to make better initial guesses, which lead to fewer choices and conflicts in the overall solve
This commit is contained in:
parent
81a6d17f4c
commit
e6e109cbc5
@ -535,10 +535,9 @@ def solve(
|
|||||||
|
|
||||||
# Initialize the control object for the solver
|
# Initialize the control object for the solver
|
||||||
self.control = clingo.Control()
|
self.control = clingo.Control()
|
||||||
self.control.configuration.solve.models = nmodels
|
|
||||||
self.control.configuration.asp.trans_ext = 'all'
|
|
||||||
self.control.configuration.asp.eq = '5'
|
|
||||||
self.control.configuration.configuration = 'tweety'
|
self.control.configuration.configuration = 'tweety'
|
||||||
|
self.control.configuration.solve.models = nmodels
|
||||||
|
self.control.configuration.solver.heuristic = 'Domain'
|
||||||
self.control.configuration.solve.parallel_mode = '1'
|
self.control.configuration.solve.parallel_mode = '1'
|
||||||
self.control.configuration.solver.opt_strategy = "usc,one"
|
self.control.configuration.solver.opt_strategy = "usc,one"
|
||||||
|
|
||||||
@ -717,7 +716,7 @@ def target_ranges(self, spec, single_target_fn):
|
|||||||
if str(target) in archspec.cpu.TARGETS:
|
if str(target) in archspec.cpu.TARGETS:
|
||||||
return [single_target_fn(spec.name, target)]
|
return [single_target_fn(spec.name, target)]
|
||||||
|
|
||||||
self.target_constraints.add((spec.name, target))
|
self.target_constraints.add(target)
|
||||||
return [fn.node_target_satisfies(spec.name, target)]
|
return [fn.node_target_satisfies(spec.name, target)]
|
||||||
|
|
||||||
def conflict_rules(self, pkg):
|
def conflict_rules(self, pkg):
|
||||||
@ -1218,8 +1217,7 @@ class Body(object):
|
|||||||
clauses.append(
|
clauses.append(
|
||||||
fn.node_compiler_version_satisfies(
|
fn.node_compiler_version_satisfies(
|
||||||
spec.name, spec.compiler.name, spec.compiler.versions))
|
spec.name, spec.compiler.name, spec.compiler.versions))
|
||||||
self.compiler_version_constraints.add(
|
self.compiler_version_constraints.add(spec.compiler)
|
||||||
(spec.name, spec.compiler))
|
|
||||||
|
|
||||||
# compiler flags
|
# compiler flags
|
||||||
for flag_type, flags in spec.compiler_flags.items():
|
for flag_type, flags in spec.compiler_flags.items():
|
||||||
@ -1405,9 +1403,12 @@ def target_defaults(self, specs):
|
|||||||
for target in supported:
|
for target in supported:
|
||||||
best_targets.add(target.name)
|
best_targets.add(target.name)
|
||||||
self.gen.fact(fn.compiler_supports_target(
|
self.gen.fact(fn.compiler_supports_target(
|
||||||
compiler.name, compiler.version, target.name))
|
compiler.name, compiler.version, target.name
|
||||||
self.gen.fact(fn.compiler_supports_target(
|
))
|
||||||
compiler.name, compiler.version, uarch.family.name))
|
|
||||||
|
self.gen.fact(fn.compiler_supports_target(
|
||||||
|
compiler.name, compiler.version, uarch.family.name
|
||||||
|
))
|
||||||
|
|
||||||
# add any targets explicitly mentioned in specs
|
# add any targets explicitly mentioned in specs
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
@ -1536,18 +1537,12 @@ def versions_for(v):
|
|||||||
def define_compiler_version_constraints(self):
|
def define_compiler_version_constraints(self):
|
||||||
compiler_list = spack.compilers.all_compiler_specs()
|
compiler_list = spack.compilers.all_compiler_specs()
|
||||||
compiler_list = list(sorted(set(compiler_list)))
|
compiler_list = list(sorted(set(compiler_list)))
|
||||||
|
for constraint in sorted(self.compiler_version_constraints):
|
||||||
for pkg_name, cspec in self.compiler_version_constraints:
|
|
||||||
for compiler in compiler_list:
|
for compiler in compiler_list:
|
||||||
if compiler.satisfies(cspec):
|
if compiler.satisfies(constraint):
|
||||||
self.gen.fact(
|
self.gen.fact(fn.compiler_version_satisfies(
|
||||||
fn.node_compiler_version_satisfies(
|
constraint.name, constraint.versions, compiler.version
|
||||||
pkg_name,
|
))
|
||||||
cspec.name,
|
|
||||||
cspec.versions,
|
|
||||||
compiler.version
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.gen.newline()
|
self.gen.newline()
|
||||||
|
|
||||||
def define_target_constraints(self):
|
def define_target_constraints(self):
|
||||||
@ -1572,8 +1567,7 @@ def _all_targets_satisfiying(single_constraint):
|
|||||||
return allowed_targets
|
return allowed_targets
|
||||||
|
|
||||||
cache = {}
|
cache = {}
|
||||||
for spec_name, target_constraint in sorted(self.target_constraints):
|
for target_constraint in sorted(self.target_constraints):
|
||||||
|
|
||||||
# Construct the list of allowed targets for this constraint
|
# Construct the list of allowed targets for this constraint
|
||||||
allowed_targets = []
|
allowed_targets = []
|
||||||
for single_constraint in str(target_constraint).split(','):
|
for single_constraint in str(target_constraint).split(','):
|
||||||
@ -1584,11 +1578,7 @@ def _all_targets_satisfiying(single_constraint):
|
|||||||
allowed_targets.extend(cache[single_constraint])
|
allowed_targets.extend(cache[single_constraint])
|
||||||
|
|
||||||
for target in allowed_targets:
|
for target in allowed_targets:
|
||||||
self.gen.fact(
|
self.gen.fact(fn.target_satisfies(target_constraint, target))
|
||||||
fn.node_target_satisfies(
|
|
||||||
spec_name, target_constraint, target
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.gen.newline()
|
self.gen.newline()
|
||||||
|
|
||||||
def define_variant_values(self):
|
def define_variant_values(self):
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
:- not 1 { version(Package, _) } 1, node(Package).
|
:- not 1 { version(Package, _) } 1, node(Package).
|
||||||
|
|
||||||
% each node must have a single platform, os and target
|
% each node must have a single platform, os and target
|
||||||
:- not 1 { node_platform(Package, _) } 1, node(Package).
|
:- not 1 { node_platform(Package, _) } 1, node(Package), error("A node must have exactly one platform").
|
||||||
:- not 1 { node_os(Package, _) } 1, node(Package).
|
:- not 1 { node_os(Package, _) } 1, node(Package).
|
||||||
:- not 1 { node_target(Package, _) } 1, node(Package).
|
:- not 1 { node_target(Package, _) } 1, node(Package).
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ version_declared(Package, Version, Weight) :- version_declared(Package, Version,
|
|||||||
% We can't emit the same version **with the same weight** from two different sources
|
% We can't emit the same version **with the same weight** from two different sources
|
||||||
:- version_declared(Package, Version, Weight, Origin1),
|
:- version_declared(Package, Version, Weight, Origin1),
|
||||||
version_declared(Package, Version, Weight, Origin2),
|
version_declared(Package, Version, Weight, Origin2),
|
||||||
Origin1 != Origin2,
|
Origin1 < Origin2,
|
||||||
error("Internal error: two versions with identical weights").
|
error("Internal error: two versions with identical weights").
|
||||||
|
|
||||||
% versions are declared w/priority -- declared with priority implies declared
|
% versions are declared w/priority -- declared with priority implies declared
|
||||||
@ -450,7 +450,7 @@ variant_set(Package, Variant) :- variant_set(Package, Variant, _).
|
|||||||
variant_value(Package, Variant, Value2),
|
variant_value(Package, Variant, Value2),
|
||||||
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
|
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
|
||||||
variant_value_from_disjoint_sets(Package, Variant, Value2, Set2),
|
variant_value_from_disjoint_sets(Package, Variant, Value2, Set2),
|
||||||
Set1 != Set2,
|
Set1 < Set2,
|
||||||
build(Package),
|
build(Package),
|
||||||
error("Variant values selected from multiple disjoint sets").
|
error("Variant values selected from multiple disjoint sets").
|
||||||
|
|
||||||
@ -546,9 +546,6 @@ variant_single_value(Package, "dev_path")
|
|||||||
% Platform semantics
|
% Platform semantics
|
||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
% one platform per node
|
|
||||||
:- M = #count { Platform : node_platform(Package, Platform) }, M !=1, node(Package), error("A node must have exactly one platform").
|
|
||||||
|
|
||||||
% if no platform is set, fall back to the default
|
% if no platform is set, fall back to the default
|
||||||
node_platform(Package, Platform)
|
node_platform(Package, Platform)
|
||||||
:- node(Package),
|
:- node(Package),
|
||||||
@ -614,15 +611,21 @@ node_os(Package, OS) :- node_os_set(Package, OS), node(Package).
|
|||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
% Target semantics
|
% Target semantics
|
||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
% one target per node -- optimization will pick the "best" one
|
|
||||||
|
% Each node has only one target chosen among the known targets
|
||||||
1 { node_target(Package, Target) : target(Target) } 1 :- node(Package), error("Each node must have exactly one target").
|
1 { node_target(Package, Target) : target(Target) } 1 :- node(Package), error("Each node must have exactly one target").
|
||||||
|
|
||||||
% node_target_satisfies semantics
|
% If a node must satisfy a target constraint the choice is reduced among the targets
|
||||||
1 { node_target(Package, Target) : node_target_satisfies(Package, Constraint, Target) } 1
|
% that satisfy that constraint
|
||||||
|
1 { node_target(Package, Target) : target_satisfies(Constraint, Target) } 1
|
||||||
:- node_target_satisfies(Package, Constraint), error("Each node must have exactly one target").
|
:- node_target_satisfies(Package, Constraint), error("Each node must have exactly one target").
|
||||||
|
|
||||||
|
% If a node has a target and the target satisfies a constraint, then the target
|
||||||
|
% associated with the node satisfies the same constraint
|
||||||
node_target_satisfies(Package, Constraint)
|
node_target_satisfies(Package, Constraint)
|
||||||
:- node_target(Package, Target), node_target_satisfies(Package, Constraint, Target).
|
:- node_target(Package, Target), target_satisfies(Constraint, Target).
|
||||||
#defined node_target_satisfies/3.
|
|
||||||
|
#defined target_satisfies/2.
|
||||||
|
|
||||||
% The target weight is either the default target weight
|
% The target weight is either the default target weight
|
||||||
% or a more specific per-package weight if set
|
% or a more specific per-package weight if set
|
||||||
@ -702,20 +705,21 @@ node_compiler(Package, Compiler) :- node_compiler_version(Package, Compiler, _).
|
|||||||
Compiler1 != Compiler2,
|
Compiler1 != Compiler2,
|
||||||
error("Internal error: mismatch between selected compiler and compiler version").
|
error("Internal error: mismatch between selected compiler and compiler version").
|
||||||
|
|
||||||
% define node_compiler_version_satisfies/3 from node_compiler_version_satisfies/4
|
% If the compiler of a node must satisfy a constraint, then its version
|
||||||
% version_satisfies implies that exactly one of the satisfying versions
|
% must be chosen among the ones that satisfy said constraint
|
||||||
% is the package's version, and vice versa.
|
|
||||||
1 { node_compiler_version(Package, Compiler, Version)
|
1 { node_compiler_version(Package, Compiler, Version)
|
||||||
: node_compiler_version_satisfies(Package, Compiler, Constraint, Version) } 1 :-
|
: compiler_version_satisfies(Compiler, Constraint, Version) } 1 :-
|
||||||
node_compiler_version_satisfies(Package, Compiler, Constraint),
|
node_compiler_version_satisfies(Package, Compiler, Constraint),
|
||||||
error("Internal error: node compiler version mismatch").
|
error("Internal error: node compiler version mismatch").
|
||||||
|
|
||||||
|
% If the node is associated with a compiler and the compiler satisfy a constraint, then
|
||||||
|
% the compiler associated with the node satisfy the same constraint
|
||||||
node_compiler_version_satisfies(Package, Compiler, Constraint)
|
node_compiler_version_satisfies(Package, Compiler, Constraint)
|
||||||
:- node_compiler_version(Package, Compiler, Version),
|
:- node_compiler_version(Package, Compiler, Version),
|
||||||
node_compiler_version_satisfies(Package, Compiler, Constraint, Version),
|
compiler_version_satisfies(Compiler, Constraint, Version),
|
||||||
build(Package).
|
build(Package).
|
||||||
|
|
||||||
#defined node_compiler_version_satisfies/4.
|
#defined compiler_version_satisfies/3.
|
||||||
|
|
||||||
% If the compiler version was set from the command line,
|
% If the compiler version was set from the command line,
|
||||||
% respect it verbatim
|
% respect it verbatim
|
||||||
@ -1017,3 +1021,14 @@ opt_criterion(1, "non-preferred targets").
|
|||||||
: node_target_weight(Package, Weight),
|
: node_target_weight(Package, Weight),
|
||||||
build_priority(Package, Priority)
|
build_priority(Package, Priority)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
%-----------------
|
||||||
|
% Domain heuristic
|
||||||
|
%-----------------
|
||||||
|
#heuristic version(Package, Version) : version_declared(Package, Version, 0), node(Package). [10, true]
|
||||||
|
#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), node(Package). [10, true]
|
||||||
|
#heuristic node_target(Package, Target) : default_target_weight(Target, 0), node(Package). [10, true]
|
||||||
|
#heuristic node_target_weight(Package, 0) : node(Package). [10, true]
|
||||||
|
#heuristic variant_value(Package, Variant, Value) : variant_default_value(Package, Variant, Value), node(Package). [10, true]
|
||||||
|
#heuristic provider(Package, Virtual) : possible_provider_weight(Package, Virtual, 0, _), virtual_node(Virtual). [10, true]
|
||||||
|
#heuristic node(Package) : possible_provider_weight(Package, Virtual, 0, _), virtual_node(Virtual). [10, true]
|
||||||
|
Loading…
Reference in New Issue
Block a user