|
3 | 3 | - [Description](#description) |
4 | 4 | - [Requirements and Installation](#requirements-and-installation) |
5 | 5 | - [Functionality and usage](#functionality-and-usage) |
6 | | - - [Load a feature model and create the BDD](#load-a-feature-model-and-create-the-bdd) |
| 6 | + - [Load a feature model in UVL and create the BDD](#load-a-feature-model-in-uvl-and-create-the-bdd) |
7 | 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) |
8 | 9 | - [Analysis operations](#analysis-operations) |
9 | 10 | - [Contributing to the BDD plugin](#contributing-to-the-bdd-plugin) |
10 | 11 |
|
@@ -48,128 +49,130 @@ The executable script [test_bdd_metamodel.py](https://github.com/flamapy/bdd_met |
48 | 49 | The following functionality is provided: |
49 | 50 |
|
50 | 51 |
|
51 | | -### Load a feature model and create the BDD |
| 52 | +### Load a feature model in UVL and create the BDD |
52 | 53 | ```python |
53 | | -from flamapy.metamodels.fm_metamodel.transformations.featureide_reader import FeatureIDEReader |
54 | | -from flamapy.metamodels.bdd_metamodel.transformations.fm_to_bdd import FmToBDD |
| 54 | +from flamapy.metamodels.fm_metamodel.transformations import UVLReader |
| 55 | +from flamapy.metamodels.bdd_metamodel.transformations import FmToBDD |
55 | 56 |
|
56 | | -# Load the feature model from FeatureIDE |
57 | | -feature_model = FeatureIDEReader('input_fms/featureide_models/pizzas.xml').transform() |
| 57 | +# Load the feature model from UVL |
| 58 | +feature_model = UVLReader('models/uvl_models/pizzas.uvl').transform() |
58 | 59 | # Create the BDD from the feature model |
59 | 60 | bdd_model = FmToBDD(feature_model).transform() |
60 | 61 | ``` |
61 | 62 |
|
62 | 63 |
|
63 | 64 | ### Save the BDD in a file |
64 | 65 | ```python |
65 | | -from flamapy.metamodels.bdd_metamodel.transformations.bdd_writer import BDDWriter, BDDDumpFormat |
| 66 | +from flamapy.metamodels.bdd_metamodel.transformations import PNGWriter, DDDMPv3Writer |
66 | 67 | # Save the BDD as an image in PNG |
67 | | -BDDWriter(path='my_bdd.png', |
68 | | - source_model=bdd_model, |
69 | | - roots=[bdd_model.root], |
70 | | - output_format=BDDDumpFormat.PNG).transform() |
| 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 | 71 | ``` |
72 | | -Formats supported: DDDMP_V3 ('dddmp'), DDDMP_V2 ('dddmp2'), PDF ('pdf'), PNG ('png'), SVG ('svg'). |
| 72 | +Writers available: DDDMPv3 ('dddmp'), DDDMPv2 ('dddmp'), JSON ('json'), Pickle ('p'), PDF ('pdf'), PNG ('png'), SVG ('svg'). |
73 | 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. |
74 | 83 |
|
75 | 84 | ### Analysis operations |
76 | 85 |
|
77 | | -- Products number |
| 86 | +- Satisfiable |
78 | 87 |
|
79 | | - Return the number of products (configurations): |
| 88 | + Return whether the model is satisfiable (valid): |
80 | 89 | ```python |
81 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDProductsNumber |
82 | | - nof_products = BDDProductsNumber().execute(bdd_model).get_result() |
83 | | - print(f'#Products: {nof_products}') |
84 | | - ``` |
85 | | - or alternatively: |
86 | | - ```python |
87 | | - from flamapy.metamodels.bdd_metamodel.operations import products_number |
88 | | - nof_products = products_number(bdd_model) |
89 | | - print(f'#Products: {nof_products}') |
| 90 | + from flamapy.metamodels.bdd_metamodel.operations import BDDSatisfiable |
| 91 | + satisfiable = BDDSatisfiable().execute(bdd_model).get_result() |
| 92 | + print(f'Satisfiable? (valid?): {satisfiable}') |
90 | 93 | ``` |
91 | 94 |
|
92 | | -- Products |
| 95 | +- Configurations number |
93 | 96 |
|
94 | | - Return the list of products (configurations): |
| 97 | + Return the number of configurations: |
95 | 98 | ```python |
96 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDProducts |
97 | | - list_products = BDDProducts().execute(bdd_model).get_result() |
98 | | - for i, prod in enumerate(list_products): |
99 | | - print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}') |
| 99 | + from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurationsNumber |
| 100 | + n_configs = BDDConfigurationsNumber().execute(bdd_model).get_result() |
| 101 | + print(f'#Configurations: {n_configs}') |
100 | 102 | ``` |
101 | | - or alternatively: |
| 103 | + |
| 104 | +- Configurations |
| 105 | + |
| 106 | + Enumerate the configurations of the model: |
102 | 107 | ```python |
103 | | - from flamapy.metamodels.bdd_metamodel.operations import products |
104 | | - nof_products = products(bdd_model) |
105 | | - for i, prod in enumerate(list_products): |
106 | | - print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}') |
| 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]]}') |
107 | 112 | ``` |
108 | 113 |
|
109 | 114 | - Sampling |
110 | 115 |
|
111 | | - Return a sample of the given size of uniform random products (configurations) with or without replacement: |
| 116 | + Return a sample of the given size of uniform random configurations with or without replacement: |
112 | 117 | ```python |
113 | 118 | from flamapy.metamodels.bdd_metamodel.operations import BDDSampling |
114 | | - list_sample = BDDSampling(size=5, with_replacement=False).execute(bdd_model).get_result() |
115 | | - for i, prod in enumerate(list_sample): |
116 | | - print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}') |
117 | | - ``` |
118 | | - or alternatively: |
119 | | - ```python |
120 | | - from flamapy.metamodels.bdd_metamodel.operations import sample |
121 | | - list_sample = sample(bdd_model, size=5, with_replacement=False) |
122 | | - for i, prod in enumerate(list_sample): |
123 | | - print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}') |
| 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]]}') |
124 | 125 | ``` |
125 | 126 |
|
126 | 127 | - Product Distribution |
127 | 128 |
|
128 | | - Return the number of products having a given number of features: |
129 | | - ```python |
130 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistributionBF |
131 | | - dist = BDDProductDistributionBF().execute(bdd_model).get_result() |
132 | | - print(f'Product Distribution: {dist}') |
133 | | - ``` |
134 | | - or alternatively: |
| 129 | + Return the number of products (configurations) having a given number of features: |
135 | 130 | ```python |
136 | | - from flamapy.metamodels.bdd_metamodel.operations import product_distribution |
137 | | - dist = product_distribution(bdd_model) |
| 131 | + from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistribution |
| 132 | + dist = BDDProductDistribution().execute(bdd_model).get_result() |
138 | 133 | print(f'Product Distribution: {dist}') |
139 | 134 | ``` |
140 | 135 |
|
141 | 136 | - Feature Inclusion Probability |
142 | 137 |
|
143 | | - Return the probability for a feature to be included in a valid product: |
| 138 | + Return the probability for a feature to be included in a valid configuration: |
144 | 139 | ```python |
145 | | - from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbabilityBF |
146 | | - prob = BDDFeatureInclusionProbabilityBF().execute(bdd_model).get_result() |
| 140 | + from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbability |
| 141 | + prob = BDDFeatureInclusionProbability().execute(bdd_model).get_result() |
147 | 142 | for feat in prob.keys(): |
148 | 143 | print(f'{feat}: {prob[feat]}') |
149 | 144 | ``` |
150 | | - or alternatively: |
| 145 | + |
| 146 | +- Core features |
| 147 | + |
| 148 | + Return the core features (those features that are present in all the configurations): |
151 | 149 | ```python |
152 | | - from flamapy.metamodels.bdd_metamodel.operations import feature_inclusion_probability |
153 | | - prob = feature_inclusion_probability(bdd_model) |
154 | | - for feat in prob.keys(): |
155 | | - print(f'{feat}: {prob[feat]}') |
| 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}') |
156 | 153 | ``` |
157 | 154 |
|
158 | | -All 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: |
| 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: |
159 | 165 |
|
160 | 166 | ```python |
161 | 167 | from flamapy.core.models import Configuration |
162 | 168 | # Create a partial configuration |
163 | 169 | elements = {'Pizza': True, 'Big': True} |
164 | 170 | partial_config = Configuration(elements) |
165 | | -# Calculate the number of products from the partial configuration |
166 | | -nof_products = BDDProductsNumber(partial_config).execute(bdd_model).get_result() |
167 | | -print(f'#Products: {nof_products}') |
168 | | -``` |
169 | | -or alternatively: |
170 | | -```python |
171 | | -nof_products = products(bdd_model, partial_config) |
172 | | -print(f'#Products: {nof_products}') |
| 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}') |
173 | 176 | ``` |
174 | 177 |
|
175 | 178 |
|
|
0 commit comments