flamapy-sat 2.6.0.dev5__tar.gz → 2.6.0.dev11__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.
- {flamapy_sat-2.6.0.dev5/flamapy_sat.egg-info → flamapy_sat-2.6.0.dev11}/PKG-INFO +3 -3
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/pysat_configuration_diagnosis.py +43 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/pysat_conflict.py +23 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/pysat_diagnosis.py +24 -0
- flamapy_sat-2.6.0.dev11/flamapy/metamodels/pysat_diagnosis_metamodel/transformations/fm_to_diag_pysat.py +37 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_backbone.py +10 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_commonality.py +15 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_filter.py +15 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_minimum_configuration.py +13 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_twise_sampling.py +16 -0
- flamapy_sat-2.6.0.dev11/flamapy/metamodels/pysat_metamodel/transformations/fm_to_pysat.py +37 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11/flamapy_sat.egg-info}/PKG-INFO +3 -3
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy_sat.egg-info/requires.txt +2 -2
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/pyproject.toml +3 -3
- flamapy_sat-2.6.0.dev5/flamapy/metamodels/pysat_diagnosis_metamodel/transformations/fm_to_diag_pysat.py +0 -73
- flamapy_sat-2.6.0.dev5/flamapy/metamodels/pysat_metamodel/transformations/fm_to_pysat.py +0 -192
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/LICENSE +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/README.md +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/models/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/models/pysat_diagnosis_model.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/checker.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/fastdiag.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/hsdag.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/labeler/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/labeler/fastdiag_labeler.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/labeler/labeler.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/labeler/quickxplain_labeler.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/hsdag/node.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/quickxplain.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/diagnosis/utils.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/operations/pysat_abstract_identifier.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_diagnosis_metamodel/transformations/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/models/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/models/pysat_model.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/models/txtcnf_model.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_attribute_optimization.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_configurations.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_configurations_number.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_core_features.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_dead_features.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_false_optional_features.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_metrics.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_sampling.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_satisfiable.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/operations/pysat_satisfiable_configuration.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/transformations/__init__.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/transformations/cnf_to_pysat.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/transformations/dimacs_reader.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/transformations/dimacs_writer.py +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy_sat.egg-info/SOURCES.txt +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy_sat.egg-info/dependency_links.txt +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy_sat.egg-info/top_level.txt +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/setup.cfg +0 -0
- {flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-sat
|
|
3
|
-
Version: 2.6.0.
|
|
3
|
+
Version: 2.6.0.dev11
|
|
4
4
|
Summary: flamapy-sat is a plugin to flamapy module
|
|
5
5
|
Author-email: Flamapy <flamapy@us.es>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -8,8 +8,8 @@ Project-URL: Homepage, https://github.com/flamapy/pysat_metamodel
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Requires-Dist: flamapy-fw~=2.6.0.
|
|
12
|
-
Requires-Dist: flamapy-fm~=2.6.0.
|
|
11
|
+
Requires-Dist: flamapy-fw~=2.6.0.dev11
|
|
12
|
+
Requires-Dist: flamapy-fm~=2.6.0.dev11
|
|
13
13
|
Requires-Dist: python-sat~=0.1.7.dev1
|
|
14
14
|
Provides-Extra: dev
|
|
15
15
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -17,6 +17,7 @@ from typing import Optional, cast
|
|
|
17
17
|
|
|
18
18
|
from flamapy.core.models import VariabilityModel
|
|
19
19
|
from flamapy.core.operations import Operation
|
|
20
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
20
21
|
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
21
22
|
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
22
23
|
|
|
@@ -52,6 +53,19 @@ def _decisions_from_literals(
|
|
|
52
53
|
class PySATConfigurationConflict(Operation):
|
|
53
54
|
"""Minimal subset of the user's decisions that is inconsistent with the model."""
|
|
54
55
|
|
|
56
|
+
facade = OperationDescriptor(
|
|
57
|
+
doc=(
|
|
58
|
+
'Returns a minimal subset of the configuration decisions that is inconsistent with\n'
|
|
59
|
+
'the feature model — the conflict explaining why the (partial) configuration cannot\n'
|
|
60
|
+
'be completed. Requires the pysat_diagnosis plugin.'
|
|
61
|
+
),
|
|
62
|
+
returns='Union[None, List[Any]]',
|
|
63
|
+
name='configuration_conflict', operation='PySATConfigurationConflict',
|
|
64
|
+
default_backend='pysat_diagnosis',
|
|
65
|
+
inputs=(Input('configuration_path', str, required=True, kind='configuration',
|
|
66
|
+
setter='set_configuration'),),
|
|
67
|
+
)
|
|
68
|
+
|
|
55
69
|
def __init__(self) -> None:
|
|
56
70
|
self._configuration: Optional[Configuration] = None
|
|
57
71
|
self._result: list[Decision] = []
|
|
@@ -78,6 +92,19 @@ class PySATConfigurationConflict(Operation):
|
|
|
78
92
|
class PySATConfigurationRepair(Operation):
|
|
79
93
|
"""Minimal subset of the user's decisions to retract to restore consistency."""
|
|
80
94
|
|
|
95
|
+
facade = OperationDescriptor(
|
|
96
|
+
doc=(
|
|
97
|
+
'Returns a minimal subset of the configuration decisions to retract in order to\n'
|
|
98
|
+
'restore consistency with the feature model — how to repair an over-constrained\n'
|
|
99
|
+
'configuration. Requires the pysat_diagnosis plugin.'
|
|
100
|
+
),
|
|
101
|
+
returns='Union[None, List[Any]]',
|
|
102
|
+
name='configuration_repair', operation='PySATConfigurationRepair',
|
|
103
|
+
default_backend='pysat_diagnosis',
|
|
104
|
+
inputs=(Input('configuration_path', str, required=True, kind='configuration',
|
|
105
|
+
setter='set_configuration'),),
|
|
106
|
+
)
|
|
107
|
+
|
|
81
108
|
def __init__(self) -> None:
|
|
82
109
|
self._configuration: Optional[Configuration] = None
|
|
83
110
|
self._result: list[Decision] = []
|
|
@@ -108,6 +135,22 @@ class PySATFeatureExplanation(Operation):
|
|
|
108
135
|
forced), and ``get_result()`` is the minimal set of decisions responsible.
|
|
109
136
|
"""
|
|
110
137
|
|
|
138
|
+
facade = OperationDescriptor(
|
|
139
|
+
doc=(
|
|
140
|
+
'Explains why a feature is forced (selected or deselected) by the current\n'
|
|
141
|
+
'configuration: returns the minimal set of decisions responsible. ``feature_name``\n'
|
|
142
|
+
'is the feature to explain. Requires the pysat_diagnosis plugin.'
|
|
143
|
+
),
|
|
144
|
+
returns='Union[None, List[Any]]',
|
|
145
|
+
name='feature_explanation', operation='PySATFeatureExplanation',
|
|
146
|
+
default_backend='pysat_diagnosis',
|
|
147
|
+
inputs=(
|
|
148
|
+
Input('configuration_path', str, required=True, kind='configuration',
|
|
149
|
+
setter='set_configuration'),
|
|
150
|
+
Input('feature_name', str, required=True, setter='set_feature'),
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
|
|
111
154
|
def __init__(self) -> None:
|
|
112
155
|
self._configuration: Optional[Configuration] = None
|
|
113
156
|
self._feature: Optional[str] = None
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Tuple
|
|
2
2
|
|
|
3
3
|
from flamapy.metamodels.pysat_diagnosis_metamodel.models import DiagnosisModel
|
|
4
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
4
5
|
from . import PySATAbstractIdentifier
|
|
5
6
|
from .diagnosis.checker import ConsistencyChecker
|
|
6
7
|
from .diagnosis.hsdag.hsdag import HSDAG
|
|
@@ -18,6 +19,28 @@ class PySATConflict(PySATAbstractIdentifier):
|
|
|
18
19
|
- max_depth - specify the maximum depth of the HSDAG to be computed
|
|
19
20
|
"""
|
|
20
21
|
|
|
22
|
+
facade = OperationDescriptor(
|
|
23
|
+
doc=(
|
|
24
|
+
'Returns a list of conflict sets: minimal subsets of the model constraints that\n'
|
|
25
|
+
'are inconsistent with the given configuration. Requires the pysat_diagnosis\n'
|
|
26
|
+
'plugin.\n'
|
|
27
|
+
'\n'
|
|
28
|
+
'``configuration_path`` accepts a configuration file path, a ``{feature:\n'
|
|
29
|
+
'value}`` mapping, or a Configuration object. ``test_case_path`` is optional\n'
|
|
30
|
+
'and, when given, looks for conflicts against that expected outcome instead;\n'
|
|
31
|
+
'same input types.'
|
|
32
|
+
),
|
|
33
|
+
returns='Union[None, List[str]]',
|
|
34
|
+
name='conflict', operation='PySATConflict', default_backend='pysat_diagnosis',
|
|
35
|
+
inputs=(
|
|
36
|
+
Input('configuration_path', str, required=True, kind='configuration',
|
|
37
|
+
setter='set_configuration'),
|
|
38
|
+
Input('test_case_path', str, default=None, kind='configuration',
|
|
39
|
+
setter='set_test_case'),
|
|
40
|
+
Input('max_conflicts', int, default=None, setter='set_max_conflicts'),
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
|
|
21
44
|
def __init__(self) -> None:
|
|
22
45
|
super().__init__()
|
|
23
46
|
self.max_conflicts = -1 # -1 means no limit
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Tuple
|
|
2
2
|
|
|
3
3
|
from flamapy.metamodels.pysat_diagnosis_metamodel.models import DiagnosisModel
|
|
4
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
4
5
|
from . import PySATAbstractIdentifier
|
|
5
6
|
from .diagnosis.checker import ConsistencyChecker
|
|
6
7
|
from .diagnosis.hsdag.hsdag import HSDAG
|
|
@@ -18,6 +19,29 @@ class PySATDiagnosis(PySATAbstractIdentifier):
|
|
|
18
19
|
- max_depth - specify the maximum depth of the HSDAG to be computed
|
|
19
20
|
"""
|
|
20
21
|
|
|
22
|
+
facade = OperationDescriptor(
|
|
23
|
+
doc=(
|
|
24
|
+
'Returns a list of diagnoses explaining why a configuration is not valid\n'
|
|
25
|
+
'against the feature model: each diagnosis is a minimal set of constraints\n'
|
|
26
|
+
'whose removal would resolve the inconsistency. Requires the pysat_diagnosis\n'
|
|
27
|
+
'plugin.\n'
|
|
28
|
+
'\n'
|
|
29
|
+
'``configuration_path`` accepts a configuration file path, a ``{feature:\n'
|
|
30
|
+
'value}`` mapping, or a Configuration object. ``test_case_path`` is optional\n'
|
|
31
|
+
'and, when given, diagnoses against that expected outcome instead; it accepts\n'
|
|
32
|
+
'the same input types.'
|
|
33
|
+
),
|
|
34
|
+
returns='Union[None, List[str]]',
|
|
35
|
+
name='diagnosis', operation='PySATDiagnosis', default_backend='pysat_diagnosis',
|
|
36
|
+
inputs=(
|
|
37
|
+
Input('configuration_path', str, required=True, kind='configuration',
|
|
38
|
+
setter='set_configuration'),
|
|
39
|
+
Input('test_case_path', str, default=None, kind='configuration',
|
|
40
|
+
setter='set_test_case'),
|
|
41
|
+
Input('max_diagnoses', int, default=None, setter='set_max_diagnoses'),
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
|
|
21
45
|
def __init__(self) -> None:
|
|
22
46
|
super().__init__()
|
|
23
47
|
self.max_diagnoses = -1 # -1 means no limit
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from flamapy.metamodels.fm_metamodel.models import FeatureModel, ClauseSet
|
|
2
|
+
from flamapy.metamodels.pysat_metamodel.transformations.fm_to_pysat import FmToPysat
|
|
3
|
+
from ..models.pysat_diagnosis_model import DiagnosisModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FmToDiagPysat(FmToPysat):
|
|
7
|
+
"""Like FmToPysat, but into a DiagnosisModel that also keeps a clause → constraint map.
|
|
8
|
+
|
|
9
|
+
The CNF and its per-source clause grouping both come from the shared feature-model encoder
|
|
10
|
+
(``ClauseSet``); this transformation just wraps them into the diagnosis model.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def get_source_extension() -> str:
|
|
15
|
+
return 'fm'
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def get_destination_extension() -> str:
|
|
19
|
+
return 'pysat_diagnosis'
|
|
20
|
+
|
|
21
|
+
def __init__(self, source_model: FeatureModel, cnf_method: str = 'distributive') -> None:
|
|
22
|
+
super().__init__(source_model, cnf_method)
|
|
23
|
+
self.destination_model = DiagnosisModel()
|
|
24
|
+
|
|
25
|
+
def transform(self) -> DiagnosisModel:
|
|
26
|
+
clause_set = ClauseSet.from_feature_model(self.source_model, cnf_method=self.cnf_method)
|
|
27
|
+
model = self.destination_model
|
|
28
|
+
for clause in clause_set.clauses:
|
|
29
|
+
model.add_clause(clause)
|
|
30
|
+
model.variables = dict(clause_set.variables)
|
|
31
|
+
model.features = dict(clause_set.features)
|
|
32
|
+
model.auxiliary_variables = set(clause_set.auxiliary_variables)
|
|
33
|
+
model.original_model = self.source_model
|
|
34
|
+
# Clause → constraint mapping (root feature / relations / cross-tree constraints).
|
|
35
|
+
for description, clauses in clause_set.clause_groups:
|
|
36
|
+
model.add_clause_to_map(description, clauses)
|
|
37
|
+
return model
|
|
@@ -3,11 +3,21 @@ from typing import Any, cast
|
|
|
3
3
|
from pysat.solvers import Solver
|
|
4
4
|
|
|
5
5
|
from flamapy.core.operations import Operation
|
|
6
|
+
from flamapy.core.operations.descriptor import OperationDescriptor
|
|
6
7
|
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
7
8
|
from flamapy.core.models import VariabilityModel
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class PySATBackbone(Operation):
|
|
12
|
+
facade = OperationDescriptor(
|
|
13
|
+
doc=(
|
|
14
|
+
'Returns the backbone of the feature model: the set of features that must\n'
|
|
15
|
+
'always be selected (core) and those that must never be selected (dead) across\n'
|
|
16
|
+
"all valid configurations, grouped under 'core' and 'dead' keys."
|
|
17
|
+
),
|
|
18
|
+
returns='Union[None, Dict[str, List[Any]]]',
|
|
19
|
+
name='backbone', operation='PySATBackbone', default_backend='sat'
|
|
20
|
+
)
|
|
11
21
|
|
|
12
22
|
def __init__(self) -> None:
|
|
13
23
|
self._result: dict[str, list[Any]] = {"core": [], "dead": []}
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
from flamapy.core.operations import Commonality
|
|
2
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
2
3
|
from flamapy.core.models import VariabilityModel
|
|
3
4
|
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
4
5
|
from .pysat_configurations import PySATConfigurations
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class PySATCommonality(Commonality):
|
|
9
|
+
facade = OperationDescriptor(
|
|
10
|
+
doc=(
|
|
11
|
+
'This is a measure of how often a feature appears in the products of a product\n'
|
|
12
|
+
"line. It's usually expressed as a percentage. A feature with 100 per cent\n"
|
|
13
|
+
'commonality is a core feature, as it appears in all products.\n'
|
|
14
|
+
'\n'
|
|
15
|
+
'``configuration_path`` accepts a configuration file path, a ``{feature:\n'
|
|
16
|
+
'value}`` mapping, or a Configuration object.'
|
|
17
|
+
),
|
|
18
|
+
returns='Union[None, float]',
|
|
19
|
+
name='commonality', operation='PySATCommonality', default_backend='sat',
|
|
20
|
+
inputs=(Input('configuration_path', str, required=True, kind='configuration',
|
|
21
|
+
setter='set_configuration'),),
|
|
22
|
+
)
|
|
8
23
|
|
|
9
24
|
def __init__(self) -> None:
|
|
10
25
|
self.result: float = 0
|
|
@@ -4,11 +4,26 @@ from pysat.solvers import Solver
|
|
|
4
4
|
|
|
5
5
|
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
6
6
|
from flamapy.core.operations import Filter
|
|
7
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
7
8
|
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
8
9
|
from flamapy.core.models import VariabilityModel
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class PySATFilter(Filter):
|
|
13
|
+
facade = OperationDescriptor(
|
|
14
|
+
doc=(
|
|
15
|
+
'This operation selects a subset of the products of a product line based on\n'
|
|
16
|
+
'certain criteria. For example, you might filter the products to only include\n'
|
|
17
|
+
'those that contain a certain feature.\n'
|
|
18
|
+
'\n'
|
|
19
|
+
'``configuration_path`` accepts a configuration file path, a ``{feature:\n'
|
|
20
|
+
'value}`` mapping, or a Configuration object.'
|
|
21
|
+
),
|
|
22
|
+
returns='Union[None, List[Configuration]]',
|
|
23
|
+
name='filter', operation='PySATFilter', default_backend='sat',
|
|
24
|
+
inputs=(Input('configuration_path', str, required=True, kind='configuration',
|
|
25
|
+
setter='set_configuration'),),
|
|
26
|
+
)
|
|
12
27
|
|
|
13
28
|
def __init__(self) -> None:
|
|
14
29
|
self.filter_products: list[list[Any]] = []
|
|
@@ -5,6 +5,7 @@ from pysat.examples.rc2 import RC2
|
|
|
5
5
|
|
|
6
6
|
from flamapy.core.models import VariabilityModel
|
|
7
7
|
from flamapy.core.operations import Operation
|
|
8
|
+
from flamapy.core.operations.descriptor import OperationDescriptor
|
|
8
9
|
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
9
10
|
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
10
11
|
|
|
@@ -17,6 +18,18 @@ class PySATMinimumConfiguration(Operation):
|
|
|
17
18
|
minimum working configuration).
|
|
18
19
|
"""
|
|
19
20
|
|
|
21
|
+
facade = OperationDescriptor(
|
|
22
|
+
doc=(
|
|
23
|
+
'Returns a valid configuration with the fewest selected features (the minimum\n'
|
|
24
|
+
'working configuration).\n'
|
|
25
|
+
'\n'
|
|
26
|
+
'``backend`` selects the analysis plugin; only "sat" implements this operation.'
|
|
27
|
+
),
|
|
28
|
+
returns='Union[None, Configuration]',
|
|
29
|
+
name='minimum_configuration', operation='PySATMinimumConfiguration',
|
|
30
|
+
default_backend='sat', selectable_backend=True,
|
|
31
|
+
)
|
|
32
|
+
|
|
20
33
|
def __init__(self) -> None:
|
|
21
34
|
self._result: Optional[Configuration] = None
|
|
22
35
|
|
|
@@ -5,6 +5,7 @@ from pysat.solvers import Solver
|
|
|
5
5
|
|
|
6
6
|
from flamapy.core.models import VariabilityModel
|
|
7
7
|
from flamapy.core.operations import Operation
|
|
8
|
+
from flamapy.core.operations.descriptor import OperationDescriptor, Input
|
|
8
9
|
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
9
10
|
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
10
11
|
|
|
@@ -18,6 +19,21 @@ class PySATTWiseSampling(Operation):
|
|
|
18
19
|
the constraints allow.
|
|
19
20
|
"""
|
|
20
21
|
|
|
22
|
+
facade = OperationDescriptor(
|
|
23
|
+
doc=(
|
|
24
|
+
'Returns a t-wise (combinatorial) sample: a set of valid configurations that\n'
|
|
25
|
+
'covers every satisfiable combination of ``t`` feature selections (pairwise for\n'
|
|
26
|
+
'``t = 2``).\n'
|
|
27
|
+
'\n'
|
|
28
|
+
'``backend`` selects the analysis plugin; only "sat" implements t-wise\n'
|
|
29
|
+
'sampling.'
|
|
30
|
+
),
|
|
31
|
+
returns='Union[None, List[Configuration]]',
|
|
32
|
+
name='t_wise_sampling', operation='PySATTWiseSampling', default_backend='sat',
|
|
33
|
+
selectable_backend=True,
|
|
34
|
+
inputs=(Input('t', int, default=2, setter='set_t'),),
|
|
35
|
+
)
|
|
36
|
+
|
|
21
37
|
def __init__(self, t: int = 2) -> None:
|
|
22
38
|
self.t = t
|
|
23
39
|
self.result: list[Configuration] = []
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from flamapy.core.transformations import ModelToModel
|
|
2
|
+
from flamapy.metamodels.fm_metamodel.models import FeatureModel, ClauseSet
|
|
3
|
+
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FmToPysat(ModelToModel):
|
|
7
|
+
"""Transform a feature model into a python-sat ``PySATModel``.
|
|
8
|
+
|
|
9
|
+
The feature-model → CNF encoding lives in ``fm_metamodel`` (``ClauseSet.from_feature_model``);
|
|
10
|
+
this class just wraps the resulting clause set into the python-sat-backed ``PySATModel`` so the
|
|
11
|
+
SAT operations keep their existing API.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def get_source_extension() -> str:
|
|
16
|
+
return 'fm'
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def get_destination_extension() -> str:
|
|
20
|
+
return 'pysat'
|
|
21
|
+
|
|
22
|
+
def __init__(self, source_model: FeatureModel, cnf_method: str = 'distributive') -> None:
|
|
23
|
+
self.source_model = source_model
|
|
24
|
+
# 'distributive' (default) or 'tseytin'; forwarded to the shared CNF encoder.
|
|
25
|
+
self.cnf_method = cnf_method
|
|
26
|
+
self.destination_model = PySATModel()
|
|
27
|
+
self.destination_model.original_model = source_model
|
|
28
|
+
|
|
29
|
+
def transform(self) -> PySATModel:
|
|
30
|
+
clause_set = ClauseSet.from_feature_model(self.source_model, cnf_method=self.cnf_method)
|
|
31
|
+
model = self.destination_model
|
|
32
|
+
for clause in clause_set.clauses:
|
|
33
|
+
model.add_clause(clause)
|
|
34
|
+
model.variables = dict(clause_set.variables)
|
|
35
|
+
model.features = dict(clause_set.features)
|
|
36
|
+
model.auxiliary_variables = set(clause_set.auxiliary_variables)
|
|
37
|
+
return model
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-sat
|
|
3
|
-
Version: 2.6.0.
|
|
3
|
+
Version: 2.6.0.dev11
|
|
4
4
|
Summary: flamapy-sat is a plugin to flamapy module
|
|
5
5
|
Author-email: Flamapy <flamapy@us.es>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -8,8 +8,8 @@ Project-URL: Homepage, https://github.com/flamapy/pysat_metamodel
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Requires-Dist: flamapy-fw~=2.6.0.
|
|
12
|
-
Requires-Dist: flamapy-fm~=2.6.0.
|
|
11
|
+
Requires-Dist: flamapy-fw~=2.6.0.dev11
|
|
12
|
+
Requires-Dist: flamapy-fm~=2.6.0.dev11
|
|
13
13
|
Requires-Dist: python-sat~=0.1.7.dev1
|
|
14
14
|
Provides-Extra: dev
|
|
15
15
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flamapy-sat"
|
|
7
|
-
version = "2.6.0.
|
|
7
|
+
version = "2.6.0.dev11"
|
|
8
8
|
description = "flamapy-sat is a plugin to flamapy module"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-3.0-or-later"
|
|
11
11
|
authors = [{ name = "Flamapy", email = "flamapy@us.es" }]
|
|
12
12
|
requires-python = ">=3.11"
|
|
13
13
|
dependencies = [
|
|
14
|
-
"flamapy-fw~=2.6.0.
|
|
15
|
-
"flamapy-fm~=2.6.0.
|
|
14
|
+
"flamapy-fw~=2.6.0.dev11",
|
|
15
|
+
"flamapy-fm~=2.6.0.dev11",
|
|
16
16
|
"python-sat~=0.1.7.dev1",
|
|
17
17
|
]
|
|
18
18
|
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from flamapy.metamodels.fm_metamodel.models.feature_model import (
|
|
4
|
-
FeatureModel,
|
|
5
|
-
Constraint,
|
|
6
|
-
Feature,
|
|
7
|
-
Relation,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
from flamapy.metamodels.pysat_metamodel.transformations.fm_to_pysat import FmToPysat
|
|
11
|
-
from ..models.pysat_diagnosis_model import DiagnosisModel
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class FmToDiagPysat(FmToPysat):
|
|
15
|
-
@staticmethod
|
|
16
|
-
def get_source_extension() -> str:
|
|
17
|
-
return 'fm'
|
|
18
|
-
|
|
19
|
-
@staticmethod
|
|
20
|
-
def get_destination_extension() -> str:
|
|
21
|
-
return 'pysat_diagnosis'
|
|
22
|
-
|
|
23
|
-
def __init__(self, source_model: FeatureModel, cnf_method: str = 'distributive') -> None:
|
|
24
|
-
super().__init__(source_model, cnf_method)
|
|
25
|
-
self.destination_model = DiagnosisModel()
|
|
26
|
-
|
|
27
|
-
def add_root(self, feature: Feature) -> None:
|
|
28
|
-
var = self.destination_model.variables.get(feature.name)
|
|
29
|
-
if var is None:
|
|
30
|
-
raise KeyError(f'Feature {feature.name} not found in the model')
|
|
31
|
-
|
|
32
|
-
self.destination_model.add_clause([var])
|
|
33
|
-
self.destination_model.add_clause_to_map(str(feature), [[var]])
|
|
34
|
-
|
|
35
|
-
#def _store_constraint_relation(self, relation: Relation, clauses: List[List[int]]) -> None:
|
|
36
|
-
# for clause in clauses:
|
|
37
|
-
# self.destination_model.add_clause(clause)
|
|
38
|
-
# self.destination_model.add_clause_to_map(str(relation), clauses)
|
|
39
|
-
def add_relation(self, relation: Relation) -> None:
|
|
40
|
-
if relation.is_mandatory():
|
|
41
|
-
clauses = self._add_mandatory_relation(relation)
|
|
42
|
-
elif relation.is_optional():
|
|
43
|
-
clauses = self._add_optional_relation(relation)
|
|
44
|
-
elif relation.is_or():
|
|
45
|
-
clauses = self._add_or_relation(relation)
|
|
46
|
-
elif relation.is_alternative():
|
|
47
|
-
clauses = self._add_alternative_relation(relation)
|
|
48
|
-
else:
|
|
49
|
-
clauses = self._add_constraint_relation(relation)
|
|
50
|
-
self._store_constraint_clauses(clauses)
|
|
51
|
-
self.destination_model.add_clause_to_map(str(relation), clauses)
|
|
52
|
-
|
|
53
|
-
def add_constraint(self, ctc: Constraint) -> None:
|
|
54
|
-
if self.cnf_method == 'tseytin':
|
|
55
|
-
clauses, aux_names = ctc.ast.get_clauses_with_aux(method='tseytin')
|
|
56
|
-
aux_map = self._allocate_auxiliary(aux_names)
|
|
57
|
-
else:
|
|
58
|
-
clauses = ctc.ast.get_clauses()
|
|
59
|
-
aux_map = {}
|
|
60
|
-
|
|
61
|
-
def get_term_variable(term: Any) -> int:
|
|
62
|
-
negated = term.startswith('-')
|
|
63
|
-
name = term[1:] if negated else term
|
|
64
|
-
var = aux_map[name] if name in aux_map else self.destination_model.get_variable(name)
|
|
65
|
-
return -var if negated else var
|
|
66
|
-
|
|
67
|
-
ctc_clauses = []
|
|
68
|
-
for clause in clauses:
|
|
69
|
-
clause_variables = list(map(get_term_variable, clause))
|
|
70
|
-
ctc_clauses.append(clause_variables)
|
|
71
|
-
self.destination_model.add_clause(clause_variables)
|
|
72
|
-
|
|
73
|
-
self.destination_model.add_clause_to_map(str(ctc), ctc_clauses)
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import itertools
|
|
2
|
-
from typing import Any, List
|
|
3
|
-
|
|
4
|
-
from flamapy.core.transformations import ModelToModel
|
|
5
|
-
from flamapy.metamodels.fm_metamodel.models.feature_model import (
|
|
6
|
-
FeatureModel,
|
|
7
|
-
Constraint,
|
|
8
|
-
Feature,
|
|
9
|
-
Relation,
|
|
10
|
-
)
|
|
11
|
-
from flamapy.metamodels.pysat_metamodel.models.pysat_model import PySATModel
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class FmToPysat(ModelToModel):
|
|
15
|
-
@staticmethod
|
|
16
|
-
def get_source_extension() -> str:
|
|
17
|
-
return 'fm'
|
|
18
|
-
|
|
19
|
-
@staticmethod
|
|
20
|
-
def get_destination_extension() -> str:
|
|
21
|
-
return 'pysat'
|
|
22
|
-
|
|
23
|
-
def __init__(self, source_model: FeatureModel, cnf_method: str = 'distributive') -> None:
|
|
24
|
-
self.source_model = source_model
|
|
25
|
-
self.counter = 1
|
|
26
|
-
# 'distributive' (default) or 'tseytin'. Tseytin keeps complex cross-tree
|
|
27
|
-
# constraints compact at the cost of auxiliary variables; it is a framework-only
|
|
28
|
-
# opt-in and is not exposed through the facade/CLI.
|
|
29
|
-
self.cnf_method = cnf_method
|
|
30
|
-
self.destination_model = PySATModel()
|
|
31
|
-
self.destination_model.original_model = source_model
|
|
32
|
-
|
|
33
|
-
def add_feature(self, feature: Feature) -> None:
|
|
34
|
-
if feature.name not in self.destination_model.variables:
|
|
35
|
-
self.destination_model.variables[feature.name] = self.counter
|
|
36
|
-
self.destination_model.features[self.counter] = feature.name
|
|
37
|
-
self.counter += 1
|
|
38
|
-
|
|
39
|
-
def add_root(self, feature: Feature) -> None:
|
|
40
|
-
value = self.destination_model.get_variable(feature.name)
|
|
41
|
-
self.destination_model.add_clause([value])
|
|
42
|
-
|
|
43
|
-
def _add_mandatory_relation(self, relation: Relation) -> List[List[int]]:
|
|
44
|
-
value_parent = self.destination_model.get_variable(relation.parent.name)
|
|
45
|
-
value_child = self.destination_model.get_variable(relation.children[0].name)
|
|
46
|
-
clauses = [[-1 * value_parent, value_child], [-1 * value_child, value_parent]]
|
|
47
|
-
return clauses
|
|
48
|
-
|
|
49
|
-
def _add_optional_relation(self, relation: Relation) -> List[List[int]]:
|
|
50
|
-
value_parent = self.destination_model.get_variable(relation.parent.name)
|
|
51
|
-
value_children = self.destination_model.get_variable(relation.children[0].name)
|
|
52
|
-
clauses = [[-1 * value_children, value_parent]]
|
|
53
|
-
return clauses
|
|
54
|
-
|
|
55
|
-
def _add_or_relation(self, relation: Relation) -> List[List[int]]:
|
|
56
|
-
# this is a 1 to n relatinship with multiple childs
|
|
57
|
-
# add the first cnf child1 or child2 or ... or childN or no parent)
|
|
58
|
-
# first elem of the constraint
|
|
59
|
-
value_parent = self.destination_model.get_variable(relation.parent.name)
|
|
60
|
-
|
|
61
|
-
alt_cnf = [-1 * value_parent]
|
|
62
|
-
for child in relation.children:
|
|
63
|
-
alt_cnf.append(self.destination_model.get_variable(child.name))
|
|
64
|
-
clauses = [alt_cnf]
|
|
65
|
-
|
|
66
|
-
for child in relation.children:
|
|
67
|
-
clauses.append([
|
|
68
|
-
-1 * self.destination_model.get_variable(child.name),
|
|
69
|
-
value_parent
|
|
70
|
-
])
|
|
71
|
-
|
|
72
|
-
return clauses
|
|
73
|
-
|
|
74
|
-
def _add_alternative_relation(self, relation: Relation) -> List[List[int]]:
|
|
75
|
-
# this is a 1 to 1 relatinship with multiple childs
|
|
76
|
-
# add the first cnf child1 or child2 or ... or childN or no parent)
|
|
77
|
-
|
|
78
|
-
value_parent = self.destination_model.get_variable(relation.parent.name)
|
|
79
|
-
# first elem of the constraint
|
|
80
|
-
alt_cnf = [-1 * value_parent]
|
|
81
|
-
for child in relation.children:
|
|
82
|
-
alt_cnf.append(self.destination_model.get_variable(child.name))
|
|
83
|
-
clauses = [alt_cnf]
|
|
84
|
-
|
|
85
|
-
for i, _ in enumerate(relation.children):
|
|
86
|
-
for j in range(i + 1, len(relation.children)):
|
|
87
|
-
if i != j:
|
|
88
|
-
clauses.append([
|
|
89
|
-
-1 * self.destination_model.get_variable(relation.children[i].name),
|
|
90
|
-
-1 * self.destination_model.get_variable(relation.children[j].name)
|
|
91
|
-
])
|
|
92
|
-
clauses.append([
|
|
93
|
-
-1 * self.destination_model.get_variable(relation.children[i].name),
|
|
94
|
-
value_parent
|
|
95
|
-
])
|
|
96
|
-
return clauses
|
|
97
|
-
|
|
98
|
-
def _add_constraint_relation(self, relation: Relation) -> List[List[int]]:
|
|
99
|
-
value_parent = self.destination_model.get_variable(relation.parent.name)
|
|
100
|
-
|
|
101
|
-
# This is a _min to _max relationship
|
|
102
|
-
_min = relation.card_min
|
|
103
|
-
_max = relation.card_max if relation.card_max != -1 else len(relation.children)
|
|
104
|
-
|
|
105
|
-
clauses = []
|
|
106
|
-
|
|
107
|
-
for val in range(len(relation.children) + 1):
|
|
108
|
-
if val < _min or val > _max:
|
|
109
|
-
# combinations of val elements
|
|
110
|
-
for combination in itertools.combinations(relation.children, val):
|
|
111
|
-
cnf = [-1 * value_parent]
|
|
112
|
-
for feat in relation.children:
|
|
113
|
-
if feat in combination:
|
|
114
|
-
cnf.append(-1 * self.destination_model.get_variable(feat.name))
|
|
115
|
-
else:
|
|
116
|
-
cnf.append(self.destination_model.get_variable(feat.name))
|
|
117
|
-
clauses.append(cnf)
|
|
118
|
-
|
|
119
|
-
# there is a special case when coping with the upper part of the thru table
|
|
120
|
-
# In the case of allowing 0 childs, you cannot exclude the option in that
|
|
121
|
-
# no feature in this relation is activated
|
|
122
|
-
for val in range(1, len(relation.children) + 1):
|
|
123
|
-
|
|
124
|
-
for combination in itertools.combinations(relation.children, val):
|
|
125
|
-
cnf = [value_parent]
|
|
126
|
-
for feat in relation.children:
|
|
127
|
-
if feat in combination:
|
|
128
|
-
cnf.append(-1 * self.destination_model.get_variable(feat.name))
|
|
129
|
-
else:
|
|
130
|
-
cnf.append(self.destination_model.get_variable(feat.name))
|
|
131
|
-
clauses.append(cnf)
|
|
132
|
-
return clauses
|
|
133
|
-
|
|
134
|
-
def _store_constraint_clauses(self, clauses: List[List[int]]) -> None:
|
|
135
|
-
for clause in clauses:
|
|
136
|
-
self.destination_model.add_clause(clause)
|
|
137
|
-
|
|
138
|
-
def add_relation(self, relation: Relation) -> None:
|
|
139
|
-
if relation.is_mandatory():
|
|
140
|
-
clauses = self._add_mandatory_relation(relation)
|
|
141
|
-
elif relation.is_optional():
|
|
142
|
-
clauses = self._add_optional_relation(relation)
|
|
143
|
-
elif relation.is_or():
|
|
144
|
-
clauses = self._add_or_relation(relation)
|
|
145
|
-
elif relation.is_alternative():
|
|
146
|
-
clauses = self._add_alternative_relation(relation)
|
|
147
|
-
else:
|
|
148
|
-
clauses = self._add_constraint_relation(relation)
|
|
149
|
-
self._store_constraint_clauses(clauses)
|
|
150
|
-
|
|
151
|
-
def _allocate_auxiliary(self, aux_names: list[str]) -> dict[str, int]:
|
|
152
|
-
"""Assign a fresh SAT variable id to each Tseytin auxiliary name, recording it as
|
|
153
|
-
a non-feature auxiliary variable so it is excluded from feature enumeration."""
|
|
154
|
-
aux_map: dict[str, int] = {}
|
|
155
|
-
for name in aux_names:
|
|
156
|
-
var = self.counter
|
|
157
|
-
self.counter += 1
|
|
158
|
-
aux_map[name] = var
|
|
159
|
-
self.destination_model.auxiliary_variables.add(var)
|
|
160
|
-
return aux_map
|
|
161
|
-
|
|
162
|
-
def add_constraint(self, ctc: Constraint) -> None:
|
|
163
|
-
if self.cnf_method == 'tseytin':
|
|
164
|
-
clauses, aux_names = ctc.ast.get_clauses_with_aux(method='tseytin')
|
|
165
|
-
aux_map = self._allocate_auxiliary(aux_names)
|
|
166
|
-
else:
|
|
167
|
-
clauses = ctc.ast.get_clauses()
|
|
168
|
-
aux_map = {}
|
|
169
|
-
|
|
170
|
-
def get_term_variable(term: Any) -> int:
|
|
171
|
-
negated = term.startswith('-')
|
|
172
|
-
name = term[1:] if negated else term
|
|
173
|
-
var = aux_map[name] if name in aux_map else self.destination_model.get_variable(name)
|
|
174
|
-
return -var if negated else var
|
|
175
|
-
|
|
176
|
-
for clause in clauses:
|
|
177
|
-
clause_variables = list(map(get_term_variable, clause))
|
|
178
|
-
self.destination_model.add_clause(clause_variables)
|
|
179
|
-
|
|
180
|
-
def transform(self) -> PySATModel:
|
|
181
|
-
for feature in self.source_model.get_features():
|
|
182
|
-
self.add_feature(feature)
|
|
183
|
-
|
|
184
|
-
self.add_root(self.source_model.root)
|
|
185
|
-
|
|
186
|
-
for relation in self.source_model.get_relations():
|
|
187
|
-
self.add_relation(relation)
|
|
188
|
-
|
|
189
|
-
for constraint in self.source_model.get_logical_constraints():
|
|
190
|
-
self.add_constraint(constraint)
|
|
191
|
-
|
|
192
|
-
return self.destination_model
|
|
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
|
{flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy/metamodels/pysat_metamodel/__init__.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
|
|
File without changes
|
|
File without changes
|
{flamapy_sat-2.6.0.dev5 → flamapy_sat-2.6.0.dev11}/flamapy_sat.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|