clingexplaid 1.2.0__tar.gz → 1.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/PKG-INFO +1 -1
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/mus/core_computer.py +63 -16
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_rule_id.py +1 -1
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid.egg-info/PKG-INFO +1 -1
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_rule_ids.lp +1 -1
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/test_muc.py +30 -8
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.envrc +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.github/workflows/deploy.yml +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.github/workflows/test.yml +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.gitignore +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.pre-commit-config.yaml +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/.readthedocs.yaml +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/CHANGES.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/CONTRIBUTING.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/DEPLOYMENT.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/DEVELOPMENT.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/LICENSE +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/LIMITATIONS.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/README.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/TODO.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/Makefile +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/_static/css/custom.css +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/_static/logo-dark-mode.png +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/_static/logo-light-mode.png +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/conf.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/content/encodings/index.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/content/encodings/instance.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/content/installation.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/content/quickstart.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/doc/index.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/graph_coloring/README.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/graph_coloring/encoding.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/graph_coloring/graph_coloring_example.svg +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/graph_coloring/instance.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/bad_mucs.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/sat.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/sat_simple.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/simple.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/soup.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/sudoku_4x4.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/sudoku_encoding.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/sudoku_encoding_2.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test/blob.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test2.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test3.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test4.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/test_inert.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/x.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/misc/zero_arity_assumptions.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/queens/README.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/queens/encoding.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/queens/instance.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/queens/queens_example.svg +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/sudoku/README.md +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/sudoku/encoding.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/sudoku/instance.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/sudoku/sudoku_example.svg +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/noxfile.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/pyproject.toml +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/setup.cfg +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/mus/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/propagators/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/propagators/constants.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/propagators/propagator_solver_decisions.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/py.typed +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/constants.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/exceptions.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_assumption.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_constraint.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_fact.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_optimization_remover.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_rule_splitter.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/unsat_constraints/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/unsat_constraints/constants.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/unsat_constraints/unsat_constraint_computer.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/logging.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/match.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/parser.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/symbols.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/utils/types.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid.egg-info/SOURCES.txt +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid.egg-info/dependency_links.txt +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid.egg-info/requires.txt +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid.egg-info/top_level.txt +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/__init__.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_constants.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_constraints.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_decision_order.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_multi_mus.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_optimization.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_pattern.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_rules.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_unsat_constraints.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_assumptions_all.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_assumptions_certain_signatures.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_constraints.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_constraints_id.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_facts.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_optimization.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_pattern.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_rules_split.lp +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/test_main.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/test_transformers.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/test_unsat_constraints.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/test_utils.py +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/py.typed +0 -0
- {clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/test_main.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clingexplaid
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Tools to aid the development of explanation systems using clingo
|
|
5
5
|
Author-email: Hannes Weichelt <hweichelt@uni-potsdam.de>, Susana Hahn <susuhahnml@yahoo.com.mx>
|
|
6
6
|
Maintainer-email: Hannes Weichelt <hweichelt@uni-potsdam.de>
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
MUS Module: Core Computer to get Minimal Unsatisfiable Subsets
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import warnings
|
|
7
|
+
from dataclasses import dataclass
|
|
6
8
|
from itertools import chain, combinations
|
|
7
|
-
from typing import Dict, Generator, List, Optional, Set, Tuple
|
|
9
|
+
from typing import Dict, Generator, Iterable, Iterator, List, Optional, Set, Tuple, Union
|
|
8
10
|
|
|
9
11
|
import clingo
|
|
10
12
|
|
|
@@ -12,6 +14,17 @@ from ..utils import get_solver_literal_lookup
|
|
|
12
14
|
from ..utils.types import Assumption, AssumptionSet, SymbolSet
|
|
13
15
|
|
|
14
16
|
|
|
17
|
+
@dataclass
|
|
18
|
+
class UnsatisfiableSubset:
|
|
19
|
+
"""Container class for unsatisfiable subsets"""
|
|
20
|
+
|
|
21
|
+
assumptions: Set[Assumption]
|
|
22
|
+
minimal: bool = False
|
|
23
|
+
|
|
24
|
+
def __iter__(self) -> Iterator[Union[tuple[clingo.Symbol, bool], int]]:
|
|
25
|
+
return self.assumptions.__iter__()
|
|
26
|
+
|
|
27
|
+
|
|
15
28
|
class CoreComputer:
|
|
16
29
|
"""
|
|
17
30
|
A container class that allows for a passed program_string and assumption_set to compute a minimal unsatisfiable
|
|
@@ -22,7 +35,9 @@ class CoreComputer:
|
|
|
22
35
|
self.control = control
|
|
23
36
|
self.assumption_set = assumption_set
|
|
24
37
|
self.literal_lookup = get_solver_literal_lookup(control=self.control)
|
|
25
|
-
self.minimal: Optional[
|
|
38
|
+
self.minimal: Optional[UnsatisfiableSubset] = None
|
|
39
|
+
self._assumptions_minimal: Set[Assumption] = set()
|
|
40
|
+
self._assumptions_removed: Set[Assumption] = set()
|
|
26
41
|
|
|
27
42
|
def _solve(self, assumptions: Optional[AssumptionSet] = None) -> Tuple[bool, SymbolSet, SymbolSet]:
|
|
28
43
|
"""
|
|
@@ -38,7 +53,7 @@ class CoreComputer:
|
|
|
38
53
|
|
|
39
54
|
return satisfiable, set(model), core
|
|
40
55
|
|
|
41
|
-
def _compute_single_minimal(self, assumptions: Optional[AssumptionSet] = None) ->
|
|
56
|
+
async def _compute_single_minimal(self, assumptions: Optional[AssumptionSet] = None) -> UnsatisfiableSubset:
|
|
42
57
|
"""
|
|
43
58
|
Function to compute a single minimal unsatisfiable subset from the passed set of assumptions and the program of
|
|
44
59
|
the CoreComputer. If there is no minimal unsatisfiable subset, since for example the program with assumptions
|
|
@@ -48,6 +63,9 @@ class CoreComputer:
|
|
|
48
63
|
if assumptions is None:
|
|
49
64
|
assumptions = self.assumption_set
|
|
50
65
|
|
|
66
|
+
# Reset progress set
|
|
67
|
+
self._assumptions_minimal = set()
|
|
68
|
+
|
|
51
69
|
# check that the assumption set isn't empty
|
|
52
70
|
if not assumptions:
|
|
53
71
|
warnings.warn("A minimal unsatisfiable subset cannot be computed on an empty assumption set")
|
|
@@ -56,37 +74,62 @@ class CoreComputer:
|
|
|
56
74
|
# rest of the algorithm and return an empty set.
|
|
57
75
|
satisfiable, _, _ = self._solve(assumptions=assumptions)
|
|
58
76
|
if satisfiable:
|
|
59
|
-
return set()
|
|
77
|
+
return UnsatisfiableSubset(set())
|
|
60
78
|
|
|
61
|
-
mus_members: Set[Assumption] = set()
|
|
62
79
|
working_set = set(assumptions)
|
|
63
80
|
|
|
64
81
|
for assumption in assumptions:
|
|
65
82
|
# remove the current assumption from the working set
|
|
66
83
|
working_set.remove(assumption)
|
|
67
84
|
|
|
68
|
-
satisfiable, _, _ = self._solve(assumptions=working_set.union(
|
|
85
|
+
satisfiable, _, _ = self._solve(assumptions=working_set.union(self._assumptions_minimal))
|
|
69
86
|
# if the working set now becomes satisfiable without the assumption it is added to the mus_members
|
|
70
87
|
if satisfiable:
|
|
71
|
-
|
|
88
|
+
self._assumptions_minimal.add(assumption)
|
|
72
89
|
# every time we discover a new mus member we also check if all currently found mus members already
|
|
73
90
|
# suffice to make the instance unsatisfiable. If so we can stop the search sice we found our mus.
|
|
74
|
-
if not self._solve(assumptions=
|
|
91
|
+
if not self._solve(assumptions=self._assumptions_minimal)[0]:
|
|
75
92
|
break
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
else:
|
|
94
|
+
# Remove the current assumption since it's not part of the mus
|
|
95
|
+
self._assumptions_removed.add(assumption)
|
|
96
|
+
|
|
97
|
+
# Do a very short wait every time to allow for async timeout interruption
|
|
98
|
+
await asyncio.sleep(0.0000001)
|
|
99
|
+
|
|
100
|
+
return UnsatisfiableSubset(self._assumptions_minimal, minimal=True)
|
|
101
|
+
|
|
102
|
+
async def _shrink_unsatisfiable_subset(
|
|
103
|
+
self, assumptions: Optional[AssumptionSet] = None, timeout: Optional[float] = None
|
|
104
|
+
) -> UnsatisfiableSubset:
|
|
105
|
+
timeout_occurred = False
|
|
106
|
+
try:
|
|
107
|
+
await asyncio.wait_for(self._compute_single_minimal(assumptions=assumptions), timeout=timeout)
|
|
108
|
+
unsat_subset = self._assumptions_minimal
|
|
109
|
+
except TimeoutError:
|
|
110
|
+
timeout_occurred = True
|
|
111
|
+
warnings.warn(
|
|
112
|
+
"Timeout encountered while computing unsatisfiable subset, "
|
|
113
|
+
"intermediate unsatisfiable subset is returned"
|
|
114
|
+
)
|
|
115
|
+
# Remove the already excluded assumptions from the original set and return them
|
|
116
|
+
provided_assumptions = set(assumptions) if assumptions is not None else set(self.assumption_set)
|
|
117
|
+
unsat_subset = provided_assumptions.difference(self._assumptions_removed)
|
|
118
|
+
return UnsatisfiableSubset(unsat_subset, minimal=not timeout_occurred)
|
|
119
|
+
|
|
120
|
+
def shrink(
|
|
121
|
+
self, assumptions: Optional[AssumptionSet] = None, timeout: Optional[float] = None
|
|
122
|
+
) -> UnsatisfiableSubset:
|
|
80
123
|
"""
|
|
81
124
|
This function applies the unsatisfiable subset minimization (`self._compute_single_minimal`) on the assumptions
|
|
82
125
|
set `assumptions` and stores the resulting MUS inside `self.minimal`.
|
|
83
126
|
|
|
84
127
|
Returns the MUS as a set of assumptions.
|
|
85
128
|
"""
|
|
86
|
-
self.minimal = self.
|
|
129
|
+
self.minimal = asyncio.run(self._shrink_unsatisfiable_subset(assumptions=assumptions, timeout=timeout))
|
|
87
130
|
return self.minimal
|
|
88
131
|
|
|
89
|
-
def get_multiple_minimal(self, max_mus: Optional[int] = None) -> Generator[
|
|
132
|
+
def get_multiple_minimal(self, max_mus: Optional[int] = None) -> Generator[UnsatisfiableSubset, None, None]:
|
|
90
133
|
"""
|
|
91
134
|
This function generates all minimal unsatisfiable subsets of the provided assumption set. It implements the
|
|
92
135
|
generator pattern since finding all mus of an assumption set is exponential in nature and the search might not
|
|
@@ -112,7 +155,7 @@ class CoreComputer:
|
|
|
112
155
|
if any(set(muc).issubset(current_subset) for muc in found_mucs):
|
|
113
156
|
continue
|
|
114
157
|
|
|
115
|
-
muc = self._compute_single_minimal(assumptions=current_subset)
|
|
158
|
+
muc = asyncio.run(self._compute_single_minimal(assumptions=current_subset))
|
|
116
159
|
|
|
117
160
|
# if the current subset wasn't unsatisfiable store this info and continue
|
|
118
161
|
if len(list(muc)) == 0:
|
|
@@ -127,7 +170,11 @@ class CoreComputer:
|
|
|
127
170
|
if max_mus is not None and len(found_mucs) == max_mus:
|
|
128
171
|
break
|
|
129
172
|
|
|
130
|
-
def mus_to_string(
|
|
173
|
+
def mus_to_string(
|
|
174
|
+
self,
|
|
175
|
+
muc: Iterable[Union[Tuple[clingo.Symbol, bool], int]],
|
|
176
|
+
literal_lookup: Optional[Dict[int, clingo.Symbol]] = None,
|
|
177
|
+
) -> Set[str]:
|
|
131
178
|
"""
|
|
132
179
|
Converts a MUS into a set containing the string representations of the contained assumptions
|
|
133
180
|
"""
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_rule_id.py
RENAMED
|
@@ -55,7 +55,7 @@ class RuleIDTransformer(_ast.Transformer):
|
|
|
55
55
|
out = []
|
|
56
56
|
_ast.parse_string(string, lambda stm: out.append((str(self(stm)))))
|
|
57
57
|
out.append(
|
|
58
|
-
f"{{_rule(1..{self._get_number_of_rules()})}}"
|
|
58
|
+
f"{{_rule(1..{self._get_number_of_rules()})}}."
|
|
59
59
|
f" % Choice rule to allow all _rule atoms to become assumptions"
|
|
60
60
|
)
|
|
61
61
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clingexplaid
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Tools to aid the development of explanation systems using clingo
|
|
5
5
|
Author-email: Hannes Weichelt <hweichelt@uni-potsdam.de>, Susana Hahn <susuhahnml@yahoo.com.mx>
|
|
6
6
|
Maintainer-email: Hannes Weichelt <hweichelt@uni-potsdam.de>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Tests for the mus package
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import random
|
|
6
7
|
from typing import Iterable, List, Optional, Sequence, Set, Tuple, Union
|
|
7
8
|
from unittest import TestCase
|
|
@@ -9,9 +10,9 @@ from unittest import TestCase
|
|
|
9
10
|
import clingo
|
|
10
11
|
|
|
11
12
|
from clingexplaid.mus import CoreComputer
|
|
13
|
+
from clingexplaid.mus.core_computer import UnsatisfiableSubset
|
|
12
14
|
from clingexplaid.transformers import AssumptionTransformer
|
|
13
15
|
from clingexplaid.transformers.transformer_assumption import FilterPattern, FilterSignature
|
|
14
|
-
from clingexplaid.utils.types import AssumptionSet
|
|
15
16
|
|
|
16
17
|
from .test_main import TEST_DIR
|
|
17
18
|
|
|
@@ -20,7 +21,8 @@ def get_mus_of_program(
|
|
|
20
21
|
program_string: str,
|
|
21
22
|
assumption_filters: Optional[Iterable[Union[FilterPattern, FilterSignature]]] = None,
|
|
22
23
|
control: Optional[clingo.Control] = None,
|
|
23
|
-
|
|
24
|
+
timeout: Optional[float] = None,
|
|
25
|
+
) -> Tuple[UnsatisfiableSubset, CoreComputer]:
|
|
24
26
|
"""
|
|
25
27
|
Helper function to directly get the MUS of a given program string.
|
|
26
28
|
"""
|
|
@@ -43,12 +45,12 @@ def get_mus_of_program(
|
|
|
43
45
|
cc = CoreComputer(ctl, assumptions)
|
|
44
46
|
|
|
45
47
|
def shrink_on_model(core: Sequence[int]) -> None:
|
|
46
|
-
_ = cc.shrink(core)
|
|
48
|
+
_ = cc.shrink(core, timeout=timeout)
|
|
47
49
|
|
|
48
50
|
ctl.solve(assumptions=list(assumptions), on_core=shrink_on_model)
|
|
49
51
|
|
|
50
52
|
# if the instance was satisfiable and the on_core function wasn't called an empty set is returned, else the mus.
|
|
51
|
-
result = cc.minimal if cc.minimal is not None else set()
|
|
53
|
+
result = cc.minimal if cc.minimal is not None else UnsatisfiableSubset(set())
|
|
52
54
|
|
|
53
55
|
return result, cc
|
|
54
56
|
|
|
@@ -178,6 +180,25 @@ class TestMUS(TestCase):
|
|
|
178
180
|
self.fail()
|
|
179
181
|
self._assert_mus(cc.mus_to_string(mus), [{f"a({i})" for i in random_core}])
|
|
180
182
|
|
|
183
|
+
def test_core_computer_shrink_timeout(self) -> None:
|
|
184
|
+
"""
|
|
185
|
+
Test the CoreComputer's `shrink` function with a satisfiable assumption set.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
ctl = clingo.Control()
|
|
189
|
+
|
|
190
|
+
n_assumptions = 3000
|
|
191
|
+
random_core = random.choices(range(1, n_assumptions), k=500)
|
|
192
|
+
program = f"""
|
|
193
|
+
a(1..{n_assumptions}).
|
|
194
|
+
:- {', '.join([f"a({i})" for i in random_core])}.
|
|
195
|
+
"""
|
|
196
|
+
filters = {FilterSignature("a", 1)}
|
|
197
|
+
|
|
198
|
+
mus, _ = get_mus_of_program(program_string=program, assumption_filters=filters, control=ctl, timeout=1)
|
|
199
|
+
|
|
200
|
+
self.assertEqual(mus.minimal, False)
|
|
201
|
+
|
|
181
202
|
def test_core_computer_shrink_satisfiable(self) -> None:
|
|
182
203
|
"""
|
|
183
204
|
Test the CoreComputer's `shrink` function with a satisfiable assumption set.
|
|
@@ -192,7 +213,7 @@ class TestMUS(TestCase):
|
|
|
192
213
|
|
|
193
214
|
mus, _ = get_mus_of_program(program_string=program, assumption_filters=filters, control=ctl)
|
|
194
215
|
|
|
195
|
-
self.assertEqual(mus, set())
|
|
216
|
+
self.assertEqual(mus, UnsatisfiableSubset(set()))
|
|
196
217
|
|
|
197
218
|
def test_core_computer_get_multiple_minimal(self) -> None:
|
|
198
219
|
"""
|
|
@@ -265,8 +286,8 @@ class TestMUS(TestCase):
|
|
|
265
286
|
control.ground([("base", [])])
|
|
266
287
|
assumptions = {(clingo.parse_term(c), True) for c in "abc"}
|
|
267
288
|
cc = CoreComputer(control, assumptions)
|
|
268
|
-
mus = cc._compute_single_minimal() # pylint: disable=W0212
|
|
269
|
-
self.assertEqual(mus, set())
|
|
289
|
+
mus = asyncio.run(cc._compute_single_minimal()) # pylint: disable=W0212
|
|
290
|
+
self.assertEqual(mus, UnsatisfiableSubset(set()))
|
|
270
291
|
|
|
271
292
|
def test_core_computer_internal_compute_single_minimal_no_assumptions(self) -> None:
|
|
272
293
|
"""
|
|
@@ -276,7 +297,8 @@ class TestMUS(TestCase):
|
|
|
276
297
|
control = clingo.Control()
|
|
277
298
|
cc = CoreComputer(control, set())
|
|
278
299
|
# Disabled exception assertion due to change in error handling
|
|
279
|
-
|
|
300
|
+
mus = asyncio.run(cc._compute_single_minimal(assumptions=None)) # pylint: disable=W0212
|
|
301
|
+
self.assertEqual(mus, UnsatisfiableSubset(set()))
|
|
280
302
|
cc.shrink([])
|
|
281
303
|
|
|
282
304
|
def test_core_computer_mus_to_string(self) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/examples/graph_coloring/graph_coloring_example.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_assumption.py
RENAMED
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_constraint.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/src/clingexplaid/transformers/transformer_rule_splitter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_constraints.lp
RENAMED
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_decision_order.lp
RENAMED
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_optimization.lp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/test_program_unsat_constraints.lp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_constraints.lp
RENAMED
|
File without changes
|
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_facts.lp
RENAMED
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_optimization.lp
RENAMED
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_pattern.lp
RENAMED
|
File without changes
|
{clingexplaid-1.2.0 → clingexplaid-1.2.2}/tests/clingexplaid/res/transformed_program_rules_split.lp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|