This plugin supports Binary Decision Diagrams (BDDs) representations for feature models.
The plugin is based on flamapy and thus, it follows the same architecture:
The BDD plugin relies on the dd library to manipulate BDDs. The complete documentation of such library is available here.
The following is an example of feature model and its BDD using complemented arcs.
- Python 3.9+
- This plugin depends on the flamapy core and on the Feature Model plugin.
pip install flamapy flamapy-fm flamapy-bdd
We have tested the plugin on Linux, but Windows is also supported.
The executable script test_bdd_metamodel.py serves as an entry point to show the plugin in action.
The following functionality is provided:
from flamapy.metamodels.fm_metamodel.transformations.featureide_reader import FeatureIDEReader
from flamapy.metamodels.bdd_metamodel.transformations.fm_to_bdd import FmToBDD
# Load the feature model from FeatureIDE
feature_model = FeatureIDEReader('input_fms/featureide_models/pizzas.xml').transform()
# Create the BDD from the feature model
bdd_model = FmToBDD(feature_model).transform()
from flamapy.metamodels.bdd_metamodel.transformations.bdd_writer import BDDWriter, BDDDumpFormat
# Save the BDD as an image in PNG
BDDWriter(path='my_bdd.png',
source_model=bdd_model,
roots=[bdd_model.root],
output_format=BDDDumpFormat.PNG).transform()
Formats supported: DDDMP_V3 ('dddmp'), DDDMP_V2 ('dddmp2'), PDF ('pdf'), PNG ('png'), SVG ('svg').
-
Products number
Return the number of products (configurations):
from flamapy.metamodels.bdd_metamodel.operations import BDDProductsNumber nof_products = BDDProductsNumber().execute(bdd_model).get_result() print(f'#Products: {nof_products}')
or alternatively:
from flamapy.metamodels.bdd_metamodel.operations import products_number nof_products = products_number(bdd_model) print(f'#Products: {nof_products}')
-
Products
Return the list of products (configurations):
from flamapy.metamodels.bdd_metamodel.operations import BDDProducts list_products = BDDProducts().execute(bdd_model).get_result() for i, prod in enumerate(list_products): print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')
or alternatively:
from flamapy.metamodels.bdd_metamodel.operations import products nof_products = products(bdd_model) for i, prod in enumerate(list_products): print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')
-
Sampling
Return a sample of the given size of uniform random products (configurations) with or without replacement:
from flamapy.metamodels.bdd_metamodel.operations import BDDSampling list_sample = BDDSampling(size=5, with_replacement=False).execute(bdd_model).get_result() for i, prod in enumerate(list_sample): print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')
or alternatively:
from flamapy.metamodels.bdd_metamodel.operations import sample list_sample = sample(bdd_model, size=5, with_replacement=False) for i, prod in enumerate(list_sample): print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')
-
Product Distribution
Return the number of products having a given number of features:
from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistributionBF dist = BDDProductDistributionBF().execute(bdd_model).get_result() print(f'Product Distribution: {dist}')
or alternatively:
from flamapy.metamodels.bdd_metamodel.operations import product_distribution dist = product_distribution(bdd_model) print(f'Product Distribution: {dist}')
-
Feature Inclusion Probability
Return the probability for a feature to be included in a valid product:
from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbabilityBF prob = BDDFeatureInclusionProbabilityBF().execute(bdd_model).get_result() for feat in prob.keys(): print(f'{feat}: {prob[feat]}')
or alternatively:
from flamapy.metamodels.bdd_metamodel.operations import feature_inclusion_probability prob = feature_inclusion_probability(bdd_model) for feat in prob.keys(): print(f'{feat}: {prob[feat]}')
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:
from flamapy.core.models import Configuration
# Create a partial configuration
elements = {'Pizza': True, 'Big': True}
partial_config = Configuration(elements)
# Calculate the number of products from the partial configuration
nof_products = BDDProductsNumber(partial_config).execute(bdd_model).get_result()
print(f'#Products: {nof_products}')
or alternatively:
nof_products = products(bdd_model, partial_config)
print(f'#Products: {nof_products}')
To contribute in the development of this plugin:
- Fork the repository into your GitHub account.
- Clone the repository:
git@github.com:<<username>>/bdd_metamodel.git
- Create a virtual environment:
python -m venv env
- Activate the virtual environment:
source env/bin/activate
- Install the plugin dependencies:
pip install flamapy flamapy-fm
- Install the BDD plugin from the source code:
pip install -e bdd_metamodel
Please try to follow the standards code quality to contribute to this plugin before creating a Pull Request:
-
To analyze your Python code and output information about errors, potential problems, convention violations and complexity, pass the prospector with:
make lint
-
To analyze the static type checker for Python and find bugs, pass the Mypy:
make mypy