Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update BDD plugin #30

Merged
merged 5 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Optional
from typing import Any, Optional, cast

from flamapy.core.models import VariabilityModel
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration

from flamapy.metamodels.bdd_metamodel.models import BDDModel
from flamapy.metamodels.bdd_metamodel.operations.interfaces import FeatureInclusionProbability
from flamapy.metamodels.bdd_metamodel.operations import BDDProducts
Expand All @@ -19,24 +19,23 @@ class BDDFeatureInclusionProbability(FeatureInclusionProbability):
"""

def __init__(self, partial_configuration: Optional[Configuration] = None) -> None:
self.bdd_model = None
self.result: dict[str, float] = {}
self.result: dict[Any, float] = {}
self.partial_configuration = partial_configuration

def execute(self, model: BDDModel) -> 'BDDFeatureInclusionProbability':
self.bdd_model = model
self.result = feature_inclusion_probability(self.bdd_model, self.partial_configuration)
def execute(self, model: VariabilityModel) -> 'BDDFeatureInclusionProbability':
bdd_model = cast(BDDModel, model)
self.result = feature_inclusion_probability(bdd_model, self.partial_configuration)
return self

def get_result(self) -> dict[str, float]:
def get_result(self) -> dict[Any, float]:
return self.result

def feature_inclusion_probability(self) -> dict[str, float]:
return feature_inclusion_probability(self.bdd_model, self.partial_configuration)
def feature_inclusion_probability(self) -> dict[Any, float]:
return self.get_result()


def feature_inclusion_probability(bdd_model: BDDModel,
config: Optional[Configuration] = None) -> dict[str, float]:
config: Optional[Configuration] = None) -> dict[Any, float]:
products = BDDProducts(config).execute(bdd_model).get_result()
n_products = len(products)
if n_products == 0:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import math
from collections import defaultdict
from typing import cast

from dd.autoref import Function

from flamapy.core.models import VariabilityModel
from flamapy.metamodels.bdd_metamodel.models import BDDModel
from flamapy.metamodels.bdd_metamodel.operations.interfaces import ProductDistribution

Expand All @@ -11,18 +13,17 @@ class BDDProductDistribution(ProductDistribution):

def __init__(self) -> None:
self.result: list[int] = []
self.bdd_model = None

def execute(self, model: BDDModel) -> 'BDDProductDistribution':
self.bdd_model = model
self.result = product_distribution(self.bdd_model)
def execute(self, model: VariabilityModel) -> 'BDDProductDistribution':
bdd_model = cast(BDDModel, model)
self.result = product_distribution(bdd_model)
return self

def get_result(self) -> list[int]:
return self.result

def product_distribution(self) -> list[int]:
return product_distribution(self.bdd_model)
return self.get_result()


def product_distribution(bdd_model: BDDModel) -> list[int]:
Expand Down Expand Up @@ -113,4 +114,4 @@ def combine_distributions(id_node: int,
node_dist[i] = value
for i, value in enumerate(high_dist):
node_dist[i + 1] = node_dist[i + 1] + value
dist[id_node] = node_dist
dist[id_node] = node_dist
16 changes: 8 additions & 8 deletions flamapy/metamodels/bdd_metamodel/operations/bdd_products.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional
from typing import Optional, cast

from flamapy.core.models import VariabilityModel
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
from flamapy.core.operations import Products
from flamapy.metamodels.bdd_metamodel.models.bdd_model import BDDModel
Expand All @@ -13,31 +14,30 @@ class BDDProducts(Products):

def __init__(self, partial_configuration: Optional[Configuration] = None) -> None:
self.result: list[Configuration] = []
self.bdd_model = None
self.partial_configuration = partial_configuration

def execute(self, model: BDDModel) -> 'BDDProducts':
self.bdd_model = model
self.result = products(self.bdd_model, self.partial_configuration)
def execute(self, model: VariabilityModel) -> 'BDDProducts':
bdd_model = cast(BDDModel, model)
self.result = products(bdd_model, self.partial_configuration)
return self

def get_result(self) -> list[Configuration]:
return self.result

def get_products(self) -> list[Configuration]:
return products(self.bdd_model, self.partial_configuration)
return self.get_result()


def products(bdd_model: BDDModel,
partial_config: Optional[Configuration] = None) -> list[Configuration]:
if partial_config is None:
u_func = bdd_model.root
care_vars = bdd_model.variables
care_vars = set(bdd_model.variables)
elements = {}
else:
values = dict(partial_config.elements.items())
u_func = bdd_model.bdd.let(values, bdd_model.root)
care_vars = set(bdd_model.variables) - values.keys()
care_vars = set(bdd_model.variables) - set(values.keys())
elements = partial_config.elements

configs = []
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional
from typing import Optional, cast

from flamapy.core.models import VariabilityModel
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
from flamapy.core.operations import ProductsNumber
from flamapy.metamodels.bdd_metamodel.models.bdd_model import BDDModel
Expand All @@ -13,20 +14,18 @@ class BDDProductsNumber(ProductsNumber):

def __init__(self, partial_configuration: Optional[Configuration] = None) -> None:
self.result = 0
self.bdd_model = None
self.feature_model = None
self.partial_configuration = partial_configuration

def execute(self, model: BDDModel) -> 'BDDProductsNumber':
self.bdd_model = model
self.result = products_number(self.bdd_model, self.partial_configuration)
def execute(self, model: VariabilityModel) -> 'BDDProductsNumber':
bdd_model = cast(BDDModel, model)
self.result = products_number(bdd_model, self.partial_configuration)
return self

def get_result(self) -> int:
return self.result

def get_products_number(self) -> int:
return products_number(self.bdd_model, self.partial_configuration)
return self.get_result()


def products_number(bdd_model: BDDModel,
Expand Down
61 changes: 35 additions & 26 deletions flamapy/metamodels/bdd_metamodel/operations/bdd_sampling.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import random
from typing import Optional
from typing import Optional, cast

from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
from flamapy.core.models import VariabilityModel
from flamapy.core.exceptions import FlamaException
from flamapy.core.operations import Sampling

from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
from flamapy.metamodels.bdd_metamodel.models import BDDModel
from flamapy.metamodels.bdd_metamodel.operations import BDDProductsNumber


class BDDSampling(Sampling):
Expand All @@ -21,43 +21,52 @@ class BDDSampling(Sampling):
as well as samples from a given partial configuration.
"""

