ASP-based solver: permit to use virtual specs in environments (#24199)
Extracting specs for the result of a solve has been factored as a method into the asp.Result class. The method account for virtual specs being passed as initial requests.
This commit is contained in:
parent
e321578bbe
commit
f33c4e7280
4 changed files with 50 additions and 17 deletions
|
@ -116,9 +116,7 @@ def solve(parser, args):
|
||||||
|
|
||||||
# dump the solutions as concretized specs
|
# dump the solutions as concretized specs
|
||||||
if 'solutions' in dump:
|
if 'solutions' in dump:
|
||||||
best = min(result.answers)
|
opt, _, _ = min(result.answers)
|
||||||
|
|
||||||
opt, _, answer = best
|
|
||||||
if ("opt" in dump) and (not args.format):
|
if ("opt" in dump) and (not args.format):
|
||||||
tty.msg("Best of %d considered solutions." % result.nmodels)
|
tty.msg("Best of %d considered solutions." % result.nmodels)
|
||||||
tty.msg("Optimization Criteria:")
|
tty.msg("Optimization Criteria:")
|
||||||
|
@ -132,16 +130,7 @@ def solve(parser, args):
|
||||||
color.cprint(fmt % (i + 1, name, val))
|
color.cprint(fmt % (i + 1, name, val))
|
||||||
print()
|
print()
|
||||||
|
|
||||||
# iterate over roots from command line
|
for spec in result.specs:
|
||||||
for input_spec in specs:
|
|
||||||
key = input_spec.name
|
|
||||||
if input_spec.virtual:
|
|
||||||
providers = [spec.name for spec in answer.values()
|
|
||||||
if spec.package.provides(key)]
|
|
||||||
key = providers[0]
|
|
||||||
|
|
||||||
spec = answer[key]
|
|
||||||
|
|
||||||
# With -y, just print YAML to output.
|
# With -y, just print YAML to output.
|
||||||
if args.format == 'yaml':
|
if args.format == 'yaml':
|
||||||
# use write because to_yaml already has a newline.
|
# use write because to_yaml already has a newline.
|
||||||
|
|
|
@ -737,8 +737,7 @@ def _concretize_specs_together_new(*abstract_specs, **kwargs):
|
||||||
result.print_cores()
|
result.print_cores()
|
||||||
tty.die("Unsatisfiable spec.")
|
tty.die("Unsatisfiable spec.")
|
||||||
|
|
||||||
opt, i, answer = min(result.answers)
|
return [s.copy() for s in result.specs]
|
||||||
return [answer[s.name].copy() for s in abstract_specs]
|
|
||||||
|
|
||||||
|
|
||||||
def _concretize_specs_together_original(*abstract_specs, **kwargs):
|
def _concretize_specs_together_original(*abstract_specs, **kwargs):
|
||||||
|
|
|
@ -197,7 +197,7 @@ def check_packages_exist(specs):
|
||||||
|
|
||||||
class Result(object):
|
class Result(object):
|
||||||
"""Result of an ASP solve."""
|
"""Result of an ASP solve."""
|
||||||
def __init__(self, asp=None):
|
def __init__(self, specs, asp=None):
|
||||||
self.asp = asp
|
self.asp = asp
|
||||||
self.satisfiable = None
|
self.satisfiable = None
|
||||||
self.optimal = None
|
self.optimal = None
|
||||||
|
@ -211,12 +211,45 @@ def __init__(self, asp=None):
|
||||||
# names of optimization criteria
|
# names of optimization criteria
|
||||||
self.criteria = []
|
self.criteria = []
|
||||||
|
|
||||||
|
# Abstract user requests
|
||||||
|
self.abstract_specs = specs
|
||||||
|
|
||||||
|
# Concrete specs
|
||||||
|
self._concrete_specs = None
|
||||||
|
|
||||||
def print_cores(self):
|
def print_cores(self):
|
||||||
for core in self.cores:
|
for core in self.cores:
|
||||||
tty.msg(
|
tty.msg(
|
||||||
"The following constraints are unsatisfiable:",
|
"The following constraints are unsatisfiable:",
|
||||||
*sorted(str(symbol) for symbol in core))
|
*sorted(str(symbol) for symbol in core))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def specs(self):
|
||||||
|
"""List of concretized specs satisfying the initial
|
||||||
|
abstract request.
|
||||||
|
"""
|
||||||
|
# The specs were already computed, return them
|
||||||
|
if self._concrete_specs:
|
||||||
|
return self._concrete_specs
|
||||||
|
|
||||||
|
# Assert prerequisite
|
||||||
|
msg = 'cannot compute specs ["satisfiable" is not True ]'
|
||||||
|
assert self.satisfiable, msg
|
||||||
|
|
||||||
|
self._concrete_specs = []
|
||||||
|
best = min(self.answers)
|
||||||
|
opt, _, answer = best
|
||||||
|
for input_spec in self.abstract_specs:
|
||||||
|
key = input_spec.name
|
||||||
|
if input_spec.virtual:
|
||||||
|
providers = [spec.name for spec in answer.values()
|
||||||
|
if spec.package.provides(key)]
|
||||||
|
key = providers[0]
|
||||||
|
|
||||||
|
self._concrete_specs.append(answer[key])
|
||||||
|
|
||||||
|
return self._concrete_specs
|
||||||
|
|
||||||
|
|
||||||
def _normalize_packages_yaml(packages_yaml):
|
def _normalize_packages_yaml(packages_yaml):
|
||||||
normalized_yaml = copy.copy(packages_yaml)
|
normalized_yaml = copy.copy(packages_yaml)
|
||||||
|
@ -329,7 +362,7 @@ def solve(
|
||||||
timer.phase("ground")
|
timer.phase("ground")
|
||||||
|
|
||||||
# With a grounded program, we can run the solve.
|
# With a grounded program, we can run the solve.
|
||||||
result = Result()
|
result = Result(specs)
|
||||||
models = [] # stable models if things go well
|
models = [] # stable models if things go well
|
||||||
cores = [] # unsatisfiable cores if they do not
|
cores = [] # unsatisfiable cores if they do not
|
||||||
|
|
||||||
|
|
|
@ -2561,3 +2561,15 @@ def test_multiple_modules_post_env_hook(tmpdir, install_mockery, mock_fetch):
|
||||||
|
|
||||||
assert view_prefix not in full_contents
|
assert view_prefix not in full_contents
|
||||||
assert spec.prefix in full_contents
|
assert spec.prefix in full_contents
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.regression('24148')
|
||||||
|
def test_virtual_spec_concretize_together(tmpdir):
|
||||||
|
# An environment should permit to concretize "mpi"
|
||||||
|
e = ev.create('virtual_spec')
|
||||||
|
e.concretization = 'together'
|
||||||
|
|
||||||
|
e.add('mpi')
|
||||||
|
e.concretize()
|
||||||
|
|
||||||
|
assert any(s.package.provides('mpi') for _, s in e.concretized_specs())
|
||||||
|
|
Loading…
Reference in a new issue