refactor: convert spack.solver.asp.solve() to a class
The solver has a lot of configuration associated with it. Rather than adding arguments to everything, we should encapsulate that in a class. This is the start of that work; it replaces `solve()` and its kwargs with a class and properties.
This commit is contained in:
parent
87a3b72ef0
commit
1903e45eec
@ -102,11 +102,15 @@ def solve(parser, args):
|
||||
|
||||
specs = spack.cmd.parse_specs(args.specs)
|
||||
|
||||
# dump generated ASP program
|
||||
result = asp.solve(
|
||||
specs, dump=dump, models=models, timers=args.timers, stats=args.stats,
|
||||
reuse=args.reuse,
|
||||
)
|
||||
# set up solver parameters
|
||||
solver = asp.Solver()
|
||||
solver.reuse = args.reuse
|
||||
solver.dump = dump
|
||||
solver.models = models
|
||||
solver.timers = args.timers
|
||||
solver.stats = args.stats
|
||||
|
||||
result = solver.solve(specs)
|
||||
if 'solutions' not in dump:
|
||||
return
|
||||
|
||||
|
@ -748,11 +748,12 @@ def concretize_specs_together(*abstract_specs, **kwargs):
|
||||
|
||||
def _concretize_specs_together_new(*abstract_specs, **kwargs):
|
||||
import spack.solver.asp
|
||||
concretization_kwargs = {
|
||||
'tests': kwargs.get('tests', False),
|
||||
'reuse': kwargs.get('reuse', False)
|
||||
}
|
||||
result = spack.solver.asp.solve(abstract_specs, **concretization_kwargs)
|
||||
|
||||
solver = spack.solver.asp.Solver()
|
||||
solver.tests = kwargs.get('tests', False)
|
||||
solver.reuse = kwargs.get('reuse', False)
|
||||
|
||||
result = solver.solve(abstract_specs)
|
||||
result.raise_if_unsat()
|
||||
return [s.copy() for s in result.specs]
|
||||
|
||||
|
@ -529,7 +529,7 @@ def fact(self, head, assumption=False):
|
||||
|
||||
def solve(
|
||||
self, solver_setup, specs, dump=None, nmodels=0,
|
||||
timers=False, stats=False, tests=False, reuse=False,
|
||||
timers=False, stats=False,
|
||||
):
|
||||
timer = spack.util.timer.Timer()
|
||||
|
||||
@ -545,7 +545,7 @@ def solve(
|
||||
self.assumptions = []
|
||||
with self.control.backend() as backend:
|
||||
self.backend = backend
|
||||
solver_setup.setup(self, specs, tests=tests, reuse=reuse)
|
||||
solver_setup.setup(self, specs)
|
||||
timer.phase("setup")
|
||||
|
||||
# read in the main ASP program and display logic -- these are
|
||||
@ -640,7 +640,7 @@ def stringify(x):
|
||||
class SpackSolverSetup(object):
|
||||
"""Class to set up and run a Spack concretization solve."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, reuse=False, tests=False):
|
||||
self.gen = None # set by setup()
|
||||
|
||||
self.declared_versions = {}
|
||||
@ -665,6 +665,12 @@ def __init__(self):
|
||||
# Caches to optimize the setup phase of the solver
|
||||
self.target_specs_cache = None
|
||||
|
||||
# whether to add installed/binary hashes to the solve
|
||||
self.reuse = reuse
|
||||
|
||||
# whether to add installed/binary hashes to the solve
|
||||
self.tests = tests
|
||||
|
||||
def pkg_version_rules(self, pkg):
|
||||
"""Output declared versions of a package.
|
||||
|
||||
@ -866,7 +872,7 @@ def pkg_rules(self, pkg, tests):
|
||||
self.package_provider_rules(pkg)
|
||||
|
||||
# dependencies
|
||||
self.package_dependencies_rules(pkg, tests)
|
||||
self.package_dependencies_rules(pkg)
|
||||
|
||||
# virtual preferences
|
||||
self.virtual_preferences(
|
||||
@ -932,17 +938,17 @@ def package_provider_rules(self, pkg):
|
||||
))
|
||||
self.gen.newline()
|
||||
|
||||
def package_dependencies_rules(self, pkg, tests):
|
||||
def package_dependencies_rules(self, pkg):
|
||||
"""Translate 'depends_on' directives into ASP logic."""
|
||||
for _, conditions in sorted(pkg.dependencies.items()):
|
||||
for cond, dep in sorted(conditions.items()):
|
||||
deptypes = dep.type.copy()
|
||||
# Skip test dependencies if they're not requested
|
||||
if not tests:
|
||||
if not self.tests:
|
||||
deptypes.discard("test")
|
||||
|
||||
# ... or if they are requested only for certain packages
|
||||
if not isinstance(tests, bool) and pkg.name not in tests:
|
||||
if not isinstance(self.tests, bool) and pkg.name not in self.tests:
|
||||
deptypes.discard("test")
|
||||
|
||||
# if there are no dependency types to be considered
|
||||
@ -1642,7 +1648,7 @@ def define_installed_packages(self, specs, possible):
|
||||
# TODO: (or any mirror really) doesn't have binaries.
|
||||
pass
|
||||
|
||||
def setup(self, driver, specs, tests=False, reuse=False):
|
||||
def setup(self, driver, specs):
|
||||
"""Generate an ASP program with relevant constraints for specs.
|
||||
|
||||
This calls methods on the solve driver to set up the problem with
|
||||
@ -1689,7 +1695,7 @@ def setup(self, driver, specs, tests=False, reuse=False):
|
||||
self.gen.h1("Concrete input spec definitions")
|
||||
self.define_concrete_input_specs(specs, possible)
|
||||
|
||||
if reuse:
|
||||
if self.reuse:
|
||||
self.gen.h1("Installed packages")
|
||||
self.gen.fact(fn.optimize_for_reuse())
|
||||
self.gen.newline()
|
||||
@ -1713,7 +1719,7 @@ def setup(self, driver, specs, tests=False, reuse=False):
|
||||
self.gen.h1('Package Constraints')
|
||||
for pkg in sorted(pkgs):
|
||||
self.gen.h2('Package rules: %s' % pkg)
|
||||
self.pkg_rules(pkg, tests=tests)
|
||||
self.pkg_rules(pkg, tests=self.tests)
|
||||
self.gen.h2('Package preferences: %s' % pkg)
|
||||
self.preferred_variants(pkg)
|
||||
self.preferred_targets(pkg)
|
||||
@ -2016,20 +2022,54 @@ def _develop_specs_from_env(spec, env):
|
||||
spec.constrain(dev_info['spec'])
|
||||
|
||||
|
||||
#
|
||||
# These are handwritten parts for the Spack ASP model.
|
||||
#
|
||||
def solve(specs, dump=(), models=0, timers=False, stats=False, tests=False,
|
||||
reuse=False):
|
||||
"""Solve for a stable model of specs.
|
||||
class Solver(object):
|
||||
"""This is the main external interface class for solving.
|
||||
|
||||
It manages solver configuration and preferences in once place. It sets up the solve
|
||||
and passes the setup method to the driver, as well.
|
||||
|
||||
Properties of interest:
|
||||
|
||||
``reuse (bool)``
|
||||
Whether to try to reuse existing installs/binaries
|
||||
|
||||
``show (tuple)``
|
||||
What information to print to the console while running. Options are:
|
||||
* asp: asp program text
|
||||
* opt: optimization criteria for best model
|
||||
* output: raw clingo output
|
||||
* solutions: models found by asp program
|
||||
* all: all of the above
|
||||
|
||||
``models (int)``
|
||||
Number of models to search (default: 0 for unlimited)
|
||||
|
||||
``timers (bool)``
|
||||
Print out coarse fimers for different solve phases.
|
||||
|
||||
``stats (bool)``
|
||||
Print out detailed stats from clingo
|
||||
|
||||
``tests (bool or tuple)``
|
||||
If ``True``, concretize test dependencies for all packages. If
|
||||
a tuple of package names, concretize test dependencies for named
|
||||
packages. If ``False``, do not concretize test dependencies.
|
||||
|
||||
Arguments:
|
||||
specs (list): list of Specs to solve.
|
||||
dump (tuple): what to dump
|
||||
models (int): number of models to search (default: 0)
|
||||
"""
|
||||
def __init__(self):
|
||||
self.set_default_configuration()
|
||||
|
||||
def set_default_configuration(self):
|
||||
self.reuse = False
|
||||
self.dump = ()
|
||||
self.models = 0
|
||||
self.timers = False
|
||||
self.stats = False
|
||||
self.tests = False
|
||||
|
||||
def solve(self, specs):
|
||||
driver = PyclingoDriver()
|
||||
if "asp" in dump:
|
||||
if "asp" in self.dump:
|
||||
driver.out = sys.stdout
|
||||
|
||||
# Check upfront that the variants are admissible
|
||||
@ -2039,9 +2079,9 @@ def solve(specs, dump=(), models=0, timers=False, stats=False, tests=False,
|
||||
continue
|
||||
spack.spec.Spec.ensure_valid_variants(s)
|
||||
|
||||
setup = SpackSolverSetup()
|
||||
setup = SpackSolverSetup(reuse=self.reuse, tests=self.tests)
|
||||
return driver.solve(
|
||||
setup, specs, dump, models, timers, stats, tests, reuse
|
||||
setup, specs, self.dump, self.models, self.timers, self.stats
|
||||
)
|
||||
|
||||
|
||||
|
@ -2615,7 +2615,11 @@ def _new_concretize(self, tests=False, reuse=False):
|
||||
if self._concrete:
|
||||
return
|
||||
|
||||
result = spack.solver.asp.solve([self], tests=tests, reuse=reuse)
|
||||
solver = spack.solver.asp.Solver()
|
||||
solver.reuse = reuse
|
||||
solver.tests = tests
|
||||
|
||||
result = solver.solve([self])
|
||||
result.raise_if_unsat()
|
||||
|
||||
# take the best answer
|
||||
|
Loading…
Reference in New Issue
Block a user