def __init__(self, size: int, with_replacement: bool = False,
partial_configuration: Optional[Configuration] = None) -> None:
def __init__(self) -> None:
self.result: list[Configuration] = []
self.bdd_model = None
self.size = size
self.sample_size: int = 0
self.with_replacement: bool = False
self.partial_configuration: Optional[Configuration] = None

def set_sample_size(self, sample_size: int) -> None:
if sample_size < 0:
raise FlamaException(f'Sample size {sample_size} cannot be negative.')
self.sample_size = sample_size

def set_with_replacement(self, with_replacement: bool) -> None:
self.with_replacement = with_replacement

def set_partial_configuration(self, partial_configuration: Configuration) -> None:
self.partial_configuration = partial_configuration

def execute(self, model: BDDModel) -> 'BDDSampling':
self.bdd_model = model
self.result = sample(self.bdd_model, self.size, self.with_replacement,
self.partial_configuration)
return self
def get_sample(self) -> list[Configuration]:
return self.get_result()

def get_result(self) -> list[Configuration]:
return self.result

def sample(self, size: int, with_replacement: bool = False,
partial_configuration: Optional[Configuration] = None) -> list[Configuration]:
return sample(self.bdd_model, size, with_replacement, partial_configuration)

def execute(self, model: VariabilityModel) -> 'BDDSampling':
bdd_model = cast(BDDModel, model)
self.result = sample(bdd_model,
self.sample_size,
self.with_replacement,
self.partial_configuration)
return self

def sample(bdd_model: BDDModel, size: int, with_replacement: bool = False,
partial_configuration: Optional[Configuration] = None) -> list[Configuration]:
nof_configs = BDDProductsNumber(partial_configuration).execute(bdd_model).get_result()
if size < 0 or (size > nof_configs and not with_replacement):
raise ValueError('Sample larger than population or is negative.')

def sample(model: BDDModel,
sample_size: int,
with_replacement: bool,
partial_configuration: Optional[Configuration]
) -> list[Configuration]:
configurations = []
for _ in range(size):
config = random_configuration(bdd_model, partial_configuration)
for _ in range(sample_size):
config = random_configuration(model, partial_configuration)
configurations.append(config)

if not with_replacement:
set_configurations = set(configurations)
while len(set_configurations) < size:
config = random_configuration(bdd_model, partial_configuration)
while len(set_configurations) < sample_size:
config = random_configuration(model, partial_configuration)
set_configurations.add(config)

return list(set_configurations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ def transform(self) -> BDDModel:
)

cnf_formula = and_connective.join(cnf_list)
self.destination_model.from_textual_cnf(
cnf_formula, list(self.source_model.variables.keys())
)
self.destination_model.from_textual_cnf(cnf_formula,
list(self.source_model.variables.keys()))

return self.destination_model
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setuptools.setup(
name="flamapy-bdd",
version="1.0.1",
version="1.6.0",
author="Flamapy",
author_email="flamapy@us.es",
description="bdd-plugin for the automated analysis of feature models",
Expand Down
10 changes: 6 additions & 4 deletions tests/test_bdd_metamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_main():
# Create the BDD from the FM
bdd_model = FmToBDD(feature_model).transform()

# # Save the BDD as a .png
# Save the BDD as a .png
bdd_writer = BDDWriter(bdd_model.root.var + '.png', bdd_model)
bdd_writer.set_format(BDDDumpFormat.SVG)
bdd_writer.set_roots([bdd_model.root])
Expand All @@ -32,7 +32,7 @@ def test_main():

# BDD products operation
products = BDDProducts().execute(bdd_model).get_result()
for i, prod in enumerate(products):
for i, prod in enumerate(products, 1):
print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')

assert len(products) == nof_products
Expand All @@ -50,9 +50,11 @@ def test_main():
print(f'{feat}: {prob[feat]}')

# BDD Sampling
sample = BDDSampling(size=5, with_replacement=False).execute(bdd_model).get_result()
sample_op = BDDSampling()
sample_op.set_sample_size(5)
sample = sample_op.execute(bdd_model).get_result()
print('Uniform Random Sampling:')
for i, prod in enumerate(sample):
for i, prod in enumerate(sample, 1):
print(f'Product {i}: {[feat for feat in prod.elements if prod.elements[feat]]}')


Expand Down
Loading