flamapy-sdd 2.6.0.dev11__tar.gz → 2.9.0.dev0__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_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/PKG-INFO +3 -3
- flamapy_sdd-2.9.0.dev0/flamapy/metamodels/sdd_metamodel/__init__.py +24 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/operations/sdd_core_features.py +6 -2
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/transformations/fm_to_sdd.py +2 -2
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/PKG-INFO +3 -3
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/SOURCES.txt +1 -0
- flamapy_sdd-2.9.0.dev0/flamapy_sdd.egg-info/entry_points.txt +2 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/requires.txt +2 -2
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/pyproject.toml +6 -3
- flamapy_sdd-2.9.0.dev0/tests/test_sdd.py +166 -0
- flamapy_sdd-2.6.0.dev11/flamapy/metamodels/sdd_metamodel/__init__.py +0 -0
- flamapy_sdd-2.6.0.dev11/tests/test_sdd.py +0 -82
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/LICENSE +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/README.md +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/models/__init__.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/models/sdd_model.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/operations/__init__.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/operations/sdd_configurations_number.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/operations/sdd_dead_features.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/operations/sdd_satisfiable.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy/metamodels/sdd_metamodel/transformations/__init__.py +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/dependency_links.txt +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/top_level.txt +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/setup.cfg +0 -0
- {flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-sdd
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0.dev0
|
|
4
4
|
Summary: flamapy-sdd is a plugin to flamapy providing Sentential Decision Diagram (SDD) knowledge compilation for exact analysis of feature models
|
|
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/sdd_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.
|
|
12
|
-
Requires-Dist: flamapy-fm~=2.
|
|
11
|
+
Requires-Dist: flamapy-fw~=2.9.0.dev0
|
|
12
|
+
Requires-Dist: flamapy-fm~=2.9.0.dev0
|
|
13
13
|
Requires-Dist: PySDD~=1.0
|
|
14
14
|
Provides-Extra: dev
|
|
15
15
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from flamapy.core.manifest import OperationCapability, PluginManifest
|
|
2
|
+
from flamapy.core.models.language_level import LanguageLevel, MajorLevel, MinorLevel
|
|
3
|
+
|
|
4
|
+
# Costs are estimated milliseconds from the 2026-11-06 calibration (betty synthetic models at 1%
|
|
5
|
+
# and 30% constraint density plus JHipster and busybox; worst case of the two densities, never
|
|
6
|
+
# decreasing). Compilation depends on the constraint density far more than on the size: the
|
|
7
|
+
# sparse models compile in 0.3 s up to 2,000 features, the dense 500-feature one takes 7.5 s and
|
|
8
|
+
# the dense 1,000-feature one (like busybox, 1,108 features) does not finish in 5 minutes.
|
|
9
|
+
# Counting is then immediate (66 ms at 500 features), but core/dead features condition the SDD
|
|
10
|
+
# per variable: 41 s for core and more than 3 minutes for dead on the dense 500-feature model.
|
|
11
|
+
MANIFEST = PluginManifest(
|
|
12
|
+
name='sdd',
|
|
13
|
+
calibration='2026-11-06',
|
|
14
|
+
extension='sdd',
|
|
15
|
+
supported_level=LanguageLevel(MajorLevel.BOOLEAN, {MinorLevel.GROUP_CARDINALITY}),
|
|
16
|
+
max_features=2000,
|
|
17
|
+
transformation_cost_curve=((50, 3), (100, 5), (200, 10), (500, 7500), (1000, 300000)),
|
|
18
|
+
operations={
|
|
19
|
+
'satisfiable': OperationCapability(cost=1),
|
|
20
|
+
'configurations_number': OperationCapability(cost_curve=((200, 1), (500, 66))),
|
|
21
|
+
'core_features': OperationCapability(cost_curve=((100, 1), (200, 5), (500, 41000))),
|
|
22
|
+
'dead_features': OperationCapability(cost_curve=((100, 1), (200, 4), (500, 180000))),
|
|
23
|
+
},
|
|
24
|
+
)
|
|
@@ -9,7 +9,8 @@ class SDDCoreFeatures(CoreFeatures):
|
|
|
9
9
|
"""Core features: present in every valid configuration.
|
|
10
10
|
|
|
11
11
|
A feature is core iff no model selects it as false, i.e. conjoining its negative literal
|
|
12
|
-
with the compiled SDD yields the false node.
|
|
12
|
+
with the compiled SDD yields the false node. A void model has no core features (the
|
|
13
|
+
convention of the SAT and BDD plugins), not vacuously all of them.
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
def __init__(self) -> None:
|
|
@@ -24,7 +25,10 @@ class SDDCoreFeatures(CoreFeatures):
|
|
|
24
25
|
def execute(self, model: VariabilityModel) -> 'SDDCoreFeatures':
|
|
25
26
|
sdd_model = cast(SDDModel, model)
|
|
26
27
|
manager = sdd_model.manager
|
|
27
|
-
core = []
|
|
28
|
+
core: list[Any] = []
|
|
29
|
+
if sdd_model.root.is_false(): # void model
|
|
30
|
+
self._result = core
|
|
31
|
+
return self
|
|
28
32
|
for variable, name in sdd_model.features.items():
|
|
29
33
|
if (sdd_model.root & manager.literal(-variable)).is_false():
|
|
30
34
|
core.append(name)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pysdd.sdd import SddManager, Vtree
|
|
2
2
|
|
|
3
3
|
from flamapy.core.transformations import ModelToModel
|
|
4
|
-
from flamapy.metamodels.fm_metamodel.models import
|
|
4
|
+
from flamapy.metamodels.fm_metamodel.models import ClauseSet, DEFAULT_CNF_METHOD, FeatureModel
|
|
5
5
|
from flamapy.metamodels.sdd_metamodel.models import SDDModel
|
|
6
6
|
|
|
7
7
|
|
|
@@ -20,7 +20,7 @@ class FmToSDD(ModelToModel):
|
|
|
20
20
|
def get_destination_extension() -> str:
|
|
21
21
|
return 'sdd'
|
|
22
22
|
|
|
23
|
-
def __init__(self, source_model: FeatureModel, cnf_method: str =
|
|
23
|
+
def __init__(self, source_model: FeatureModel, cnf_method: str = DEFAULT_CNF_METHOD) -> None:
|
|
24
24
|
self.source_model = source_model
|
|
25
25
|
self.cnf_method = cnf_method
|
|
26
26
|
self.destination_model = SDDModel()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-sdd
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0.dev0
|
|
4
4
|
Summary: flamapy-sdd is a plugin to flamapy providing Sentential Decision Diagram (SDD) knowledge compilation for exact analysis of feature models
|
|
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/sdd_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.
|
|
12
|
-
Requires-Dist: flamapy-fm~=2.
|
|
11
|
+
Requires-Dist: flamapy-fw~=2.9.0.dev0
|
|
12
|
+
Requires-Dist: flamapy-fm~=2.9.0.dev0
|
|
13
13
|
Requires-Dist: PySDD~=1.0
|
|
14
14
|
Provides-Extra: dev
|
|
15
15
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -15,6 +15,7 @@ flamapy/metamodels/sdd_metamodel/transformations/fm_to_sdd.py
|
|
|
15
15
|
flamapy_sdd.egg-info/PKG-INFO
|
|
16
16
|
flamapy_sdd.egg-info/SOURCES.txt
|
|
17
17
|
flamapy_sdd.egg-info/dependency_links.txt
|
|
18
|
+
flamapy_sdd.egg-info/entry_points.txt
|
|
18
19
|
flamapy_sdd.egg-info/requires.txt
|
|
19
20
|
flamapy_sdd.egg-info/top_level.txt
|
|
20
21
|
tests/test_sdd.py
|
|
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flamapy-sdd"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.9.0.dev0"
|
|
8
8
|
description = "flamapy-sdd is a plugin to flamapy providing Sentential Decision Diagram (SDD) knowledge compilation for exact analysis of feature models"
|
|
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.
|
|
15
|
-
"flamapy-fm~=2.
|
|
14
|
+
"flamapy-fw~=2.9.0.dev0",
|
|
15
|
+
"flamapy-fm~=2.9.0.dev0",
|
|
16
16
|
"PySDD~=1.0",
|
|
17
17
|
]
|
|
18
18
|
|
|
@@ -25,6 +25,9 @@ dev = [
|
|
|
25
25
|
"coverage",
|
|
26
26
|
]
|
|
27
27
|
|
|
28
|
+
[project.entry-points."flamapy.plugins"]
|
|
29
|
+
sdd = "flamapy.metamodels.sdd_metamodel"
|
|
30
|
+
|
|
28
31
|
[project.urls]
|
|
29
32
|
Homepage = "https://github.com/flamapy/sdd_metamodel"
|
|
30
33
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Tests for the SDD metamodel: exact counting, satisfiability, core/dead features.
|
|
2
|
+
|
|
3
|
+
Oracles are computed by brute-forcing the CNF from fm_metamodel's solver-agnostic ClauseSet,
|
|
4
|
+
so CI needs no SAT plugin — only flamapy-fm, which is already a declared dependency.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import tempfile
|
|
8
|
+
from itertools import product
|
|
9
|
+
|
|
10
|
+
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
11
|
+
from flamapy.metamodels.fm_metamodel.models import FeatureModel, ClauseSet
|
|
12
|
+
from flamapy.metamodels.sdd_metamodel.transformations import FmToSDD
|
|
13
|
+
from flamapy.metamodels.sdd_metamodel.operations import (
|
|
14
|
+
SDDConfigurationsNumber,
|
|
15
|
+
SDDSatisfiable,
|
|
16
|
+
SDDCoreFeatures,
|
|
17
|
+
SDDDeadFeatures,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _valid_configs(fm: FeatureModel) -> tuple:
|
|
22
|
+
"""(valid configurations as frozensets of selected names, all feature names)."""
|
|
23
|
+
clause_set = ClauseSet.from_feature_model(fm)
|
|
24
|
+
name_of = {vid: name for name, vid in clause_set.variables.items()}
|
|
25
|
+
var_ids = sorted({abs(lit) for clause in clause_set.clauses for lit in clause}
|
|
26
|
+
| set(clause_set.variables.values()))
|
|
27
|
+
configs = set()
|
|
28
|
+
for bits in product((False, True), repeat=len(var_ids)):
|
|
29
|
+
assignment = dict(zip(var_ids, bits))
|
|
30
|
+
if all(any((lit > 0) == assignment[abs(lit)] for lit in clause)
|
|
31
|
+
for clause in clause_set.clauses):
|
|
32
|
+
configs.add(frozenset(name_of[v] for v in var_ids if assignment[v] and v in name_of))
|
|
33
|
+
return configs, set(clause_set.variables)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _exact_count(fm: FeatureModel) -> int:
|
|
37
|
+
return len(_valid_configs(fm)[0])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _core_features(fm: FeatureModel) -> set:
|
|
41
|
+
configs, names = _valid_configs(fm)
|
|
42
|
+
return {name for name in names if configs and all(name in cfg for cfg in configs)}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _dead_features(fm: FeatureModel) -> set:
|
|
46
|
+
configs, names = _valid_configs(fm)
|
|
47
|
+
return names - (set().union(*configs) if configs else set())
|
|
48
|
+
|
|
49
|
+
_UVL = """features
|
|
50
|
+
Root {abstract}
|
|
51
|
+
mandatory
|
|
52
|
+
Base
|
|
53
|
+
optional
|
|
54
|
+
A
|
|
55
|
+
B
|
|
56
|
+
C
|
|
57
|
+
constraints
|
|
58
|
+
A => B
|
|
59
|
+
A | B
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
_UNSAT_UVL = """features
|
|
63
|
+
Root {abstract}
|
|
64
|
+
mandatory
|
|
65
|
+
A
|
|
66
|
+
constraints
|
|
67
|
+
!A
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _fm(uvl):
|
|
72
|
+
handle, path = tempfile.mkstemp(suffix='.uvl')
|
|
73
|
+
try:
|
|
74
|
+
with os.fdopen(handle, 'w') as file:
|
|
75
|
+
file.write(uvl)
|
|
76
|
+
return UVLReader(path).transform()
|
|
77
|
+
finally:
|
|
78
|
+
os.remove(path)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_count_matches_sat_enumeration():
|
|
82
|
+
fm = _fm(_UVL)
|
|
83
|
+
exact = _exact_count(fm)
|
|
84
|
+
sdd = SDDConfigurationsNumber().execute(FmToSDD(fm).transform()).get_result()
|
|
85
|
+
assert sdd == exact
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_satisfiable():
|
|
89
|
+
assert SDDSatisfiable().execute(FmToSDD(_fm(_UVL)).transform()).get_result() is True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_unsatisfiable_model():
|
|
93
|
+
assert SDDSatisfiable().execute(FmToSDD(_fm(_UNSAT_UVL)).transform()).get_result() is False
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_core_features_match_sat():
|
|
97
|
+
fm = _fm(_UVL)
|
|
98
|
+
expected = _core_features(fm)
|
|
99
|
+
sdd = set(SDDCoreFeatures().execute(FmToSDD(fm).transform()).get_result())
|
|
100
|
+
assert sdd == expected
|
|
101
|
+
assert 'Base' in sdd and 'Root' in sdd # mandatory chain is core
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_dead_features_match_sat():
|
|
105
|
+
fm = _fm(_UVL)
|
|
106
|
+
expected = _dead_features(fm)
|
|
107
|
+
sdd = set(SDDDeadFeatures().execute(FmToSDD(fm).transform()).get_result())
|
|
108
|
+
assert sdd == expected # no dead features in this model
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_void_model_has_no_core_features():
|
|
112
|
+
fm = _fm(_UNSAT_UVL)
|
|
113
|
+
model = FmToSDD(fm).transform()
|
|
114
|
+
assert SDDCoreFeatures().execute(model).get_result() == []
|
|
115
|
+
assert set(SDDCoreFeatures().execute(model).get_result()) == _core_features(fm)
|
|
116
|
+
assert set(SDDDeadFeatures().execute(model).get_result()) == _dead_features(fm)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
_TSEYTIN_UVL = """features
|
|
120
|
+
Root {abstract}
|
|
121
|
+
optional
|
|
122
|
+
A
|
|
123
|
+
B
|
|
124
|
+
C
|
|
125
|
+
D
|
|
126
|
+
E
|
|
127
|
+
F
|
|
128
|
+
constraints
|
|
129
|
+
(A & B & C) | (D & E & F) | (B & E & F)
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_cnf_methods_agree():
|
|
134
|
+
"""Tseytin auxiliary variables must not change the count or the core/dead features.
|
|
135
|
+
|
|
136
|
+
The constraint is wide enough for 'auto' to choose Tseytin (27 distributive clauses).
|
|
137
|
+
"""
|
|
138
|
+
fm = _fm(_TSEYTIN_UVL)
|
|
139
|
+
assert ClauseSet.from_feature_model(fm, cnf_method='auto').auxiliary_variables
|
|
140
|
+
expected = (_exact_count(fm), _core_features(fm), _dead_features(fm))
|
|
141
|
+
for method in ('distributive', 'tseytin', 'auto'):
|
|
142
|
+
model = FmToSDD(fm, cnf_method=method).transform()
|
|
143
|
+
got = (SDDConfigurationsNumber().execute(model).get_result(),
|
|
144
|
+
set(SDDCoreFeatures().execute(model).get_result()),
|
|
145
|
+
set(SDDDeadFeatures().execute(model).get_result()))
|
|
146
|
+
assert got == expected, method
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# [1..2] over A, B, C (3 + 3 selections) times D optional: 12 configurations.
|
|
150
|
+
_GROUP_UVL = """features
|
|
151
|
+
Root {abstract}
|
|
152
|
+
[1..2]
|
|
153
|
+
A
|
|
154
|
+
B
|
|
155
|
+
C
|
|
156
|
+
optional
|
|
157
|
+
D
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_group_cardinality():
|
|
162
|
+
fm = _fm(_GROUP_UVL)
|
|
163
|
+
model = FmToSDD(fm).transform()
|
|
164
|
+
assert SDDConfigurationsNumber().execute(model).get_result() == 12
|
|
165
|
+
assert set(SDDCoreFeatures().execute(model).get_result()) == _core_features(fm) == {'Root'}
|
|
166
|
+
assert set(SDDDeadFeatures().execute(model).get_result()) == _dead_features(fm) == set()
|
|
File without changes
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"""Tests for the SDD metamodel: exact counting, satisfiability, core/dead features.
|
|
2
|
-
|
|
3
|
-
Oracles come from the SAT backend (a declared dependency) so CI needs no extra plugin.
|
|
4
|
-
"""
|
|
5
|
-
import os
|
|
6
|
-
import tempfile
|
|
7
|
-
|
|
8
|
-
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
9
|
-
from flamapy.metamodels.sdd_metamodel.transformations import FmToSDD
|
|
10
|
-
from flamapy.metamodels.sdd_metamodel.operations import (
|
|
11
|
-
SDDConfigurationsNumber,
|
|
12
|
-
SDDSatisfiable,
|
|
13
|
-
SDDCoreFeatures,
|
|
14
|
-
SDDDeadFeatures,
|
|
15
|
-
)
|
|
16
|
-
from flamapy.metamodels.pysat_metamodel.transformations import FmToPysat
|
|
17
|
-
from flamapy.metamodels.pysat_metamodel.operations.pysat_configurations_number import (
|
|
18
|
-
PySATConfigurationsNumber,
|
|
19
|
-
)
|
|
20
|
-
from flamapy.metamodels.pysat_metamodel.operations.pysat_core_features import PySATCoreFeatures
|
|
21
|
-
from flamapy.metamodels.pysat_metamodel.operations.pysat_dead_features import PySATDeadFeatures
|
|
22
|
-
|
|
23
|
-
_UVL = """features
|
|
24
|
-
Root {abstract}
|
|
25
|
-
mandatory
|
|
26
|
-
Base
|
|
27
|
-
optional
|
|
28
|
-
A
|
|
29
|
-
B
|
|
30
|
-
C
|
|
31
|
-
constraints
|
|
32
|
-
A => B
|
|
33
|
-
A | B
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
_UNSAT_UVL = """features
|
|
37
|
-
Root {abstract}
|
|
38
|
-
mandatory
|
|
39
|
-
A
|
|
40
|
-
constraints
|
|
41
|
-
!A
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def _fm(uvl):
|
|
46
|
-
handle, path = tempfile.mkstemp(suffix='.uvl')
|
|
47
|
-
try:
|
|
48
|
-
with os.fdopen(handle, 'w') as file:
|
|
49
|
-
file.write(uvl)
|
|
50
|
-
return UVLReader(path).transform()
|
|
51
|
-
finally:
|
|
52
|
-
os.remove(path)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def test_count_matches_sat_enumeration():
|
|
56
|
-
fm = _fm(_UVL)
|
|
57
|
-
exact = PySATConfigurationsNumber().execute(FmToPysat(fm).transform()).get_result()
|
|
58
|
-
sdd = SDDConfigurationsNumber().execute(FmToSDD(fm).transform()).get_result()
|
|
59
|
-
assert sdd == exact
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def test_satisfiable():
|
|
63
|
-
assert SDDSatisfiable().execute(FmToSDD(_fm(_UVL)).transform()).get_result() is True
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_unsatisfiable_model():
|
|
67
|
-
assert SDDSatisfiable().execute(FmToSDD(_fm(_UNSAT_UVL)).transform()).get_result() is False
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def test_core_features_match_sat():
|
|
71
|
-
fm = _fm(_UVL)
|
|
72
|
-
sat = set(PySATCoreFeatures().execute(FmToPysat(fm).transform()).get_result())
|
|
73
|
-
sdd = set(SDDCoreFeatures().execute(FmToSDD(fm).transform()).get_result())
|
|
74
|
-
assert sdd == sat
|
|
75
|
-
assert 'Base' in sdd and 'Root' in sdd # mandatory chain is core
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def test_dead_features_match_sat():
|
|
79
|
-
fm = _fm(_UVL)
|
|
80
|
-
sat = set(PySATDeadFeatures().execute(FmToPysat(fm).transform()).get_result())
|
|
81
|
-
sdd = set(SDDDeadFeatures().execute(FmToSDD(fm).transform()).get_result())
|
|
82
|
-
assert sdd == sat # no dead features in this 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
|
{flamapy_sdd-2.6.0.dev11 → flamapy_sdd-2.9.0.dev0}/flamapy_sdd.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|