flamapy-bdd 2.5.0.dev0__tar.gz → 2.6.0__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.
Files changed (58) hide show
  1. flamapy_bdd-2.6.0/PKG-INFO +34 -0
  2. flamapy_bdd-2.6.0/README.md +12 -0
  3. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/models/bdd_model.py +1 -1
  4. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/models/utils/pl_model.py +12 -11
  5. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_configurations_with_n_features.py +16 -0
  6. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_false_optional_features.py +6 -6
  7. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_feature_inclusion_probability.py +12 -0
  8. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_homogeneity.py +11 -0
  9. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_metrics.py +1 -1
  10. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_product_distribution.py +11 -0
  11. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_pure_optional_features.py +11 -0
  12. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_unique_features.py +10 -0
  13. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_variability.py +11 -0
  14. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_variant_features.py +11 -0
  15. flamapy_bdd-2.6.0/flamapy_bdd.egg-info/PKG-INFO +34 -0
  16. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy_bdd.egg-info/requires.txt +2 -2
  17. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/pyproject.toml +5 -5
  18. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/tests/test_bdd_metamodel.py +1 -0
  19. flamapy_bdd-2.5.0.dev0/PKG-INFO +0 -220
  20. flamapy_bdd-2.5.0.dev0/README.md +0 -198
  21. flamapy_bdd-2.5.0.dev0/flamapy_bdd.egg-info/PKG-INFO +0 -220
  22. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/LICENSE +0 -0
  23. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/__init__.py +0 -0
  24. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/models/__init__.py +0 -0
  25. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/models/utils/__init__.py +0 -0
  26. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/models/utils/txtcnf.py +0 -0
  27. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/__init__.py +0 -0
  28. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_commonality_factor.py +0 -0
  29. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_configurations.py +0 -0
  30. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_configurations_number.py +0 -0
  31. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_core_features.py +0 -0
  32. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_dead_features.py +0 -0
  33. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_sampling.py +0 -0
  34. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_satisfiable.py +0 -0
  35. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/bdd_satisfiable_configuration.py +0 -0
  36. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/__init__.py +0 -0
  37. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/commonality_factor.py +0 -0
  38. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/feature_inclusion_probability.py +0 -0
  39. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/homogeneity.py +0 -0
  40. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/product_distribution.py +0 -0
  41. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/pure_optional_features.py +0 -0
  42. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/unique_features.py +0 -0
  43. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/variability.py +0 -0
  44. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/operations/interfaces/variant_features.py +0 -0
  45. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/__init__.py +0 -0
  46. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/dddmp_reader.py +0 -0
  47. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/dddmp_writer.py +0 -0
  48. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/fm_to_bdd.py +0 -0
  49. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/json_reader.py +0 -0
  50. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/json_writer.py +0 -0
  51. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/pdf_writer.py +0 -0
  52. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/png_writer.py +0 -0
  53. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy/metamodels/bdd_metamodel/transformations/svg_writer.py +0 -0
  54. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy_bdd.egg-info/SOURCES.txt +0 -0
  55. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy_bdd.egg-info/dependency_links.txt +0 -0
  56. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/flamapy_bdd.egg-info/top_level.txt +0 -0
  57. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/setup.cfg +0 -0
  58. {flamapy_bdd-2.5.0.dev0 → flamapy_bdd-2.6.0}/setup.py +0 -0
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: flamapy-bdd
3
+ Version: 2.6.0
4
+ Summary: bdd-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/bdd_metamodel
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: flamapy-fw~=2.6.0
12
+ Requires-Dist: flamapy-fm~=2.6.0
13
+ Requires-Dist: dd~=0.6.0
14
+ Requires-Dist: graphviz~=0.20
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest; extra == "dev"
17
+ Requires-Dist: pytest-mock; extra == "dev"
18
+ Requires-Dist: prospector; extra == "dev"
19
+ Requires-Dist: mypy; extra == "dev"
20
+ Requires-Dist: coverage; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # flamapy-bdd
24
+
25
+ BDD-based analysis for [flamapy](https://flamapy.org) feature models, built on
26
+ the [dd](https://github.com/tulip-control/dd) library.
27
+
28
+ **Documentation:** https://docs.flamapy.org/framework/plugins/bdd_plugin
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install flamapy-bdd
34
+ ```
@@ -0,0 +1,12 @@
1
+ # flamapy-bdd
2
+
3
+ BDD-based analysis for [flamapy](https://flamapy.org) feature models, built on
4
+ the [dd](https://github.com/tulip-control/dd) library.
5
+
6
+ **Documentation:** https://docs.flamapy.org/framework/plugins/bdd_plugin
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pip install flamapy-bdd
12
+ ```
@@ -55,7 +55,7 @@ class BDDModel(VariabilityModel):
55
55
 
56
56
  def count_solutions(self) -> int:
57
57
  """Count the number of valid configurations (SAT)."""
58
- return self.bdd.count(self.root, len(self.vars)) # count(node, n_vars)
58
+ return self.bdd.count(self.root, len(self.vars_order)) # count(node, n_vars)
59
59
 
60
60
  def dump_structure(self) -> None:
61
61
  """Prints the structure of the BDD for debugging purposes."""
@@ -89,21 +89,20 @@ class PLModel():
89
89
  return f" {and_str} ".join(f"({f})" for f in formula)
90
90
 
91
91
  def _get_mutex_formula(self, relation: Relation) -> str:
92
- formula = []
93
- parent = relation.parent.name
94
- children = {child.name for child in relation.children}
95
92
  equiv_str = self.logic_connectives['EQUIVALENCE']
96
93
  and_str = self.logic_connectives['AND']
97
94
  not_str = self.logic_connectives['NOT']
98
95
  or_str = self.logic_connectives['OR']
96
+ parent = relation.parent.name
97
+ children = {child.name for child in relation.children}
98
+
99
+ one_child_formula = []
99
100
  for child in children:
100
- children_negatives = children - {child}
101
- neg_children = f" {and_str} ".join(not_str + cn for cn in children_negatives)
102
- formula.append(f"{child} {equiv_str} ({neg_children} {and_str} {parent})")
103
- formula_str = f" {and_str} ".join(f"({f})" for f in formula)
104
- children_or = f" {or_str} ".join(child for child in children)
105
- left = f"({parent} {equiv_str} {not_str} ({children_or}))"
106
- return f"{left} {or_str} ({formula_str})"
101
+ other_children_or = f" {or_str} ".join(c for c in children - {child})
102
+ one_child_formula.append(f"({not_str} {child} {equiv_str} ({other_children_or}))")
103
+ one_child_str = f" {and_str} ".join(f for f in one_child_formula)
104
+ no_child_str = f" {and_str} ".join(f"{not_str} {c}" for c in children)
105
+ return f"({no_child_str}) {or_str} (({one_child_str}) {and_str} {parent})"
107
106
 
108
107
  def _get_cardinality_formula(self, relation: Relation) -> str:
109
108
  parent = relation.parent.name
@@ -112,11 +111,13 @@ class PLModel():
112
111
  and_str = self.logic_connectives['AND']
113
112
  or_str = self.logic_connectives['OR']
114
113
 
114
+ card_min = relation.card_min
115
+ card_max = relation.card_max if relation.card_max != -1 else len(children)
115
116
  all_clauses = []
116
117
 
117
118
  # 1. If the parent is active, prohibit combinations outside the range [min..max]
118
119
  for val in range(len(children) + 1):
119
- if val < relation.card_min or val > relation.card_max:
120
+ if val < card_min or val > card_max:
120
121
  for combination in itertools.combinations(children, val):
121
122
  # To prohibit an exact combination: (NOT parent OR NOT child1 OR child2...)
122
123
  clause_parts = [f"{not_str}{parent}"]
@@ -2,14 +2,30 @@ from typing import cast, Any, Generator
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
4
  from flamapy.core.operations import Operation
5
+ from flamapy.core.operations.descriptor import OperationDescriptor, Input
5
6
  from flamapy.metamodels.configuration_metamodel.models import Configuration
6
7
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
7
8
  from flamapy.metamodels.bdd_metamodel.operations.bdd_product_distribution import DistributionEngine
8
9
 
9
10
 
11
+ def _configurations_with_n_features_result(result: Any) -> Any:
12
+ return list(result)
13
+
14
+
10
15
  class BDDConfigurationsWithNFeatures(Operation):
11
16
  """Operation to get all configurations with exactly n selected features from a BDD model."""
12
17
 
18
+ facade = OperationDescriptor(
19
+ doc=(
20
+ 'Returns all valid configurations that have exactly n features selected.'
21
+ ),
22
+ returns='Union[None, List[Configuration]]',
23
+ name='configurations_with_n_features', operation='BDDConfigurationsWithNFeatures',
24
+ default_backend='bdd',
25
+ inputs=(Input('n', int, required=True, setter='set_n_features'),),
26
+ result_adapter=_configurations_with_n_features_result,
27
+ )
28
+
13
29
  def __init__(self) -> None:
14
30
  self._result: Generator[Configuration, None, None]
15
31
  self.n_features: int = 0
@@ -9,7 +9,7 @@ from flamapy.metamodels.fm_metamodel.models import FeatureModel
9
9
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
10
10
 
11
11
 
12
- LOGGER = logging.getLogger('PySATFalseOptionalFeatures')
12
+ LOGGER = logging.getLogger('BDDFalseOptionalFeatures')
13
13
 
14
14
 
15
15
  class BDDFalseOptionalFeatures(FalseOptionalFeatures):
@@ -25,11 +25,11 @@ class BDDFalseOptionalFeatures(FalseOptionalFeatures):
25
25
 
26
26
  def execute(self, model: VariabilityModel) -> 'BDDFalseOptionalFeatures':
27
27
  bdd_model = cast(BDDModel, model)
28
- try:
29
- feature_model = cast(FeatureModel, model.original_model)
30
- except FlamaException:
31
- LOGGER.exception("The transformation didn't attach the source model, "
32
- "which is required for this operation.")
28
+ original_model = getattr(model, 'original_model', None)
29
+ if original_model is None:
30
+ raise FlamaException("The transformation didn't attach the source model, "
31
+ "which is required for this operation.")
32
+ feature_model = cast(FeatureModel, original_model)
33
33
  self._result = get_false_optional_features(bdd_model, feature_model)
34
34
  return self
35
35
 
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Optional, cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
5
6
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
6
7
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import FeatureInclusionProbability
@@ -14,6 +15,17 @@ class BDDFeatureInclusionProbability(FeatureInclusionProbability):
14
15
  (https://doi.org/10.1109/ICSE.2019.00091)]
15
16
  """
16
17
 
18
+ facade = OperationDescriptor(
19
+ doc=(
20
+ 'Returns a mapping from each feature name to its inclusion probability: the\n'
21
+ 'fraction of valid configurations in which that feature is selected. Core\n'
22
+ 'features have probability 1.0 and dead features have probability 0.0.'
23
+ ),
24
+ returns='Union[None, Dict[str, float]]',
25
+ name='feature_inclusion_probability', operation='BDDFeatureInclusionProbability',
26
+ default_backend='bdd',
27
+ )
28
+
17
29
  def __init__(self) -> None:
18
30
  self._result: dict[Any, float] = {}
19
31
  self._partial_configuration: Optional[Configuration] = None
@@ -1,6 +1,7 @@
1
1
  from typing import cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
5
6
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
6
7
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import Homogeneity
@@ -8,6 +9,16 @@ from flamapy.metamodels.bdd_metamodel.operations import BDDCommonalityFactor
8
9
 
9
10
 
10
11
  class BDDHomogeneity(Homogeneity):
12
+
13
+ facade = OperationDescriptor(
14
+ doc=(
15
+ 'Measures how similar the products of the feature model are to each other. It\n'
16
+ 'is computed as the average commonality factor across all features. A value of\n'
17
+ '1.0 means all products are identical; lower values indicate more diversity.'
18
+ ),
19
+ returns='Union[None, float]',
20
+ name='homogeneity', operation='BDDHomogeneity', default_backend='bdd'
21
+ )
11
22
  def __init__(self) -> None:
12
23
  self._result: float = 0.0
13
24
 
@@ -52,7 +52,7 @@ class BDDMetrics(Metrics):
52
52
  self.model = cast(BDDModel, model)
53
53
 
54
54
  # Do some basic calculations to speedup the rest
55
- self._features = list(self.model.features_variables.keys())
55
+ self._features = list(self.model.features_vars.keys())
56
56
  self._configurations_number = (
57
57
  bdd_operations.BDDConfigurationsNumber().execute(self.model).get_result()
58
58
  )
@@ -1,11 +1,22 @@
1
1
  from typing import cast, Any
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
5
6
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import ProductDistribution
6
7
 
7
8
 
8
9
  class BDDProductDistribution(ProductDistribution):
10
+
11
+ facade = OperationDescriptor(
12
+ doc=(
13
+ 'Returns the distribution of products by number of activated features. The\n'
14
+ 'value at index i is the count of valid configurations that have exactly i\n'
15
+ 'features selected.'
16
+ ),
17
+ returns='Union[None, List[int]]',
18
+ name='product_distribution', operation='BDDProductDistribution', default_backend='bdd'
19
+ )
9
20
  def __init__(self) -> None:
10
21
  self._result: list[int] = []
11
22
 
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Optional, cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
5
6
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
6
7
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import PureOptionalFeatures
@@ -8,6 +9,16 @@ from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProba
8
9
 
9
10
 
10
11
  class BDDPureOptionalFeatures(PureOptionalFeatures):
12
+
13
+ facade = OperationDescriptor(
14
+ doc=(
15
+ 'Returns features with a feature inclusion probability of exactly 0.5, meaning\n'
16
+ 'they are selected in exactly half of the valid configurations. These are the\n'
17
+ 'most unconstrained optional features.'
18
+ ),
19
+ returns='Union[None, List[str]]',
20
+ name='pure_optional_features', operation='BDDPureOptionalFeatures', default_backend='bdd'
21
+ )
11
22
  def __init__(self) -> None:
12
23
  self._result: list[Any] = []
13
24
  self._partial_configuration: Optional[Configuration] = None
@@ -1,12 +1,22 @@
1
1
  from typing import Any, Optional, cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
5
6
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
6
7
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import UniqueFeatures
7
8
 
8
9
 
9
10
  class BDDUniqueFeatures(UniqueFeatures):
11
+
12
+ facade = OperationDescriptor(
13
+ doc=(
14
+ 'Returns features that appear in exactly one valid configuration. These\n'
15
+ 'features uniquely identify a single product in the product line.'
16
+ ),
17
+ returns='Union[None, List[str]]',
18
+ name='unique_features', operation='BDDUniqueFeatures', default_backend='bdd'
19
+ )
10
20
  def __init__(self) -> None:
11
21
  self._result: list[Any] = []
12
22
  self._partial_configuration: Optional[Configuration] = None
@@ -1,12 +1,23 @@
1
1
  from typing import cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
5
6
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import Variability
6
7
  from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurationsNumber, BDDVariantFeatures
7
8
 
8
9
 
9
10
  class BDDVariability(Variability):
11
+
12
+ facade = OperationDescriptor(
13
+ doc=(
14
+ 'Returns a tuple of (total_variability, partial_variability). Total variability\n'
15
+ 'is the ratio of valid configurations to the theoretical maximum; partial\n'
16
+ 'variability is the ratio relative to only the variant features.'
17
+ ),
18
+ returns='Union[None, Tuple[float, float]]',
19
+ name='variability', operation='BDDVariability', default_backend='bdd'
20
+ )
10
21
  def __init__(self) -> None:
11
22
  self._result: tuple[float, float] = (0.0, 0.0)
12
23
 
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Optional, cast
2
2
 
3
3
  from flamapy.core.models import VariabilityModel
4
+ from flamapy.core.operations.descriptor import OperationDescriptor
4
5
  from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
5
6
  from flamapy.metamodels.bdd_metamodel.models import BDDModel
6
7
  from flamapy.metamodels.bdd_metamodel.operations.interfaces import VariantFeatures
@@ -8,6 +9,16 @@ from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProba
8
9
 
9
10
 
10
11
  class BDDVariantFeatures(VariantFeatures):
12
+
13
+ facade = OperationDescriptor(
14
+ doc=(
15
+ 'Returns the features that are neither core nor dead — they appear in some but\n'
16
+ 'not all valid configurations. These are the features that actually vary across\n'
17
+ 'products.'
18
+ ),
19
+ returns='Union[None, List[str]]',
20
+ name='variant_features', operation='BDDVariantFeatures', default_backend='bdd'
21
+ )
11
22
  def __init__(self) -> None:
12
23
  self._result: list[Any] = []
13
24
  self._partial_configuration: Optional[Configuration] = None
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: flamapy-bdd
3
+ Version: 2.6.0
4
+ Summary: bdd-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/bdd_metamodel
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: flamapy-fw~=2.6.0
12
+ Requires-Dist: flamapy-fm~=2.6.0
13
+ Requires-Dist: dd~=0.6.0
14
+ Requires-Dist: graphviz~=0.20
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest; extra == "dev"
17
+ Requires-Dist: pytest-mock; extra == "dev"
18
+ Requires-Dist: prospector; extra == "dev"
19
+ Requires-Dist: mypy; extra == "dev"
20
+ Requires-Dist: coverage; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # flamapy-bdd
24
+
25
+ BDD-based analysis for [flamapy](https://flamapy.org) feature models, built on
26
+ the [dd](https://github.com/tulip-control/dd) library.
27
+
28
+ **Documentation:** https://docs.flamapy.org/framework/plugins/bdd_plugin
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install flamapy-bdd
34
+ ```
@@ -1,5 +1,5 @@
1
- flamapy-fw~=2.5.0.dev0
2
- flamapy-fm~=2.5.0.dev0
1
+ flamapy-fw~=2.6.0
2
+ flamapy-fm~=2.6.0
3
3
  dd~=0.6.0
4
4
  graphviz~=0.20
5
5
 
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flamapy-bdd"
7
- version = "2.5.0.dev0"
7
+ version = "2.6.0"
8
8
  description = "bdd-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
- requires-python = ">=3.9"
12
+ requires-python = ">=3.11"
13
13
  dependencies = [
14
- "flamapy-fw~=2.5.0.dev0",
15
- "flamapy-fm~=2.5.0.dev0",
14
+ "flamapy-fw~=2.6.0",
15
+ "flamapy-fm~=2.6.0",
16
16
  "dd~=0.6.0",
17
17
  "graphviz~=0.20",
18
18
  ]
@@ -34,7 +34,7 @@ include = ["flamapy.*"]
34
34
 
35
35
  [tool.ruff]
36
36
  line-length = 100 # Matches max-line-length from pycodestyle
37
- target-version = "py39"
37
+ target-version = "py311"
38
38
 
39
39
  [tool.ruff.lint]
40
40
  select = ["E", "W", "F", "C", "PL", "RUF"] # Includes pycodestyle, pylint, and McCabe complexity
@@ -70,6 +70,7 @@ def test_bdd_satisfiable(path: str, expected: bool):
70
70
  ("resources/models/uvl_models/Pizzas_complex.uvl", 25),
71
71
  ("resources/models/uvl_models/Truck.uvl", 234),
72
72
  ("resources/models/uvl_models/group_cardinalities.uvl", 16),
73
+ ("resources/models/uvl_models/mutex.uvl", 6)
73
74
  # ('resources/models/uvl_models/Trimesh_NFM.uvl', 734720),
74
75
  ],
75
76
  )
@@ -1,220 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: flamapy-bdd
3
- Version: 2.5.0.dev0
4
- Summary: bdd-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/bdd_metamodel
8
- Requires-Python: >=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.5.0.dev0
12
- Requires-Dist: flamapy-fm~=2.5.0.dev0
13
- Requires-Dist: dd~=0.6.0
14
- Requires-Dist: graphviz~=0.20
15
- Provides-Extra: dev
16
- Requires-Dist: pytest; extra == "dev"
17
- Requires-Dist: pytest-mock; extra == "dev"
18
- Requires-Dist: prospector; extra == "dev"
19
- Requires-Dist: mypy; extra == "dev"
20
- Requires-Dist: coverage; extra == "dev"
21
- Dynamic: license-file
22
-
23
- # BDD plugin for flamapy
24
- - [BDD plugin for flamapy](#bdd-plugin-for-flamapy)
25
- - [Description](#description)
26
- - [Requirements and Installation](#requirements-and-installation)
27
- - [Functionality and usage](#functionality-and-usage)
28
- - [Load a feature model in UVL and create the BDD](#load-a-feature-model-in-uvl-and-create-the-bdd)
29
- - [Save the BDD in a file](#save-the-bdd-in-a-file)
30
- - [Load the BDD from a file](#load-the-bdd-from-a-file)
31
- - [Analysis operations](#analysis-operations)
32
- - [Contributing to the BDD plugin](#contributing-to-the-bdd-plugin)
33
-
34
-
35
- ## Description
36
- This plugin supports Binary Decision Diagrams (BDDs) representations for feature models.
37
-
38
- The plugin is based on [flamapy](https://github.com/flamapy/core) and thus, it follows the same architecture:
39
-
40
- <p align="center">
41
- <img width="750" src="doc/bdd_plugin.png">
42
- </p>
43
-
44
- The BDD plugin relies on the [dd](https://github.com/tulip-control/dd) library to manipulate BDDs.
45
- The complete documentation of such library is available [here](https://github.com/tulip-control/dd/blob/main/doc.md).
46
-
47
- The following is an example of feature model and its BDD using complemented arcs.
48
-
49
- <p align="center">
50
- <img width="750" src="doc/fm_example.png">
51
- </p>
52
-
53
- <p align="center">
54
- <img width="750" src="doc/bdd_example.svg">
55
- </p>
56
-
57
- ## Requirements and Installation
58
- - Python 3.9+
59
- - This plugin depends on the [flamapy core](https://github.com/flamapy/core) and on the [Feature Model plugin](https://github.com/flamapy/fm_metamodel).
60
-
61
- ```
62
- pip install flamapy flamapy-fm flamapy-bdd
63
- ```
64
-
65
- We have tested the plugin on Linux, but Windows is also supported.
66
-
67
-
68
- ## Functionality and usage
69
- 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.
70
-
71
- The following functionality is provided:
72
-
73
-
74
- ### Load a feature model in UVL and create the BDD
75
- ```python
76
- from flamapy.metamodels.fm_metamodel.transformations import UVLReader
77
- from flamapy.metamodels.bdd_metamodel.transformations import FmToBDD
78
-
79
- # Load the feature model from UVL
80
- feature_model = UVLReader('models/uvl_models/pizzas.uvl').transform()
81
- # Create the BDD from the feature model
82
- bdd_model = FmToBDD(feature_model).transform()
83
- ```
84
-
85
-
86
- ### Save the BDD in a file
87
- ```python
88
- from flamapy.metamodels.bdd_metamodel.transformations import PNGWriter, DDDMPv3Writer
89
- # Save the BDD as an image in PNG
90
- PNGWriter(path='my_bdd.png', bdd_model).transform()
91
- # Save the BDD in a .dddmp file
92
- DDDMPv3Writer(f'my_bdd.dddmp', bdd_model).transform()
93
- ```
94
- Writers available: DDDMPv3 ('dddmp'), DDDMPv2 ('dddmp'), JSON ('json'), Pickle ('p'), PDF ('pdf'), PNG ('png'), SVG ('svg').
95
-
96
- ### Load the BDD from a file
97
- ```python
98
- from flamapy.metamodels.bdd_metamodel.transformations import JSONReader
99
- # Load the BDD from a .json file
100
- bdd_model = JSONReader(path='path/to/my_bdd.json').transform()
101
- ```
102
- Readers available: JSON ('json'), DDDMP ('dddmp'), Pickle ('p').
103
-
104
- *NOTE:* DDDMP and Pickle readers are not fully supported yet.
105
-
106
- ### Analysis operations
107
-
108
- - Satisfiable
109
-
110
- Return whether the model is satisfiable (valid):
111
- ```python
112
- from flamapy.metamodels.bdd_metamodel.operations import BDDSatisfiable
113
- satisfiable = BDDSatisfiable().execute(bdd_model).get_result()
114
- print(f'Satisfiable? (valid?): {satisfiable}')
115
- ```
116
-
117
- - Configurations number
118
-
119
- Return the number of configurations:
120
- ```python
121
- from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurationsNumber
122
- n_configs = BDDConfigurationsNumber().execute(bdd_model).get_result()
123
- print(f'#Configurations: {n_configs}')
124
- ```
125
-
126
- - Configurations
127
-
128
- Enumerate the configurations of the model:
129
- ```python
130
- from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurations
131
- configurations = BDDConfigurations().execute(bdd_model).get_result()
132
- for i, config in enumerate(configurations, 1):
133
- print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}')
134
- ```
135
-
136
- - Sampling
137
-
138
- Return a sample of the given size of uniform random configurations with or without replacement:
139
- ```python
140
- from flamapy.metamodels.bdd_metamodel.operations import BDDSampling
141
- sampling_op = BDDSampling()
142
- sampling_op.set_sample_size(5)
143
- sampling_op.set_with_replacement(False) # Default False
144
- sample = sampling_op.execute(bdd_model).get_result()
145
- for i, config in enumerate(sample, 1):
146
- print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}')
147
- ```
148
-
149
- - Product Distribution
150
-
151
- Return the number of products (configurations) having a given number of features:
152
- ```python
153
- from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistribution
154
- dist = BDDProductDistribution().execute(bdd_model).get_result()
155
- print(f'Product Distribution: {dist}')
156
- ```
157
-
158
- - Feature Inclusion Probability
159
-
160
- Return the probability for a feature to be included in a valid configuration:
161
- ```python
162
- from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbability
163
- prob = BDDFeatureInclusionProbability().execute(bdd_model).get_result()
164
- for feat in prob.keys():
165
- print(f'{feat}: {prob[feat]}')
166
- ```
167
-
168
- - Core features
169
-
170
- Return the core features (those features that are present in all the configurations):
171
- ```python
172
- from flamapy.metamodels.bdd_metamodel.operations import BDDCoreFeatures
173
- core_features = BDDCoreFeatures().execute(bdd_model).get_result()
174
- print(f'Core features: {core_features}')
175
- ```
176
-
177
- - Dead features
178
-
179
- Return the dead features (those features that are not present in any configuration):
180
- ```python
181
- from flamapy.metamodels.bdd_metamodel.operations import BDDDeadFeatures
182
- dead_features = BDDDeadFeatures().execute(bdd_model).get_result()
183
- print(f'Dead features: {dead_features}')
184
- ```
185
-
186
- 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:
187
-
188
- ```python
189
- from flamapy.core.models import Configuration
190
- # Create a partial configuration
191
- elements = {'Pizza': True, 'Big': True}
192
- partial_config = Configuration(elements)
193
- # Calculate the number of configuration from the partial configuration
194
- configs_number_op = BDDConfigurationsNumber()
195
- configs_number_op.set_partial_configuration(partial_config)
196
- n_configs = configs_number_op.execute(bdd_model).get_result()
197
- print(f'#Configurations: {n_configs}')
198
- ```
199
-
200
-
201
- ## Contributing to the BDD plugin
202
- To contribute in the development of this plugin:
203
-
204
- 1. Fork the repository into your GitHub account.
205
- 2. Clone the repository: `git@github.com:<<username>>/bdd_metamodel.git`
206
- 3. Create a virtual environment: `python -m venv env`
207
- 4. Activate the virtual environment: `source env/bin/activate`
208
- 5. Install the plugin dependencies: `pip install flamapy flamapy-fm`
209
- 6. Install the BDD plugin from the source code: `pip install -e bdd_metamodel`
210
-
211
- Please try to follow the standards code quality to contribute to this plugin before creating a Pull Request:
212
-
213
- - To analyze your Python code and output information about errors, potential problems, convention violations and complexity, pass the prospector with:
214
-
215
- `make lint`
216
-
217
- - To analyze the static type checker for Python and find bugs, pass the Mypy:
218
-
219
- `make mypy`
220
-
@@ -1,198 +0,0 @@
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)
11
-
12
-
13
- ## Description
14
- This plugin supports Binary Decision Diagrams (BDDs) representations for feature models.
15
-
16
- The plugin is based on [flamapy](https://github.com/flamapy/core) and thus, it follows the same architecture:
17
-
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}')
176
- ```
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
-
@@ -1,220 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: flamapy-bdd
3
- Version: 2.5.0.dev0
4
- Summary: bdd-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/bdd_metamodel
8
- Requires-Python: >=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.5.0.dev0
12
- Requires-Dist: flamapy-fm~=2.5.0.dev0
13
- Requires-Dist: dd~=0.6.0
14
- Requires-Dist: graphviz~=0.20
15
- Provides-Extra: dev
16
- Requires-Dist: pytest; extra == "dev"
17
- Requires-Dist: pytest-mock; extra == "dev"
18
- Requires-Dist: prospector; extra == "dev"
19
- Requires-Dist: mypy; extra == "dev"
20
- Requires-Dist: coverage; extra == "dev"
21
- Dynamic: license-file
22
-
23
- # BDD plugin for flamapy
24
- - [BDD plugin for flamapy](#bdd-plugin-for-flamapy)
25
- - [Description](#description)
26
- - [Requirements and Installation](#requirements-and-installation)
27
- - [Functionality and usage](#functionality-and-usage)
28
- - [Load a feature model in UVL and create the BDD](#load-a-feature-model-in-uvl-and-create-the-bdd)
29
- - [Save the BDD in a file](#save-the-bdd-in-a-file)
30
- - [Load the BDD from a file](#load-the-bdd-from-a-file)
31
- - [Analysis operations](#analysis-operations)
32
- - [Contributing to the BDD plugin](#contributing-to-the-bdd-plugin)
33
-
34
-
35
- ## Description
36
- This plugin supports Binary Decision Diagrams (BDDs) representations for feature models.
37
-
38
- The plugin is based on [flamapy](https://github.com/flamapy/core) and thus, it follows the same architecture:
39
-
40
- <p align="center">
41
- <img width="750" src="doc/bdd_plugin.png">
42
- </p>
43
-
44
- The BDD plugin relies on the [dd](https://github.com/tulip-control/dd) library to manipulate BDDs.
45
- The complete documentation of such library is available [here](https://github.com/tulip-control/dd/blob/main/doc.md).
46
-
47
- The following is an example of feature model and its BDD using complemented arcs.
48
-
49
- <p align="center">
50
- <img width="750" src="doc/fm_example.png">
51
- </p>
52
-
53
- <p align="center">
54
- <img width="750" src="doc/bdd_example.svg">
55
- </p>
56
-
57
- ## Requirements and Installation
58
- - Python 3.9+
59
- - This plugin depends on the [flamapy core](https://github.com/flamapy/core) and on the [Feature Model plugin](https://github.com/flamapy/fm_metamodel).
60
-
61
- ```
62
- pip install flamapy flamapy-fm flamapy-bdd
63
- ```
64
-
65
- We have tested the plugin on Linux, but Windows is also supported.
66
-
67
-
68
- ## Functionality and usage
69
- 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.
70
-
71
- The following functionality is provided:
72
-
73
-
74
- ### Load a feature model in UVL and create the BDD
75
- ```python
76
- from flamapy.metamodels.fm_metamodel.transformations import UVLReader
77
- from flamapy.metamodels.bdd_metamodel.transformations import FmToBDD
78
-
79
- # Load the feature model from UVL
80
- feature_model = UVLReader('models/uvl_models/pizzas.uvl').transform()
81
- # Create the BDD from the feature model
82
- bdd_model = FmToBDD(feature_model).transform()
83
- ```
84
-
85
-
86
- ### Save the BDD in a file
87
- ```python
88
- from flamapy.metamodels.bdd_metamodel.transformations import PNGWriter, DDDMPv3Writer
89
- # Save the BDD as an image in PNG
90
- PNGWriter(path='my_bdd.png', bdd_model).transform()
91
- # Save the BDD in a .dddmp file
92
- DDDMPv3Writer(f'my_bdd.dddmp', bdd_model).transform()
93
- ```
94
- Writers available: DDDMPv3 ('dddmp'), DDDMPv2 ('dddmp'), JSON ('json'), Pickle ('p'), PDF ('pdf'), PNG ('png'), SVG ('svg').
95
-
96
- ### Load the BDD from a file
97
- ```python
98
- from flamapy.metamodels.bdd_metamodel.transformations import JSONReader
99
- # Load the BDD from a .json file
100
- bdd_model = JSONReader(path='path/to/my_bdd.json').transform()
101
- ```
102
- Readers available: JSON ('json'), DDDMP ('dddmp'), Pickle ('p').
103
-
104
- *NOTE:* DDDMP and Pickle readers are not fully supported yet.
105
-
106
- ### Analysis operations
107
-
108
- - Satisfiable
109
-
110
- Return whether the model is satisfiable (valid):
111
- ```python
112
- from flamapy.metamodels.bdd_metamodel.operations import BDDSatisfiable
113
- satisfiable = BDDSatisfiable().execute(bdd_model).get_result()
114
- print(f'Satisfiable? (valid?): {satisfiable}')
115
- ```
116
-
117
- - Configurations number
118
-
119
- Return the number of configurations:
120
- ```python
121
- from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurationsNumber
122
- n_configs = BDDConfigurationsNumber().execute(bdd_model).get_result()
123
- print(f'#Configurations: {n_configs}')
124
- ```
125
-
126
- - Configurations
127
-
128
- Enumerate the configurations of the model:
129
- ```python
130
- from flamapy.metamodels.bdd_metamodel.operations import BDDConfigurations
131
- configurations = BDDConfigurations().execute(bdd_model).get_result()
132
- for i, config in enumerate(configurations, 1):
133
- print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}')
134
- ```
135
-
136
- - Sampling
137
-
138
- Return a sample of the given size of uniform random configurations with or without replacement:
139
- ```python
140
- from flamapy.metamodels.bdd_metamodel.operations import BDDSampling
141
- sampling_op = BDDSampling()
142
- sampling_op.set_sample_size(5)
143
- sampling_op.set_with_replacement(False) # Default False
144
- sample = sampling_op.execute(bdd_model).get_result()
145
- for i, config in enumerate(sample, 1):
146
- print(f'Config {i}: {[feat for feat in config.elements if config.elements[feat]]}')
147
- ```
148
-
149
- - Product Distribution
150
-
151
- Return the number of products (configurations) having a given number of features:
152
- ```python
153
- from flamapy.metamodels.bdd_metamodel.operations import BDDProductDistribution
154
- dist = BDDProductDistribution().execute(bdd_model).get_result()
155
- print(f'Product Distribution: {dist}')
156
- ```
157
-
158
- - Feature Inclusion Probability
159
-
160
- Return the probability for a feature to be included in a valid configuration:
161
- ```python
162
- from flamapy.metamodels.bdd_metamodel.operations import BDDFeatureInclusionProbability
163
- prob = BDDFeatureInclusionProbability().execute(bdd_model).get_result()
164
- for feat in prob.keys():
165
- print(f'{feat}: {prob[feat]}')
166
- ```
167
-
168
- - Core features
169
-
170
- Return the core features (those features that are present in all the configurations):
171
- ```python
172
- from flamapy.metamodels.bdd_metamodel.operations import BDDCoreFeatures
173
- core_features = BDDCoreFeatures().execute(bdd_model).get_result()
174
- print(f'Core features: {core_features}')
175
- ```
176
-
177
- - Dead features
178
-
179
- Return the dead features (those features that are not present in any configuration):
180
- ```python
181
- from flamapy.metamodels.bdd_metamodel.operations import BDDDeadFeatures
182
- dead_features = BDDDeadFeatures().execute(bdd_model).get_result()
183
- print(f'Dead features: {dead_features}')
184
- ```
185
-
186
- 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:
187
-
188
- ```python
189
- from flamapy.core.models import Configuration
190
- # Create a partial configuration
191
- elements = {'Pizza': True, 'Big': True}
192
- partial_config = Configuration(elements)
193
- # Calculate the number of configuration from the partial configuration
194
- configs_number_op = BDDConfigurationsNumber()
195
- configs_number_op.set_partial_configuration(partial_config)
196
- n_configs = configs_number_op.execute(bdd_model).get_result()
197
- print(f'#Configurations: {n_configs}')
198
- ```
199
-
200
-
201
- ## Contributing to the BDD plugin
202
- To contribute in the development of this plugin:
203
-
204
- 1. Fork the repository into your GitHub account.
205
- 2. Clone the repository: `git@github.com:<<username>>/bdd_metamodel.git`
206
- 3. Create a virtual environment: `python -m venv env`
207
- 4. Activate the virtual environment: `source env/bin/activate`
208
- 5. Install the plugin dependencies: `pip install flamapy flamapy-fm`
209
- 6. Install the BDD plugin from the source code: `pip install -e bdd_metamodel`
210
-
211
- Please try to follow the standards code quality to contribute to this plugin before creating a Pull Request:
212
-
213
- - To analyze your Python code and output information about errors, potential problems, convention violations and complexity, pass the prospector with:
214
-
215
- `make lint`
216
-
217
- - To analyze the static type checker for Python and find bugs, pass the Mypy:
218
-
219
- `make mypy`
220
-
File without changes
File without changes
File without changes