summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/solve.py33
-rw-r--r--lib/spack/spack/solver/asp.py16
-rw-r--r--lib/spack/spack/solver/concretize.lp33
-rw-r--r--lib/spack/spack/solver/display.lp14
4 files changed, 78 insertions, 18 deletions
diff --git a/lib/spack/spack/cmd/solve.py b/lib/spack/spack/cmd/solve.py
index 64219b300f..e81161de90 100644
--- a/lib/spack/spack/cmd/solve.py
+++ b/lib/spack/spack/cmd/solve.py
@@ -10,6 +10,7 @@ import re
import sys
import llnl.util.tty as tty
+import llnl.util.tty.color as color
import spack
import spack.cmd
@@ -23,15 +24,20 @@ section = 'developer'
level = 'long'
#: output options
-show_options = ('asp', 'output', 'solutions')
+show_options = ('asp', 'opt', 'output', 'solutions')
def setup_parser(subparser):
# Solver arguments
subparser.add_argument(
- '--show', action='store', default=('solutions'),
- help="outputs: a list with any of: "
- "%s (default), all" % ', '.join(show_options))
+ '--show', action='store', default='opt,solutions',
+ help="select outputs: comma-separated list of: \n"
+ " asp asp program text\n"
+ " opt optimization criteria for best model\n"
+ " output raw clingo output\n"
+ " solutions models found by asp program\n"
+ " all all of the above"
+ )
subparser.add_argument(
'--models', action='store', type=int, default=0,
help="number of solutions to search (default 0 for all)")
@@ -41,10 +47,10 @@ def setup_parser(subparser):
subparser, ['long', 'very_long', 'install_status'])
subparser.add_argument(
'-y', '--yaml', action='store_const', dest='format', default=None,
- const='yaml', help='print concrete spec as YAML')
+ const='yaml', help='print concrete spec as yaml')
subparser.add_argument(
'-j', '--json', action='store_const', dest='format', default=None,
- const='json', help='print concrete spec as YAML')
+ const='json', help='print concrete spec as json')
subparser.add_argument(
'-c', '--cover', action='store',
default='nodes', choices=['nodes', 'edges', 'paths'],
@@ -113,9 +119,18 @@ def solve(parser, args):
best = min(result.answers)
opt, _, answer = best
- if not args.format:
- tty.msg("Best of %d answers." % result.nmodels)
- tty.msg("Optimization: %s" % opt)
+ if ("opt" in dump) and (not args.format):
+ tty.msg("Best of %d considered solutions." % result.nmodels)
+ tty.msg("Optimization Criteria:")
+
+ maxlen = max(len(s) for s in result.criteria)
+ color.cprint(
+ "@*{ Priority Criterion %sValue}" % ((maxlen - 10) * " ")
+ )
+ for i, (name, val) in enumerate(zip(result.criteria, opt)):
+ fmt = " @K{%%-8d} %%-%ds%%5d" % maxlen
+ color.cprint(fmt % (i + 1, name, val))
+ print()
# iterate over roots from command line
for input_spec in specs:
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 179dff2052..712a21b05b 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -207,6 +207,9 @@ class Result(object):
self.answers = []
self.cores = []
+ # names of optimization criteria
+ self.criteria = []
+
def print_cores(self):
for core in self.cores:
tty.msg(
@@ -354,6 +357,7 @@ class PyclingoDriver(object):
return x.string or str(x)
if result.satisfiable:
+ # build spec from the best model
builder = SpecBuilder(specs)
min_cost, best_model = min(models)
tuples = [
@@ -361,8 +365,20 @@ class PyclingoDriver(object):
for sym in best_model
]
answers = builder.build_specs(tuples)
+
+ # add best spec to the results
result.answers.append((list(min_cost), 0, answers))
+ # pull optimization criteria names out of the solution
+ criteria = [
+ (int(args[0]), args[1]) for name, args in tuples
+ if name == "opt_criterion"
+ ]
+ result.criteria = [t[1] for t in sorted(criteria, reverse=True)]
+
+ # record the number of models the solver considered
+ result.nmodels = len(models)
+
elif cores:
symbols = dict(
(a.literal, a.symbol)
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index cbde0076fb..898927a8a8 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -705,19 +705,31 @@ no_flags(Package, FlagType)
%-----------------------------------------------------------------------------
% How to optimize the spec (high to low priority)
%-----------------------------------------------------------------------------
+% Each criterion below has:
+% 1. an opt_criterion(ID, Name) fact that describes the criterion, and
+% 2. a `#minimize{ 0@2 : #true }.` statement that ensures the criterion
+% is displayed (clingo doesn't display sums over empty sets by default)
% The highest priority is to minimize the:
% 1. Version weight
% 2. Number of variants with a non default value, if not set
% for the root(Package)
-#minimize { Weight@15 : root(Package),version_weight(Package, Weight)}.
+opt_criterion(15, "version weight").
+#minimize{ 0@15 : #true }.
+#minimize { Weight@15 : root(Package),version_weight(Package, Weight) }.
+
+opt_criterion(14, "number of non-default variants (roots)").
+#minimize{ 0@14 : #true }.
#minimize {
Weight@14,Package,Variant,Value
: variant_not_default(Package, Variant, Value, Weight), root(Package)
}.
+
% If the value is a multivalued variant there could be multiple
% values set as default. Since a default value has a weight of 0 we
% need to maximize their number below to ensure they're all set
+opt_criterion(13, "multi-valued variants + preferred providers for roots").
+#minimize{ 0@13 : #true }.
#maximize {
1@13,Package,Variant,Value
: variant_not_default(Package, Variant, Value, Weight),
@@ -730,19 +742,27 @@ no_flags(Package, FlagType)
}.
% Try to use default variants or variants that have been set
+opt_criterion(11, "number of non-default variants (non-roots)").
+#minimize{ 0@11 : #true }.
#minimize {
Weight@11,Package,Variant,Value
: variant_not_default(Package, Variant, Value, Weight), not root(Package)
}.
+
% Minimize the weights of the providers, i.e. use as much as
% possible the most preferred providers
+opt_criterion(9, "number of non-default providers (non-roots)").
+#minimize{ 0@9 : #true }.
#minimize{
Weight@9,Provider
: provider_weight(Provider, Weight), not root(Provider)
}.
+
% If the value is a multivalued variant there could be multiple
% values set as default. Since a default value has a weight of 0 we
% need to maximize their number below to ensure they're all set
+opt_criterion(8, "count of non-root multi-valued variants").
+#minimize{ 0@8 : #true }.
#maximize {
1@8,Package,Variant,Value
: variant_not_default(Package, Variant, Value, Weight),
@@ -754,18 +774,29 @@ no_flags(Package, FlagType)
% while minimizing the number of nodes. This is done because
% a maximization on the number of matches for compilers is highly
% correlated to a preference to have as many nodes as possible
+opt_criterion(7, "compiler matches + number of nodes").
+#minimize{ 0@7 : #true }.
#minimize{ 1@7,Package : node(Package) }.
#maximize{ Weight@7,Package : compiler_version_match(Package, Weight) }.
% Choose more recent versions for nodes
+opt_criterion(6, "version badness").
+#minimize{ 0@6 : #true }.
#minimize{
Weight@6,Package : version_weight(Package, Weight)
}.
% Try to use preferred compilers
+opt_criterion(5, "non-preferred compilers").
+#minimize{ 0@5 : #true }.
#minimize{ Weight@5,Package : compiler_weight(Package, Weight) }.
% Maximize the number of matches for targets in the DAG, try
% to select the preferred target.
+opt_criterion(4, "target matches").
+#minimize{ 0@4 : #true }.
#maximize{ Weight@4,Package : node_target_match(Package, Weight) }.
+
+opt_criterion(3, "non-preferred targets").
+#minimize{ 0@3 : #true }.
#minimize{ Weight@3,Package : node_target_weight(Package, Weight) }.
diff --git a/lib/spack/spack/solver/display.lp b/lib/spack/spack/solver/display.lp
index f67c4b6c3c..c1231ca62a 100644
--- a/lib/spack/spack/solver/display.lp
+++ b/lib/spack/spack/solver/display.lp
@@ -8,6 +8,9 @@
%
% This section determines what parts of the model are printed at the end
%==============================================================================
+
+% Spec-related functions.
+% Used to build the result of the solve.
#show node/1.
#show depends_on/3.
#show version/2.
@@ -21,12 +24,7 @@
#show node_flag_compiler_default/1.
#show node_flag_source/2.
#show no_flags/2.
-
-#show variant_not_default/4.
-#show provider_weight/2.
-#show version_weight/2.
-#show compiler_version_match/2.
-#show compiler_weight/2.
-#show node_target_match/2.
-#show node_target_weight/2.
#show external_spec_selected/2.
+
+% names of optimization criteria
+#show opt_criterion/2.