flamapy-z3 2.5.0.dev0__tar.gz → 2.6.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_z3-2.6.0.dev0/PKG-INFO +32 -0
- flamapy_z3-2.6.0.dev0/README.md +13 -0
- flamapy_z3-2.6.0.dev0/flamapy_z3.egg-info/PKG-INFO +32 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy_z3.egg-info/requires.txt +2 -2
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/pyproject.toml +3 -3
- flamapy_z3-2.5.0.dev0/PKG-INFO +0 -202
- flamapy_z3-2.5.0.dev0/README.md +0 -183
- flamapy_z3-2.5.0.dev0/flamapy_z3.egg-info/PKG-INFO +0 -202
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/__init__.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/models/__init__.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/models/z3_model.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/__init__.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/interfaces/__init__.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/interfaces/attribute_optimization.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_all_feature_bounds.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_attribute_optimization.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_configurations.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_configurations_number.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_core_features.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_dead_features.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_false_optional_features.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_feature_bounds.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_satisfiable.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_satisfiable_configuration.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/operations/z3_variable_bounds_complex.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/transformations/__init__.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/transformations/fm_to_z3.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy_z3.egg-info/SOURCES.txt +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy_z3.egg-info/dependency_links.txt +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy_z3.egg-info/top_level.txt +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/setup.cfg +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/setup.py +0 -0
- {flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/tests/test_z3_metamodel.py +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flamapy-z3
|
|
3
|
+
Version: 2.6.0.dev0
|
|
4
|
+
Summary: z3-plugin for the automated analysis of feature models
|
|
5
|
+
Author-email: Flamapy <flamapy@us.es>
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/flamapy/z3_metamodel
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: flamapy-fw~=2.6.0.dev0
|
|
11
|
+
Requires-Dist: flamapy-fm~=2.6.0.dev0
|
|
12
|
+
Requires-Dist: z3-solver~=4.14.1.0
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
16
|
+
Requires-Dist: prospector; extra == "dev"
|
|
17
|
+
Requires-Dist: mypy; extra == "dev"
|
|
18
|
+
Requires-Dist: coverage; extra == "dev"
|
|
19
|
+
|
|
20
|
+
# flamapy-z3
|
|
21
|
+
|
|
22
|
+
SMT-based analysis for [flamapy](https://flamapy.org) feature models with typed
|
|
23
|
+
attributes (Integer, Real, String), built on the [Z3](https://github.com/Z3Prover/z3)
|
|
24
|
+
solver.
|
|
25
|
+
|
|
26
|
+
**Documentation:** https://docs.flamapy.org/framework/plugins/z3_plugin
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install flamapy-z3
|
|
32
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# flamapy-z3
|
|
2
|
+
|
|
3
|
+
SMT-based analysis for [flamapy](https://flamapy.org) feature models with typed
|
|
4
|
+
attributes (Integer, Real, String), built on the [Z3](https://github.com/Z3Prover/z3)
|
|
5
|
+
solver.
|
|
6
|
+
|
|
7
|
+
**Documentation:** https://docs.flamapy.org/framework/plugins/z3_plugin
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install flamapy-z3
|
|
13
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flamapy-z3
|
|
3
|
+
Version: 2.6.0.dev0
|
|
4
|
+
Summary: z3-plugin for the automated analysis of feature models
|
|
5
|
+
Author-email: Flamapy <flamapy@us.es>
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/flamapy/z3_metamodel
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: flamapy-fw~=2.6.0.dev0
|
|
11
|
+
Requires-Dist: flamapy-fm~=2.6.0.dev0
|
|
12
|
+
Requires-Dist: z3-solver~=4.14.1.0
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
16
|
+
Requires-Dist: prospector; extra == "dev"
|
|
17
|
+
Requires-Dist: mypy; extra == "dev"
|
|
18
|
+
Requires-Dist: coverage; extra == "dev"
|
|
19
|
+
|
|
20
|
+
# flamapy-z3
|
|
21
|
+
|
|
22
|
+
SMT-based analysis for [flamapy](https://flamapy.org) feature models with typed
|
|
23
|
+
attributes (Integer, Real, String), built on the [Z3](https://github.com/Z3Prover/z3)
|
|
24
|
+
solver.
|
|
25
|
+
|
|
26
|
+
**Documentation:** https://docs.flamapy.org/framework/plugins/z3_plugin
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install flamapy-z3
|
|
32
|
+
```
|
|
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flamapy-z3"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.6.0.dev0"
|
|
8
8
|
description = "z3-plugin for the automated 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.9"
|
|
13
13
|
dependencies = [
|
|
14
|
-
"flamapy-fw~=2.
|
|
15
|
-
"flamapy-fm~=2.
|
|
14
|
+
"flamapy-fw~=2.6.0.dev0",
|
|
15
|
+
"flamapy-fm~=2.6.0.dev0",
|
|
16
16
|
"z3-solver~=4.14.1.0",
|
|
17
17
|
]
|
|
18
18
|
|
flamapy_z3-2.5.0.dev0/PKG-INFO
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: flamapy-z3
|
|
3
|
-
Version: 2.5.0.dev0
|
|
4
|
-
Summary: z3-plugin for the automated analysis of feature models
|
|
5
|
-
Author-email: Flamapy <flamapy@us.es>
|
|
6
|
-
License-Expression: GPL-3.0-or-later
|
|
7
|
-
Project-URL: Homepage, https://github.com/flamapy/z3_metamodel
|
|
8
|
-
Requires-Python: >=3.9
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
Requires-Dist: flamapy-fw~=2.5.0.dev0
|
|
11
|
-
Requires-Dist: flamapy-fm~=2.5.0.dev0
|
|
12
|
-
Requires-Dist: z3-solver~=4.14.1.0
|
|
13
|
-
Provides-Extra: dev
|
|
14
|
-
Requires-Dist: pytest; extra == "dev"
|
|
15
|
-
Requires-Dist: pytest-mock; extra == "dev"
|
|
16
|
-
Requires-Dist: prospector; extra == "dev"
|
|
17
|
-
Requires-Dist: mypy; extra == "dev"
|
|
18
|
-
Requires-Dist: coverage; extra == "dev"
|
|
19
|
-
|
|
20
|
-
# Automated Analysis of UVL using Satisfiability Modulo Theories
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Description
|
|
24
|
-
This repository contains the plugin that supports z3 representations for feature models.
|
|
25
|
-
|
|
26
|
-
The plugin is based on [flamapy](https://flamapy.github.io/), and relies on the [Z3 solver](https://github.com/Z3Prover/z3?tab=readme-ov-file) library. The architecture is as follows:
|
|
27
|
-
|
|
28
|
-
<p align="center">
|
|
29
|
-
<img width="750" src="resources/images/z3metamodel.png">
|
|
30
|
-
</p>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## Requirements and Installation
|
|
34
|
-
- [Python 3.11+](https://www.python.org/)
|
|
35
|
-
- [Flamapy](https://www.flamapy.org/)
|
|
36
|
-
|
|
37
|
-
The framework has been tested in Linux and Windows 11 with Python 3.12. Python 3.13+ may not be still supported.
|
|
38
|
-
|
|
39
|
-
### Download and installation
|
|
40
|
-
1. Install [Python 3.11+](https://www.python.org/).
|
|
41
|
-
2. Download/Clone this repository and enter into the main directory.
|
|
42
|
-
3. Create a virtual environment: `python -m venv env`
|
|
43
|
-
4. Activate the environment:
|
|
44
|
-
|
|
45
|
-
In Linux: `source env/bin/activate`
|
|
46
|
-
|
|
47
|
-
In Windows: `.\env\Scripts\Activate`
|
|
48
|
-
|
|
49
|
-
5. Install dependencies (flamapy): `pip install -r requirements.txt`
|
|
50
|
-
|
|
51
|
-
** In case that you are running Ubuntu and get an error installing flamapy, please install the package python3-dev with the command `sudo apt update && sudo apt install python3-dev` and update wheel and setuptools with the command `pip install --upgrade pip wheel setuptools` before step 5.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
## Functionality and usage
|
|
55
|
-
The executable script [test.py](/test.py) serves as an entry point to show the plugin in action.
|
|
56
|
-
|
|
57
|
-
Simply run: `python test.py` to see it in action over the running feature model presented in the paper.
|
|
58
|
-
|
|
59
|
-
The following functionality is provided:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### Load a feature model in UVL and translate to SMT
|
|
63
|
-
```python
|
|
64
|
-
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
65
|
-
from flamapy.metamodels.z3_metamodel.transformations import FmToZ3
|
|
66
|
-
|
|
67
|
-
# Load the feature model from UVL
|
|
68
|
-
fm_model = UVLReader('resources/models/uvl_models/Pizza_z3.uvl').transform()
|
|
69
|
-
# Transform the feature model to SMT
|
|
70
|
-
z3_model = FmToZ3(fm_model).transform()
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Analysis operations
|
|
74
|
-
The following operations are available:
|
|
75
|
-
```python
|
|
76
|
-
from flamapy.metamodels.z3_metamodel.operations import (
|
|
77
|
-
Z3Satisfiable,
|
|
78
|
-
Z3Configurations,
|
|
79
|
-
Z3ConfigurationsNumber,
|
|
80
|
-
Z3CoreFeatures,
|
|
81
|
-
Z3DeadFeatures,
|
|
82
|
-
Z3FalseOptionalFeatures,
|
|
83
|
-
Z3AttributeOptimization,
|
|
84
|
-
Z3SatisfiableConfiguration,
|
|
85
|
-
Z3FeatureBounds,
|
|
86
|
-
Z3AllFeatureBounds,
|
|
87
|
-
)
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
- **Satisfiable**
|
|
91
|
-
|
|
92
|
-
Return whether the model is satisfiable (valid):
|
|
93
|
-
```python
|
|
94
|
-
satisfiable = Z3Satisfiable().execute(z3_model).get_result()
|
|
95
|
-
print(f'Satisfiable? (valid?): {satisfiable}')
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
- **Core features**
|
|
99
|
-
|
|
100
|
-
Return the core features of the model:
|
|
101
|
-
```python
|
|
102
|
-
core_features = Z3CoreFeatures().execute(z3_model).get_result()
|
|
103
|
-
print(f'Core features: {core_features}')
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
- **Dead features**
|
|
107
|
-
|
|
108
|
-
Return the dead features of the model:
|
|
109
|
-
```python
|
|
110
|
-
dead_features = Z3DeadFeatures().execute(z3_model).get_result()
|
|
111
|
-
print(f'Dead features: {dead_features}')
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- **False-Optional features**
|
|
115
|
-
|
|
116
|
-
Return the false-optional features of the model:
|
|
117
|
-
```python
|
|
118
|
-
false_optional_features = Z3FalseOptionalFeatures().execute(z3_model).get_result()
|
|
119
|
-
print(f'False-optional features: {false_optional_features}')
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- **Configurations**
|
|
123
|
-
|
|
124
|
-
Enumerate the configurations of the model:
|
|
125
|
-
```python
|
|
126
|
-
configurations = Z3Configurations().execute(z3_model).get_result()
|
|
127
|
-
print(f'Configurations: {len(configurations)}')
|
|
128
|
-
for i, config in enumerate(configurations, 1):
|
|
129
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
130
|
-
print(f'Config. {i}: {config_str}')
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
- **Configurations number**
|
|
134
|
-
|
|
135
|
-
Return the number of configurations:
|
|
136
|
-
```python
|
|
137
|
-
n_configs = Z3ConfigurationsNumber().execute(z3_model).get_result()
|
|
138
|
-
print(f'Configurations number: {n_configs}')
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
- **Boundaries analysis of typed features**
|
|
142
|
-
|
|
143
|
-
Return the boundaries of the numerical features (Integer, Real, String) of the model:
|
|
144
|
-
```python
|
|
145
|
-
attributes = fm_model.get_attributes()
|
|
146
|
-
print('Attributes in the model')
|
|
147
|
-
for attr in attributes:
|
|
148
|
-
print(f' - {attr.name} ({attr.attribute_type})')
|
|
149
|
-
|
|
150
|
-
variable_bounds = Z3AllFeatureBounds().execute(z3_model).get_result()
|
|
151
|
-
print('Variable bounds for all typed variables:')
|
|
152
|
-
for var_name, bounds in variable_bounds.items():
|
|
153
|
-
print(f' - {var_name}: {bounds}')
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- **Configuration optimization based on feature attributes:**
|
|
157
|
-
|
|
158
|
-
Return the set of configurations that optimize the given goals (i.e., the pareto front):
|
|
159
|
-
```python
|
|
160
|
-
attribute_optimization_op = Z3AttributeOptimization()
|
|
161
|
-
attributes = {'Price': OptimizationGoal.MAXIMIZE,
|
|
162
|
-
'Kcal': OptimizationGoal.MINIMIZE}
|
|
163
|
-
attribute_optimization_op.set_attributes(attributes)
|
|
164
|
-
configurations_with_values = attribute_optimization_op.execute(z3_model).get_result()
|
|
165
|
-
print(f'Optimum configurations: {len(configurations_with_values)} configs.')
|
|
166
|
-
for i, config_value in enumerate(configurations_with_values, 1):
|
|
167
|
-
config, values = config_value
|
|
168
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
169
|
-
values_str = ', '.join(f'{k}={v}' for k,v in values.items())
|
|
170
|
-
print(f'Config. {i}: {config_str} | Values: {values_str}')
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
- Configuration validation:
|
|
174
|
-
|
|
175
|
-
Return whether a given partial or full configuration is valid:
|
|
176
|
-
```python
|
|
177
|
-
from flamapy.metamodels.configuration_metamodel.transformations import ConfigurationJSONReader
|
|
178
|
-
configuration = ConfigurationJSONReader('resources/configs/pizza_z3_config1.json').transform()
|
|
179
|
-
configuration.set_full(False)
|
|
180
|
-
print(f'Configuration: {configuration.elements}')
|
|
181
|
-
satisfiable_configuration_op = Z3SatisfiableConfiguration()
|
|
182
|
-
satisfiable_configuration_op.set_configuration(configuration)
|
|
183
|
-
is_satisfiable = satisfiable_configuration_op.execute(z3_model).get_result()
|
|
184
|
-
print(f'Is the configuration satisfiable? {is_satisfiable}')
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations may takes longer if the number of configuration is huge, or even not finish if the model is unbounded.
|
|
188
|
-
|
|
189
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations support also a partial configuration as an additional argument, so the operation will return the result taking into account the given partial configuration.
|
|
190
|
-
For example:
|
|
191
|
-
|
|
192
|
-
```python
|
|
193
|
-
from flamapy.core.models import Configuration
|
|
194
|
-
# Create a partial configuration
|
|
195
|
-
elements = {'Pizza': True, 'SpicyLvl': 5}
|
|
196
|
-
partial_config = Configuration(elements)
|
|
197
|
-
# Calculate the number of configuration from the partial configuration
|
|
198
|
-
configs_number_op = Z3ConfigurationsNumber()
|
|
199
|
-
configs_number_op.set_partial_configuration(partial_config)
|
|
200
|
-
n_configs = configs_number_op.execute(z3_model).get_result()
|
|
201
|
-
print(f'#Configurations: {n_configs}')
|
|
202
|
-
```
|
flamapy_z3-2.5.0.dev0/README.md
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# Automated Analysis of UVL using Satisfiability Modulo Theories
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
## Description
|
|
5
|
-
This repository contains the plugin that supports z3 representations for feature models.
|
|
6
|
-
|
|
7
|
-
The plugin is based on [flamapy](https://flamapy.github.io/), and relies on the [Z3 solver](https://github.com/Z3Prover/z3?tab=readme-ov-file) library. The architecture is as follows:
|
|
8
|
-
|
|
9
|
-
<p align="center">
|
|
10
|
-
<img width="750" src="resources/images/z3metamodel.png">
|
|
11
|
-
</p>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Requirements and Installation
|
|
15
|
-
- [Python 3.11+](https://www.python.org/)
|
|
16
|
-
- [Flamapy](https://www.flamapy.org/)
|
|
17
|
-
|
|
18
|
-
The framework has been tested in Linux and Windows 11 with Python 3.12. Python 3.13+ may not be still supported.
|
|
19
|
-
|
|
20
|
-
### Download and installation
|
|
21
|
-
1. Install [Python 3.11+](https://www.python.org/).
|
|
22
|
-
2. Download/Clone this repository and enter into the main directory.
|
|
23
|
-
3. Create a virtual environment: `python -m venv env`
|
|
24
|
-
4. Activate the environment:
|
|
25
|
-
|
|
26
|
-
In Linux: `source env/bin/activate`
|
|
27
|
-
|
|
28
|
-
In Windows: `.\env\Scripts\Activate`
|
|
29
|
-
|
|
30
|
-
5. Install dependencies (flamapy): `pip install -r requirements.txt`
|
|
31
|
-
|
|
32
|
-
** In case that you are running Ubuntu and get an error installing flamapy, please install the package python3-dev with the command `sudo apt update && sudo apt install python3-dev` and update wheel and setuptools with the command `pip install --upgrade pip wheel setuptools` before step 5.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## Functionality and usage
|
|
36
|
-
The executable script [test.py](/test.py) serves as an entry point to show the plugin in action.
|
|
37
|
-
|
|
38
|
-
Simply run: `python test.py` to see it in action over the running feature model presented in the paper.
|
|
39
|
-
|
|
40
|
-
The following functionality is provided:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### Load a feature model in UVL and translate to SMT
|
|
44
|
-
```python
|
|
45
|
-
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
46
|
-
from flamapy.metamodels.z3_metamodel.transformations import FmToZ3
|
|
47
|
-
|
|
48
|
-
# Load the feature model from UVL
|
|
49
|
-
fm_model = UVLReader('resources/models/uvl_models/Pizza_z3.uvl').transform()
|
|
50
|
-
# Transform the feature model to SMT
|
|
51
|
-
z3_model = FmToZ3(fm_model).transform()
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Analysis operations
|
|
55
|
-
The following operations are available:
|
|
56
|
-
```python
|
|
57
|
-
from flamapy.metamodels.z3_metamodel.operations import (
|
|
58
|
-
Z3Satisfiable,
|
|
59
|
-
Z3Configurations,
|
|
60
|
-
Z3ConfigurationsNumber,
|
|
61
|
-
Z3CoreFeatures,
|
|
62
|
-
Z3DeadFeatures,
|
|
63
|
-
Z3FalseOptionalFeatures,
|
|
64
|
-
Z3AttributeOptimization,
|
|
65
|
-
Z3SatisfiableConfiguration,
|
|
66
|
-
Z3FeatureBounds,
|
|
67
|
-
Z3AllFeatureBounds,
|
|
68
|
-
)
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- **Satisfiable**
|
|
72
|
-
|
|
73
|
-
Return whether the model is satisfiable (valid):
|
|
74
|
-
```python
|
|
75
|
-
satisfiable = Z3Satisfiable().execute(z3_model).get_result()
|
|
76
|
-
print(f'Satisfiable? (valid?): {satisfiable}')
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
- **Core features**
|
|
80
|
-
|
|
81
|
-
Return the core features of the model:
|
|
82
|
-
```python
|
|
83
|
-
core_features = Z3CoreFeatures().execute(z3_model).get_result()
|
|
84
|
-
print(f'Core features: {core_features}')
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
- **Dead features**
|
|
88
|
-
|
|
89
|
-
Return the dead features of the model:
|
|
90
|
-
```python
|
|
91
|
-
dead_features = Z3DeadFeatures().execute(z3_model).get_result()
|
|
92
|
-
print(f'Dead features: {dead_features}')
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
- **False-Optional features**
|
|
96
|
-
|
|
97
|
-
Return the false-optional features of the model:
|
|
98
|
-
```python
|
|
99
|
-
false_optional_features = Z3FalseOptionalFeatures().execute(z3_model).get_result()
|
|
100
|
-
print(f'False-optional features: {false_optional_features}')
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
- **Configurations**
|
|
104
|
-
|
|
105
|
-
Enumerate the configurations of the model:
|
|
106
|
-
```python
|
|
107
|
-
configurations = Z3Configurations().execute(z3_model).get_result()
|
|
108
|
-
print(f'Configurations: {len(configurations)}')
|
|
109
|
-
for i, config in enumerate(configurations, 1):
|
|
110
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
111
|
-
print(f'Config. {i}: {config_str}')
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- **Configurations number**
|
|
115
|
-
|
|
116
|
-
Return the number of configurations:
|
|
117
|
-
```python
|
|
118
|
-
n_configs = Z3ConfigurationsNumber().execute(z3_model).get_result()
|
|
119
|
-
print(f'Configurations number: {n_configs}')
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- **Boundaries analysis of typed features**
|
|
123
|
-
|
|
124
|
-
Return the boundaries of the numerical features (Integer, Real, String) of the model:
|
|
125
|
-
```python
|
|
126
|
-
attributes = fm_model.get_attributes()
|
|
127
|
-
print('Attributes in the model')
|
|
128
|
-
for attr in attributes:
|
|
129
|
-
print(f' - {attr.name} ({attr.attribute_type})')
|
|
130
|
-
|
|
131
|
-
variable_bounds = Z3AllFeatureBounds().execute(z3_model).get_result()
|
|
132
|
-
print('Variable bounds for all typed variables:')
|
|
133
|
-
for var_name, bounds in variable_bounds.items():
|
|
134
|
-
print(f' - {var_name}: {bounds}')
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
- **Configuration optimization based on feature attributes:**
|
|
138
|
-
|
|
139
|
-
Return the set of configurations that optimize the given goals (i.e., the pareto front):
|
|
140
|
-
```python
|
|
141
|
-
attribute_optimization_op = Z3AttributeOptimization()
|
|
142
|
-
attributes = {'Price': OptimizationGoal.MAXIMIZE,
|
|
143
|
-
'Kcal': OptimizationGoal.MINIMIZE}
|
|
144
|
-
attribute_optimization_op.set_attributes(attributes)
|
|
145
|
-
configurations_with_values = attribute_optimization_op.execute(z3_model).get_result()
|
|
146
|
-
print(f'Optimum configurations: {len(configurations_with_values)} configs.')
|
|
147
|
-
for i, config_value in enumerate(configurations_with_values, 1):
|
|
148
|
-
config, values = config_value
|
|
149
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
150
|
-
values_str = ', '.join(f'{k}={v}' for k,v in values.items())
|
|
151
|
-
print(f'Config. {i}: {config_str} | Values: {values_str}')
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
- Configuration validation:
|
|
155
|
-
|
|
156
|
-
Return whether a given partial or full configuration is valid:
|
|
157
|
-
```python
|
|
158
|
-
from flamapy.metamodels.configuration_metamodel.transformations import ConfigurationJSONReader
|
|
159
|
-
configuration = ConfigurationJSONReader('resources/configs/pizza_z3_config1.json').transform()
|
|
160
|
-
configuration.set_full(False)
|
|
161
|
-
print(f'Configuration: {configuration.elements}')
|
|
162
|
-
satisfiable_configuration_op = Z3SatisfiableConfiguration()
|
|
163
|
-
satisfiable_configuration_op.set_configuration(configuration)
|
|
164
|
-
is_satisfiable = satisfiable_configuration_op.execute(z3_model).get_result()
|
|
165
|
-
print(f'Is the configuration satisfiable? {is_satisfiable}')
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations may takes longer if the number of configuration is huge, or even not finish if the model is unbounded.
|
|
169
|
-
|
|
170
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations support also a partial configuration as an additional argument, so the operation will return the result taking into account the given partial configuration.
|
|
171
|
-
For example:
|
|
172
|
-
|
|
173
|
-
```python
|
|
174
|
-
from flamapy.core.models import Configuration
|
|
175
|
-
# Create a partial configuration
|
|
176
|
-
elements = {'Pizza': True, 'SpicyLvl': 5}
|
|
177
|
-
partial_config = Configuration(elements)
|
|
178
|
-
# Calculate the number of configuration from the partial configuration
|
|
179
|
-
configs_number_op = Z3ConfigurationsNumber()
|
|
180
|
-
configs_number_op.set_partial_configuration(partial_config)
|
|
181
|
-
n_configs = configs_number_op.execute(z3_model).get_result()
|
|
182
|
-
print(f'#Configurations: {n_configs}')
|
|
183
|
-
```
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: flamapy-z3
|
|
3
|
-
Version: 2.5.0.dev0
|
|
4
|
-
Summary: z3-plugin for the automated analysis of feature models
|
|
5
|
-
Author-email: Flamapy <flamapy@us.es>
|
|
6
|
-
License-Expression: GPL-3.0-or-later
|
|
7
|
-
Project-URL: Homepage, https://github.com/flamapy/z3_metamodel
|
|
8
|
-
Requires-Python: >=3.9
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
Requires-Dist: flamapy-fw~=2.5.0.dev0
|
|
11
|
-
Requires-Dist: flamapy-fm~=2.5.0.dev0
|
|
12
|
-
Requires-Dist: z3-solver~=4.14.1.0
|
|
13
|
-
Provides-Extra: dev
|
|
14
|
-
Requires-Dist: pytest; extra == "dev"
|
|
15
|
-
Requires-Dist: pytest-mock; extra == "dev"
|
|
16
|
-
Requires-Dist: prospector; extra == "dev"
|
|
17
|
-
Requires-Dist: mypy; extra == "dev"
|
|
18
|
-
Requires-Dist: coverage; extra == "dev"
|
|
19
|
-
|
|
20
|
-
# Automated Analysis of UVL using Satisfiability Modulo Theories
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Description
|
|
24
|
-
This repository contains the plugin that supports z3 representations for feature models.
|
|
25
|
-
|
|
26
|
-
The plugin is based on [flamapy](https://flamapy.github.io/), and relies on the [Z3 solver](https://github.com/Z3Prover/z3?tab=readme-ov-file) library. The architecture is as follows:
|
|
27
|
-
|
|
28
|
-
<p align="center">
|
|
29
|
-
<img width="750" src="resources/images/z3metamodel.png">
|
|
30
|
-
</p>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## Requirements and Installation
|
|
34
|
-
- [Python 3.11+](https://www.python.org/)
|
|
35
|
-
- [Flamapy](https://www.flamapy.org/)
|
|
36
|
-
|
|
37
|
-
The framework has been tested in Linux and Windows 11 with Python 3.12. Python 3.13+ may not be still supported.
|
|
38
|
-
|
|
39
|
-
### Download and installation
|
|
40
|
-
1. Install [Python 3.11+](https://www.python.org/).
|
|
41
|
-
2. Download/Clone this repository and enter into the main directory.
|
|
42
|
-
3. Create a virtual environment: `python -m venv env`
|
|
43
|
-
4. Activate the environment:
|
|
44
|
-
|
|
45
|
-
In Linux: `source env/bin/activate`
|
|
46
|
-
|
|
47
|
-
In Windows: `.\env\Scripts\Activate`
|
|
48
|
-
|
|
49
|
-
5. Install dependencies (flamapy): `pip install -r requirements.txt`
|
|
50
|
-
|
|
51
|
-
** In case that you are running Ubuntu and get an error installing flamapy, please install the package python3-dev with the command `sudo apt update && sudo apt install python3-dev` and update wheel and setuptools with the command `pip install --upgrade pip wheel setuptools` before step 5.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
## Functionality and usage
|
|
55
|
-
The executable script [test.py](/test.py) serves as an entry point to show the plugin in action.
|
|
56
|
-
|
|
57
|
-
Simply run: `python test.py` to see it in action over the running feature model presented in the paper.
|
|
58
|
-
|
|
59
|
-
The following functionality is provided:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### Load a feature model in UVL and translate to SMT
|
|
63
|
-
```python
|
|
64
|
-
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
|
|
65
|
-
from flamapy.metamodels.z3_metamodel.transformations import FmToZ3
|
|
66
|
-
|
|
67
|
-
# Load the feature model from UVL
|
|
68
|
-
fm_model = UVLReader('resources/models/uvl_models/Pizza_z3.uvl').transform()
|
|
69
|
-
# Transform the feature model to SMT
|
|
70
|
-
z3_model = FmToZ3(fm_model).transform()
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Analysis operations
|
|
74
|
-
The following operations are available:
|
|
75
|
-
```python
|
|
76
|
-
from flamapy.metamodels.z3_metamodel.operations import (
|
|
77
|
-
Z3Satisfiable,
|
|
78
|
-
Z3Configurations,
|
|
79
|
-
Z3ConfigurationsNumber,
|
|
80
|
-
Z3CoreFeatures,
|
|
81
|
-
Z3DeadFeatures,
|
|
82
|
-
Z3FalseOptionalFeatures,
|
|
83
|
-
Z3AttributeOptimization,
|
|
84
|
-
Z3SatisfiableConfiguration,
|
|
85
|
-
Z3FeatureBounds,
|
|
86
|
-
Z3AllFeatureBounds,
|
|
87
|
-
)
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
- **Satisfiable**
|
|
91
|
-
|
|
92
|
-
Return whether the model is satisfiable (valid):
|
|
93
|
-
```python
|
|
94
|
-
satisfiable = Z3Satisfiable().execute(z3_model).get_result()
|
|
95
|
-
print(f'Satisfiable? (valid?): {satisfiable}')
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
- **Core features**
|
|
99
|
-
|
|
100
|
-
Return the core features of the model:
|
|
101
|
-
```python
|
|
102
|
-
core_features = Z3CoreFeatures().execute(z3_model).get_result()
|
|
103
|
-
print(f'Core features: {core_features}')
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
- **Dead features**
|
|
107
|
-
|
|
108
|
-
Return the dead features of the model:
|
|
109
|
-
```python
|
|
110
|
-
dead_features = Z3DeadFeatures().execute(z3_model).get_result()
|
|
111
|
-
print(f'Dead features: {dead_features}')
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- **False-Optional features**
|
|
115
|
-
|
|
116
|
-
Return the false-optional features of the model:
|
|
117
|
-
```python
|
|
118
|
-
false_optional_features = Z3FalseOptionalFeatures().execute(z3_model).get_result()
|
|
119
|
-
print(f'False-optional features: {false_optional_features}')
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- **Configurations**
|
|
123
|
-
|
|
124
|
-
Enumerate the configurations of the model:
|
|
125
|
-
```python
|
|
126
|
-
configurations = Z3Configurations().execute(z3_model).get_result()
|
|
127
|
-
print(f'Configurations: {len(configurations)}')
|
|
128
|
-
for i, config in enumerate(configurations, 1):
|
|
129
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
130
|
-
print(f'Config. {i}: {config_str}')
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
- **Configurations number**
|
|
134
|
-
|
|
135
|
-
Return the number of configurations:
|
|
136
|
-
```python
|
|
137
|
-
n_configs = Z3ConfigurationsNumber().execute(z3_model).get_result()
|
|
138
|
-
print(f'Configurations number: {n_configs}')
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
- **Boundaries analysis of typed features**
|
|
142
|
-
|
|
143
|
-
Return the boundaries of the numerical features (Integer, Real, String) of the model:
|
|
144
|
-
```python
|
|
145
|
-
attributes = fm_model.get_attributes()
|
|
146
|
-
print('Attributes in the model')
|
|
147
|
-
for attr in attributes:
|
|
148
|
-
print(f' - {attr.name} ({attr.attribute_type})')
|
|
149
|
-
|
|
150
|
-
variable_bounds = Z3AllFeatureBounds().execute(z3_model).get_result()
|
|
151
|
-
print('Variable bounds for all typed variables:')
|
|
152
|
-
for var_name, bounds in variable_bounds.items():
|
|
153
|
-
print(f' - {var_name}: {bounds}')
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- **Configuration optimization based on feature attributes:**
|
|
157
|
-
|
|
158
|
-
Return the set of configurations that optimize the given goals (i.e., the pareto front):
|
|
159
|
-
```python
|
|
160
|
-
attribute_optimization_op = Z3AttributeOptimization()
|
|
161
|
-
attributes = {'Price': OptimizationGoal.MAXIMIZE,
|
|
162
|
-
'Kcal': OptimizationGoal.MINIMIZE}
|
|
163
|
-
attribute_optimization_op.set_attributes(attributes)
|
|
164
|
-
configurations_with_values = attribute_optimization_op.execute(z3_model).get_result()
|
|
165
|
-
print(f'Optimum configurations: {len(configurations_with_values)} configs.')
|
|
166
|
-
for i, config_value in enumerate(configurations_with_values, 1):
|
|
167
|
-
config, values = config_value
|
|
168
|
-
config_str = ', '.join(f'{f}={v}' if not isinstance(v, bool) else f'{f}' for f,v in config.elements.items() if config.is_selected(f))
|
|
169
|
-
values_str = ', '.join(f'{k}={v}' for k,v in values.items())
|
|
170
|
-
print(f'Config. {i}: {config_str} | Values: {values_str}')
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
- Configuration validation:
|
|
174
|
-
|
|
175
|
-
Return whether a given partial or full configuration is valid:
|
|
176
|
-
```python
|
|
177
|
-
from flamapy.metamodels.configuration_metamodel.transformations import ConfigurationJSONReader
|
|
178
|
-
configuration = ConfigurationJSONReader('resources/configs/pizza_z3_config1.json').transform()
|
|
179
|
-
configuration.set_full(False)
|
|
180
|
-
print(f'Configuration: {configuration.elements}')
|
|
181
|
-
satisfiable_configuration_op = Z3SatisfiableConfiguration()
|
|
182
|
-
satisfiable_configuration_op.set_configuration(configuration)
|
|
183
|
-
is_satisfiable = satisfiable_configuration_op.execute(z3_model).get_result()
|
|
184
|
-
print(f'Is the configuration satisfiable? {is_satisfiable}')
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations may takes longer if the number of configuration is huge, or even not finish if the model is unbounded.
|
|
188
|
-
|
|
189
|
-
**Note:** The Z3Configurations and Z3ConfigurationsNumber operations support also a partial configuration as an additional argument, so the operation will return the result taking into account the given partial configuration.
|
|
190
|
-
For example:
|
|
191
|
-
|
|
192
|
-
```python
|
|
193
|
-
from flamapy.core.models import Configuration
|
|
194
|
-
# Create a partial configuration
|
|
195
|
-
elements = {'Pizza': True, 'SpicyLvl': 5}
|
|
196
|
-
partial_config = Configuration(elements)
|
|
197
|
-
# Calculate the number of configuration from the partial configuration
|
|
198
|
-
configs_number_op = Z3ConfigurationsNumber()
|
|
199
|
-
configs_number_op.set_partial_configuration(partial_config)
|
|
200
|
-
n_configs = configs_number_op.execute(z3_model).get_result()
|
|
201
|
-
print(f'#Configurations: {n_configs}')
|
|
202
|
-
```
|
|
File without changes
|
{flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/models/__init__.py
RENAMED
|
File without changes
|
{flamapy_z3-2.5.0.dev0 → flamapy_z3-2.6.0.dev0}/flamapy/metamodels/z3_metamodel/models/z3_model.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|