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:
Massimiliano Culpo 2021-06-08 19:04:49 +02:00 committed by GitHub
parent e321578bbe
commit f33c4e7280
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 17 deletions

View file

@ -116,9 +116,7 @@ def solve(parser, args):
# dump the solutions as concretized specs
if 'solutions' in dump:
best = min(result.answers)
opt, _, answer = best
opt, _, _ = min(result.answers)
if ("opt" in dump) and (not args.format):
tty.msg("Best of %d considered solutions." % result.nmodels)
tty.msg("Optimization Criteria:")
@ -132,16 +130,7 @@ def solve(parser, args):
color.cprint(fmt % (i + 1, name, val))
print()
# iterate over roots from command line
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]
for spec in result.specs:
# With -y, just print YAML to output.
if args.format == 'yaml':
# use write because to_yaml already has a newline.

View file

@ -737,8 +737,7 @@ def _concretize_specs_together_new(*abstract_specs, **kwargs):
result.print_cores()
tty.die("Unsatisfiable spec.")
opt, i, answer = min(result.answers)
return [answer[s.name].copy() for s in abstract_specs]
return [s.copy() for s in result.specs]
def _concretize_specs_together_original(*abstract_specs, **kwargs):

View file

@ -197,7 +197,7 @@ def check_packages_exist(specs):
class Result(object):
"""Result of an ASP solve."""
def __init__(self, asp=None):
def __init__(self, specs, asp=None):
self.asp = asp
self.satisfiable = None
self.optimal = None
@ -211,12 +211,45 @@ def __init__(self, asp=None):
# names of optimization criteria
self.criteria = []
# Abstract user requests
self.abstract_specs = specs
# Concrete specs
self._concrete_specs = None
def print_cores(self):
for core in self.cores:
tty.msg(
"The following constraints are unsatisfiable:",
*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):
normalized_yaml = copy.copy(packages_yaml)
@ -329,7 +362,7 @@ def solve(
timer.phase("ground")
# With a grounded program, we can run the solve.
result = Result()
result = Result(specs)
models = [] # stable models if things go well
cores = [] # unsatisfiable cores if they do not

View file

@ -2561,3 +2561,15 @@ def test_multiple_modules_post_env_hook(tmpdir, install_mockery, mock_fetch):
assert view_prefix not 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())