|
1 | | -# BDD plugin for flamapy |
2 | | -- [BDD plugin for flamapy](#bdd-plugin-for-flamapy) |
3 | | - - [Description](#description) |
4 | | - - [Requirements and Installation](#requirements-and-installation) |
5 | | - - [Functionality and usage](#functionality-and-usage) |
6 | | - - [Load a feature model in UVL and create the BDD](#load-a-feature-model-in-uvl-and-create-the-bdd) |
7 | | - - [Save the BDD in a file](#save-the-bdd-in-a-file) |
8 | | - - [Load the BDD from a file](#load-the-bdd-from-a-file) |
9 | | - - [Analysis operations](#analysis-operations) |
10 | | - - [Contributing to the BDD plugin](#contributing-to-the-bdd-plugin) |
| 1 | +# flamapy-bdd |
11 | 2 |
|
| 3 | +BDD-based analysis for [flamapy](https://flamapy.org) feature models, built on |
| 4 | +the [dd](https://github.com/tulip-control/dd) library. |
12 | 5 |
|
13 | | -## Description |
14 | | -This plugin supports Binary Decision Diagrams (BDDs) representations for feature models. |
| 6 | +**Documentation:** https://docs.flamapy.org/framework/plugins/bdd_plugin |
15 | 7 |
|
16 | | -The plugin is based on [flamapy](https://github.com/flamapy/core) and thus, it follows the same architecture: |
| 8 | +## Installation |
17 | 9 |
|
18 | | -<p align="center"> |
19 | | - <img width="750" src="doc/bdd_plugin.png"> |
20 | | -</p> |
21 | | - |
22 | | -The BDD plugin relies on the [dd](https://github.com/tulip-control/dd) library to manipulate BDDs. |
23 | | -The complete documentation of such library is available [here](https://github.com/tulip-control/dd/blob/main/doc.md). |
24 | | - |
25 | | -The following is an example of feature model and its BDD using complemented arcs. |
26 | | - |
27 | | -<p align="center"> |
28 | | - <img width="750" src="doc/fm_example.png"> |
29 | | -</p> |
30 | | - |
31 | | -<p align="center"> |
32 | | - <img width="750" src="doc/bdd_example.svg"> |
33 | | -</p> |
34 | | - |
35 | | -## Requirements and Installation |
36 | | -- Python 3.9+ |
37 | | -- This plugin depends on the [flamapy core](https://github.com/flamapy/core) and on the [Feature Model plugin](https://github.com/flamapy/fm_metamodel). |
38 | | - |
39 | | -``` |
40 | | -pip install flamapy flamapy-fm flamapy-bdd |
41 | | -``` |
42 | | - |
43 | | -We have tested the plugin on Linux, but Windows is also supported. |
44 | | - |
45 | | - |
46 | | -## Functionality and usage |
47 | | -The executable script [test_bdd_metamodel.py](https://github.com/flamapy/bdd_metamodel/blob/master/tests/test_bdd_metamodel.py) serves as an entry point to show the plugin in action. |
48 | | - |
49 | | -The following functionality is provided: |
50 | | - |
51 | | - |
52 | | -### Load a feature model in UVL and create the BDD |
53 | | -```python |
54 | | -from flamapy.metamodels.fm_metamodel.transformations import UVLReader |
55 | | -from flamapy.metamodels.bdd_metamodel.transformations import FmToBDD |
56 | | - |
57 | | -# Load the feature model from UVL |
58 | | -feature_model = UVLReader('models/uvl_models/pizzas.uvl').transform() |
59 | | -# Create the BDD from the feature model |
60 | | -bdd_model = FmToBDD(feature_model).transform() |
61 | | -``` |
62 | | - |
63 | | - |
64 | | -### Save the BDD in a file |
65 | | -```python |
66 | | -from flamapy.metamodels.bdd_metamodel.transformations import PNGWriter, DDDMPv3Writer |
67 | | -# Save the BDD as an image in PNG |
68 | | -PNGWriter(path='my_bdd.png', bdd_model).transform() |
69 | | -# Save the BDD in a .dddmp file |
70 | | -DDDMPv3Writer(f'my_bdd.dddmp', bdd_model).transform() |
71 | | -``` |
72 | | -Writers available: DDDMPv3 ('dddmp'), DDDMPv2 ('dddmp'), JSON ('json'), Pickle ('p'), PDF ('pdf'), PNG ('png'), SVG ('svg'). |
73 | | - |
74 | | -### Load the BDD from a file |
75 | | -```python |
76 | | -from flamapy.metamodels.bdd_metamodel.transformations import JSONReader |
77 | | -# Load the BDD from a .json file |
78 | | -bdd_model = JSONReader(path='path/to/my_bdd.json').transform() |
79 | | -``` |
80 | | -Readers available: JSON ('json'), DDDMP ('dddmp'), Pickle ('p'). |
81 | | - |
82 | | -*NOTE:* DDDMP and Pickle readers are not fully supported yet. |
83 | | - |
84 | | -### Analysis operations |
85 | | - |
86 | | -- Satisfiable |
87 | | - |
88 | | - Return whether the model is satisfiable (valid): |
89 | | - ```python |
90 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDSatisfiable |
91 | | - satisfiable = BDDSatisfiable().execute(bdd_model).get_result() |
92 | | - print(f'Satisfiable? (valid?): {satisfiable}') |
93 | | - ``` |
94 | | - |
95 | | -- Configurations number |
96 | | - |
97 | | - Return the number of configurations: |
98 | | - ```python |
99 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurationsNumber |
100 | | - n_configs = BDDConfigurationsNumber().execute(bdd_model).get_result() |
101 | | - print(f'#Configurations: {n_configs}') |
102 | | - ``` |
103 | | - |
104 | | -- Configurations |
105 | | - |
106 | | - Enumerate the configurations of the model: |
107 | | - ```python |
108 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurations |
109 | | - configurations = BDDConfigurations().execute(bdd_model).get_result() |
110 | | - for i, config in enumerate(configurations, 1): |
111 | | - print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}') |
112 | | - ``` |
113 | | - |
114 | | -- Sampling |
115 | | - |
116 | | - Return a sample of the given size of uniform random configurations with or without replacement: |
117 | | - ```python |
118 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDSampling |
119 | | - sampling_op = BDDSampling() |
120 | | - sampling_op.set_sample_size(5) |
121 | | - sampling_op.set_with_replacement(False) # Default False |
122 | | - sample = sampling_op.execute(bdd_model).get_result() |
123 | | - for i, config in enumerate(sample, 1): |
124 | | - print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}') |
125 | | - ``` |
126 | | - |
127 | | -- Product Distribution |
128 | | - |
129 | | - Return the number of products (configurations) having a given number of features: |
130 | | - ```python |
131 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistribution |
132 | | - dist = BDDProductDistribution().execute(bdd_model).get_result() |
133 | | - print(f'Product Distribution: {dist}') |
134 | | - ``` |
135 | | - |
136 | | -- Feature Inclusion Probability |
137 | | - |
138 | | - Return the probability for a feature to be included in a valid configuration: |
139 | | - ```python |
140 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbability |
141 | | - prob = BDDFeatureInclusionProbability().execute(bdd_model).get_result() |
142 | | - for feat in prob.keys(): |
143 | | - print(f'{feat}: {prob[feat]}') |
144 | | - ``` |
145 | | - |
146 | | -- Core features |
147 | | - |
148 | | - Return the core features (those features that are present in all the configurations): |
149 | | - ```python |
150 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDCoreFeatures |
151 | | - core_features = BDDCoreFeatures().execute(bdd_model).get_result() |
152 | | - print(f'Core features: {core_features}') |
153 | | - ``` |
154 | | - |
155 | | -- Dead features |
156 | | - |
157 | | - Return the dead features (those features that are not present in any configuration): |
158 | | - ```python |
159 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDDeadFeatures |
160 | | - dead_features = BDDDeadFeatures().execute(bdd_model).get_result() |
161 | | - print(f'Dead features: {dead_features}') |
162 | | - ``` |
163 | | - |
164 | | -Most analysis operations support also a partial configuration as an additional argument, so the operation will return the result taking into account the given partial configuration. For example: |
165 | | - |
166 | | -```python |
167 | | -from flamapy.core.models import Configuration |
168 | | -# Create a partial configuration |
169 | | -elements = {'Pizza': True, 'Big': True} |
170 | | -partial_config = Configuration(elements) |
171 | | -# Calculate the number of configuration from the partial configuration |
172 | | -configs_number_op = BDDConfigurationsNumber() |
173 | | -configs_number_op.set_partial_configuration(partial_config) |
174 | | -n_configs = configs_number_op.execute(bdd_model).get_result() |
175 | | -print(f'#Configurations: {n_configs}') |
| 10 | +```bash |
| 11 | +pip install flamapy-bdd |
176 | 12 | ``` |
177 | | - |
178 | | - |
179 | | -## Contributing to the BDD plugin |
180 | | -To contribute in the development of this plugin: |
181 | | - |
182 | | -1. Fork the repository into your GitHub account. |
183 | | -2. Clone the repository: `git@github.com:<<username>>/bdd_metamodel.git` |
184 | | -3. Create a virtual environment: `python -m venv env` |
185 | | -4. Activate the virtual environment: `source env/bin/activate` |
186 | | -5. Install the plugin dependencies: `pip install flamapy flamapy-fm` |
187 | | -6. Install the BDD plugin from the source code: `pip install -e bdd_metamodel` |
188 | | - |
189 | | -Please try to follow the standards code quality to contribute to this plugin before creating a Pull Request: |
190 | | - |
191 | | -- To analyze your Python code and output information about errors, potential problems, convention violations and complexity, pass the prospector with: |
192 | | - |
193 | | - `make lint` |
194 | | - |
195 | | -- To analyze the static type checker for Python and find bugs, pass the Mypy: |
196 | | - |
197 | | - `make mypy` |
198 | | - |
0 commit comments