flamapy-dnnf 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_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/PKG-INFO +3 -3
- flamapy_dnnf-2.9.0.dev0/flamapy/metamodels/dnnf_metamodel/__init__.py +35 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/models/dnnf_model.py +3 -2
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/transformations/fm_to_dnnf.py +2 -2
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/PKG-INFO +3 -3
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/SOURCES.txt +1 -0
- flamapy_dnnf-2.9.0.dev0/flamapy_dnnf.egg-info/entry_points.txt +2 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/requires.txt +2 -2
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/pyproject.toml +6 -3
- flamapy_dnnf-2.9.0.dev0/tests/test_dnnf.py +147 -0
- flamapy_dnnf-2.6.0.dev11/flamapy/metamodels/dnnf_metamodel/__init__.py +0 -0
- flamapy_dnnf-2.6.0.dev11/tests/test_dnnf.py +0 -71
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/LICENSE +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/README.md +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/models/__init__.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/operations/__init__.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/operations/d4_runner.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/operations/dnnf_configurations_number.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/operations/dnnf_satisfiable.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy/metamodels/dnnf_metamodel/transformations/__init__.py +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/dependency_links.txt +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/top_level.txt +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/setup.cfg +0 -0
- {flamapy_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-dnnf
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0.dev0
|
|
4
4
|
Summary: flamapy-dnnf is a plugin to flamapy providing exact analysis of feature models via d-DNNF knowledge compilation with the d4 compiler
|
|
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/dnnf_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
|
Provides-Extra: dev
|
|
14
14
|
Requires-Dist: pytest; extra == "dev"
|
|
15
15
|
Requires-Dist: pytest-mock; extra == "dev"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from flamapy.core.exceptions import FlamaException
|
|
2
|
+
from flamapy.core.manifest import PluginManifest, OperationCapability
|
|
3
|
+
from flamapy.core.models.language_level import LanguageLevel, MajorLevel, MinorLevel
|
|
4
|
+
from flamapy.metamodels.dnnf_metamodel.models.dnnf_model import locate_d4
|
|
5
|
+
|
|
6
|
+
# d-DNNF compilation scales further than BDDs for counting. The cost is a placeholder: the
|
|
7
|
+
# 2026-11-06 calibration machine had no d4, so this plugin is the one without measured curves.
|
|
8
|
+
# It declares no ``calibration``, so the planner only picks it when no calibrated plugin can
|
|
9
|
+
# run the operation.
|
|
10
|
+
# d4 is a native binary with no PyPI distribution (see models.locate_d4): without it the
|
|
11
|
+
# operations fail (the transformation, which only writes the DIMACS file, still runs), so the
|
|
12
|
+
# manifest declares the plugin unavailable and the planner never routes to it. The check runs
|
|
13
|
+
# once, when the plugin is imported: set FLAMAPY_D4_PATH before that.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _d4_available() -> bool:
|
|
17
|
+
try:
|
|
18
|
+
locate_d4()
|
|
19
|
+
except FlamaException:
|
|
20
|
+
return False
|
|
21
|
+
return True
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_D4_AVAILABLE = _d4_available()
|
|
25
|
+
|
|
26
|
+
MANIFEST = PluginManifest(
|
|
27
|
+
name='dnnf',
|
|
28
|
+
extension='dnnf',
|
|
29
|
+
available=_D4_AVAILABLE,
|
|
30
|
+
unavailable_reason='the d4 compiler is not installed (set FLAMAPY_D4_PATH or put d4 on PATH)',
|
|
31
|
+
supported_level=LanguageLevel(MajorLevel.BOOLEAN, {MinorLevel.GROUP_CARDINALITY}),
|
|
32
|
+
operations={
|
|
33
|
+
'configurations_number': OperationCapability(cost=80),
|
|
34
|
+
},
|
|
35
|
+
)
|
|
@@ -14,9 +14,10 @@ def locate_d4() -> str:
|
|
|
14
14
|
installed separately.
|
|
15
15
|
"""
|
|
16
16
|
candidate = os.environ.get('FLAMAPY_D4_PATH') or shutil.which('d4')
|
|
17
|
-
if not candidate or not os.path.
|
|
17
|
+
if not candidate or not os.path.isfile(candidate) or not os.access(candidate, os.X_OK):
|
|
18
18
|
raise FlamaException(
|
|
19
|
-
'The d4 compiler was not found. Install d4
|
|
19
|
+
'The d4 compiler was not found (or is not executable). Install d4 '
|
|
20
|
+
'(https://github.com/crillab/d4) and '
|
|
20
21
|
'expose it as "d4" on PATH or via the FLAMAPY_D4_PATH environment variable.'
|
|
21
22
|
)
|
|
22
23
|
return candidate
|
|
@@ -3,7 +3,7 @@ import subprocess
|
|
|
3
3
|
import tempfile
|
|
4
4
|
|
|
5
5
|
from flamapy.core.transformations import ModelToModel
|
|
6
|
-
from flamapy.metamodels.fm_metamodel.models import
|
|
6
|
+
from flamapy.metamodels.fm_metamodel.models import ClauseSet, DEFAULT_CNF_METHOD, FeatureModel
|
|
7
7
|
from flamapy.metamodels.dnnf_metamodel.models import DDNNFModel, locate_d4
|
|
8
8
|
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ class FmToDDNNF(ModelToModel):
|
|
|
26
26
|
def __init__(
|
|
27
27
|
self,
|
|
28
28
|
source_model: FeatureModel,
|
|
29
|
-
cnf_method: str =
|
|
29
|
+
cnf_method: str = DEFAULT_CNF_METHOD,
|
|
30
30
|
compile: bool = False,
|
|
31
31
|
) -> None:
|
|
32
32
|
self.source_model = source_model
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flamapy-dnnf
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0.dev0
|
|
4
4
|
Summary: flamapy-dnnf is a plugin to flamapy providing exact analysis of feature models via d-DNNF knowledge compilation with the d4 compiler
|
|
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/dnnf_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
|
Provides-Extra: dev
|
|
14
14
|
Requires-Dist: pytest; extra == "dev"
|
|
15
15
|
Requires-Dist: pytest-mock; extra == "dev"
|
|
@@ -14,6 +14,7 @@ flamapy/metamodels/dnnf_metamodel/transformations/fm_to_dnnf.py
|
|
|
14
14
|
flamapy_dnnf.egg-info/PKG-INFO
|
|
15
15
|
flamapy_dnnf.egg-info/SOURCES.txt
|
|
16
16
|
flamapy_dnnf.egg-info/dependency_links.txt
|
|
17
|
+
flamapy_dnnf.egg-info/entry_points.txt
|
|
17
18
|
flamapy_dnnf.egg-info/requires.txt
|
|
18
19
|
flamapy_dnnf.egg-info/top_level.txt
|
|
19
20
|
tests/test_dnnf.py
|
|
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flamapy-dnnf"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.9.0.dev0"
|
|
8
8
|
description = "flamapy-dnnf is a plugin to flamapy providing exact analysis of feature models via d-DNNF knowledge compilation with the d4 compiler"
|
|
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
|
]
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
@@ -24,6 +24,9 @@ dev = [
|
|
|
24
24
|
"coverage",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
|
+
[project.entry-points."flamapy.plugins"]
|
|
28
|
+
dnnf = "flamapy.metamodels.dnnf_metamodel"
|
|
29
|
+
|
|
27
30
|
[project.urls]
|
|
28
31
|
Homepage = "https://github.com/flamapy/dnnf_metamodel"
|
|
29
32
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Tests for the d-DNNF (d4) metamodel.
|
|
2
|
+
|
|
3
|
+
d4 is a native binary with no PyPI distribution, so these tests are skipped unless d4 is
|
|
4
|
+
available (on PATH or via FLAMAPY_D4_PATH). When present, exact counts are checked against an
|
|
5
|
+
oracle brute-forced from fm_metamodel's solver-agnostic ClauseSet (no SAT plugin needed).
|
|
6
|
+
"""
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import tempfile
|
|
10
|
+
from itertools import product
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
15
|
+
from flamapy.metamodels.fm_metamodel.models import FeatureModel, ClauseSet
|
|
16
|
+
from flamapy.metamodels.dnnf_metamodel.transformations import FmToDDNNF
|
|
17
|
+
from flamapy.metamodels.dnnf_metamodel.operations import (
|
|
18
|
+
DDNNFConfigurationsNumber,
|
|
19
|
+
DDNNFSatisfiable,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _exact_count(fm: FeatureModel) -> int:
|
|
24
|
+
"""Exact configuration count by brute-forcing the ClauseSet CNF (no SAT backend)."""
|
|
25
|
+
clause_set = ClauseSet.from_feature_model(fm)
|
|
26
|
+
name_of = {vid: name for name, vid in clause_set.variables.items()}
|
|
27
|
+
var_ids = sorted({abs(lit) for clause in clause_set.clauses for lit in clause}
|
|
28
|
+
| set(clause_set.variables.values()))
|
|
29
|
+
configs = set()
|
|
30
|
+
for bits in product((False, True), repeat=len(var_ids)):
|
|
31
|
+
assignment = dict(zip(var_ids, bits))
|
|
32
|
+
if all(any((lit > 0) == assignment[abs(lit)] for lit in clause)
|
|
33
|
+
for clause in clause_set.clauses):
|
|
34
|
+
configs.add(frozenset(name_of[v] for v in var_ids if assignment[v] and v in name_of))
|
|
35
|
+
return len(configs)
|
|
36
|
+
|
|
37
|
+
_D4_AVAILABLE = bool(os.environ.get('FLAMAPY_D4_PATH') or shutil.which('d4'))
|
|
38
|
+
requires_d4 = pytest.mark.skipif(not _D4_AVAILABLE, reason='the d4 compiler is not installed')
|
|
39
|
+
|
|
40
|
+
_UVL = """features
|
|
41
|
+
Root {abstract}
|
|
42
|
+
mandatory
|
|
43
|
+
Base
|
|
44
|
+
optional
|
|
45
|
+
A
|
|
46
|
+
B
|
|
47
|
+
C
|
|
48
|
+
constraints
|
|
49
|
+
A => B
|
|
50
|
+
A | B
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _fm(uvl):
|
|
55
|
+
handle, path = tempfile.mkstemp(suffix='.uvl')
|
|
56
|
+
try:
|
|
57
|
+
with os.fdopen(handle, 'w') as file:
|
|
58
|
+
file.write(uvl)
|
|
59
|
+
return UVLReader(path).transform()
|
|
60
|
+
finally:
|
|
61
|
+
os.remove(path)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@requires_d4
|
|
65
|
+
def test_count_matches_sat():
|
|
66
|
+
fm = _fm(_UVL)
|
|
67
|
+
exact = _exact_count(fm)
|
|
68
|
+
dnnf = DDNNFConfigurationsNumber().execute(FmToDDNNF(fm).transform()).get_result()
|
|
69
|
+
assert dnnf == exact
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@requires_d4
|
|
73
|
+
def test_satisfiable():
|
|
74
|
+
assert DDNNFSatisfiable().execute(FmToDDNNF(_fm(_UVL)).transform()).get_result() is True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_transformation_writes_dimacs():
|
|
78
|
+
"""The DIMACS export does not need d4 and can always be checked."""
|
|
79
|
+
model = FmToDDNNF(_fm(_UVL)).transform()
|
|
80
|
+
assert os.path.exists(model.dimacs_path)
|
|
81
|
+
with open(model.dimacs_path) as dimacs:
|
|
82
|
+
header = dimacs.readline()
|
|
83
|
+
assert header.startswith('p cnf ')
|
|
84
|
+
assert model.var_count >= 5 # Root, Base, A, B, C
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
_TSEYTIN_UVL = """features
|
|
88
|
+
Root {abstract}
|
|
89
|
+
optional
|
|
90
|
+
A
|
|
91
|
+
B
|
|
92
|
+
C
|
|
93
|
+
D
|
|
94
|
+
E
|
|
95
|
+
F
|
|
96
|
+
constraints
|
|
97
|
+
(A & B & C) | (D & E & F) | (B & E & F)
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
# [1..2] over A, B, C (3 + 3 selections) times D optional: 12 configurations.
|
|
101
|
+
_GROUP_UVL = """features
|
|
102
|
+
Root {abstract}
|
|
103
|
+
[1..2]
|
|
104
|
+
A
|
|
105
|
+
B
|
|
106
|
+
C
|
|
107
|
+
optional
|
|
108
|
+
D
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_tseytin_adds_variables_to_the_dimacs():
|
|
113
|
+
"""Without d4: the 'auto'/'tseytin' CNF written for d4 holds the auxiliary variables."""
|
|
114
|
+
fm = _fm(_TSEYTIN_UVL)
|
|
115
|
+
plain = FmToDDNNF(fm, cnf_method='distributive').transform()
|
|
116
|
+
gated = FmToDDNNF(fm, cnf_method='tseytin').transform()
|
|
117
|
+
assert gated.var_count > plain.var_count == 7 # Root and A-F
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@requires_d4
|
|
121
|
+
def test_cnf_methods_agree():
|
|
122
|
+
fm = _fm(_TSEYTIN_UVL)
|
|
123
|
+
exact = _exact_count(fm)
|
|
124
|
+
for method in ('distributive', 'tseytin', 'auto'):
|
|
125
|
+
model = FmToDDNNF(fm, cnf_method=method).transform()
|
|
126
|
+
assert DDNNFConfigurationsNumber().execute(model).get_result() == exact, method
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@requires_d4
|
|
130
|
+
def test_group_cardinality():
|
|
131
|
+
model = FmToDDNNF(_fm(_GROUP_UVL)).transform()
|
|
132
|
+
assert DDNNFConfigurationsNumber().execute(model).get_result() == 12
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_availability_follows_locate_d4(monkeypatch, tmp_path):
|
|
136
|
+
import importlib # noqa: PLC0415
|
|
137
|
+
import flamapy.metamodels.dnnf_metamodel as plugin # noqa: PLC0415
|
|
138
|
+
monkeypatch.setenv('FLAMAPY_D4_PATH', str(tmp_path / 'missing-d4'))
|
|
139
|
+
monkeypatch.setattr(shutil, 'which', lambda _name: None)
|
|
140
|
+
assert importlib.reload(plugin).MANIFEST.available is False
|
|
141
|
+
fake = tmp_path / 'd4'
|
|
142
|
+
fake.write_text('#!/bin/sh\n')
|
|
143
|
+
fake.chmod(0o755)
|
|
144
|
+
monkeypatch.setenv('FLAMAPY_D4_PATH', str(fake))
|
|
145
|
+
assert importlib.reload(plugin).MANIFEST.available is True
|
|
146
|
+
monkeypatch.undo()
|
|
147
|
+
importlib.reload(plugin)
|
|
File without changes
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"""Tests for the d-DNNF (d4) metamodel.
|
|
2
|
-
|
|
3
|
-
d4 is a native binary with no PyPI distribution, so these tests are skipped unless d4 is
|
|
4
|
-
available (on PATH or via FLAMAPY_D4_PATH). When present, exact counts are checked against the
|
|
5
|
-
SAT backend oracle.
|
|
6
|
-
"""
|
|
7
|
-
import os
|
|
8
|
-
import shutil
|
|
9
|
-
import tempfile
|
|
10
|
-
|
|
11
|
-
import pytest
|
|
12
|
-
|
|
13
|
-
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
14
|
-
from flamapy.metamodels.dnnf_metamodel.transformations import FmToDDNNF
|
|
15
|
-
from flamapy.metamodels.dnnf_metamodel.operations import (
|
|
16
|
-
DDNNFConfigurationsNumber,
|
|
17
|
-
DDNNFSatisfiable,
|
|
18
|
-
)
|
|
19
|
-
from flamapy.metamodels.pysat_metamodel.transformations import FmToPysat
|
|
20
|
-
from flamapy.metamodels.pysat_metamodel.operations.pysat_configurations_number import (
|
|
21
|
-
PySATConfigurationsNumber,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
_D4_AVAILABLE = bool(os.environ.get('FLAMAPY_D4_PATH') or shutil.which('d4'))
|
|
25
|
-
requires_d4 = pytest.mark.skipif(not _D4_AVAILABLE, reason='the d4 compiler is not installed')
|
|
26
|
-
|
|
27
|
-
_UVL = """features
|
|
28
|
-
Root {abstract}
|
|
29
|
-
mandatory
|
|
30
|
-
Base
|
|
31
|
-
optional
|
|
32
|
-
A
|
|
33
|
-
B
|
|
34
|
-
C
|
|
35
|
-
constraints
|
|
36
|
-
A => B
|
|
37
|
-
A | B
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def _fm(uvl):
|
|
42
|
-
handle, path = tempfile.mkstemp(suffix='.uvl')
|
|
43
|
-
try:
|
|
44
|
-
with os.fdopen(handle, 'w') as file:
|
|
45
|
-
file.write(uvl)
|
|
46
|
-
return UVLReader(path).transform()
|
|
47
|
-
finally:
|
|
48
|
-
os.remove(path)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@requires_d4
|
|
52
|
-
def test_count_matches_sat():
|
|
53
|
-
fm = _fm(_UVL)
|
|
54
|
-
exact = PySATConfigurationsNumber().execute(FmToPysat(fm).transform()).get_result()
|
|
55
|
-
dnnf = DDNNFConfigurationsNumber().execute(FmToDDNNF(fm).transform()).get_result()
|
|
56
|
-
assert dnnf == exact
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@requires_d4
|
|
60
|
-
def test_satisfiable():
|
|
61
|
-
assert DDNNFSatisfiable().execute(FmToDDNNF(_fm(_UVL)).transform()).get_result() is True
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def test_transformation_writes_dimacs():
|
|
65
|
-
"""The DIMACS export does not need d4 and can always be checked."""
|
|
66
|
-
model = FmToDDNNF(_fm(_UVL)).transform()
|
|
67
|
-
assert os.path.exists(model.dimacs_path)
|
|
68
|
-
with open(model.dimacs_path) as dimacs:
|
|
69
|
-
header = dimacs.readline()
|
|
70
|
-
assert header.startswith('p cnf ')
|
|
71
|
-
assert model.var_count >= 5 # Root, Base, A, B, C
|
|
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_dnnf-2.6.0.dev11 → flamapy_dnnf-2.9.0.dev0}/flamapy_dnnf.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|