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

Pass prospector and fix sampling and product interfaces #119

Merged
merged 2 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
5 changes: 2 additions & 3 deletions flamapy/core/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ def use_operation(self, src: VariabilityModel, operation_name: str) -> Operation
operation = plugin.get_operation(operation_name)
return plugin.use_operation(operation, src)


def use_operation_from_vm(
self,
operation_name: str,
Expand Down Expand Up @@ -218,15 +217,15 @@ def use_operation_from_vm(
operation = plugin.use_operation(operation, vm_temp)

return operation.get_result()

def use_operation_from_file(
self,
operation_name: str,
file: str,
plugin_name: Optional[str] = None,
configuration_file: Optional[str] = None
) -> Any:

if operation_name not in self.get_name_operations():
raise OperationNotFound()

Expand Down
4 changes: 3 additions & 1 deletion flamapy/core/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
class FlamaException(Exception):
pass


class ParsingException(Exception):
pass


class PluginNotFound(FlamaException):
pass

Expand All @@ -25,4 +27,4 @@ class DuplicatedFeature(FlamaException):


class ConfigurationNotFound(FlamaException):
pass
pass
4 changes: 2 additions & 2 deletions flamapy/core/models/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ASTOperation(Enum):
EQUALS = 'EQUALS'
LOWER = 'LOWER'
GREATER = 'GREATER'
LOWER_EQUALS = 'LOWER_EQUALS'
LOWER_EQUALS = 'LOWER_EQUALS'
GREATER_EQUALS = 'GREATER_EQUALS'
NOT_EQUALS = 'NOT_EQUALS'
# Arithmetic operators
Expand All @@ -24,7 +24,7 @@ class ASTOperation(Enum):
MUL = 'MUL'
DIV = 'DIV'
# Aggregation operators
SUM ='SUM'
SUM = 'SUM'
AVG = 'AVG'
# Set operators
LEN = 'LEN'
Expand Down
1 change: 1 addition & 0 deletions flamapy/core/models/variability_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ def get_extension() -> str:


class VariabilityElement():

def __init__(self, name: str) -> None:
self.name = name
94 changes: 47 additions & 47 deletions flamapy/core/operations/metrics_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import json

from typing import Any, Callable,List, Tuple, Union, Optional, Collection, Dict
from typing import Any, Optional, Collection

from flamapy.core.exceptions import FlamaException
from flamapy.core.transformations.model_to_model import ModelToModel
Expand All @@ -13,93 +13,93 @@


class Metrics(Operation):
"""This is intended to host a set of metrics calculations for a variability model. This abstract class will recruit all its implementations and agregate the results
"""This is intended to host a set of metrics calculations for a variability model.

This abstract class will recruit all its implementations and agregate the results
"""
filter: Optional[List[str]] = None
result: List[Dict[str, Any]] = []
filter: Optional[list[str]] = None
result: list[dict[str, Any]] = []

def __init__(self) -> None:
self.model: Optional[VariabilityModel] = None

@abstractmethod
def calculate_metamodel_metrics(
self,
model: VariabilityModel,
) -> List[Dict[str, Any]]:
"""Return a list of metrics for each metamodel"""
def calculate_metamodel_metrics(self, model: VariabilityModel) -> list[dict[str, Any]]:
"""Return a list of metrics for each metamodel."""

def only_these_metrics(self, filter: List[str]) -> None:
self.filter = filter
def only_these_metrics(self, filter_metrics: list[str]) -> None:
self.filter = filter_metrics

def execute(self, model: VariabilityModel) -> 'Metrics':
self.model = model
#Identifying all implementations of MetricsOperation
# Identifying all implementations of MetricsOperation

for subclass in Metrics.__subclasses__():
#We first have to identify the metamodels that are being used and transform this model to the correspointing metamodel
metrics_operation=subclass()

# We first have to identify the metamodels that are being used and
# transform this model to the correspointing metamodel
metrics_operation = subclass()

if self.model.__class__.get_extension() == metrics_operation.model_type_extension:
#if its the metamodel that math the model, calculate the metrics
#Then we calculate the metrics for each metamodel
# If its the metamodel that math the model, calculate the metrics
# Then we calculate the metrics for each metamodel
self.result.append(subclass().calculate_metamodel_metrics(model))
else:
#if not, search a transformation, transform and call the calutation
m_to_m=self._search_transformations(self.model.__class__.get_extension(),metrics_operation.model_type_extension)
dest_model=m_to_m(self.model).transform()
# If not, search a transformation, transform and call the calutation
m_to_m = self._search_transformations(self.model.__class__.get_extension(),
metrics_operation.model_type_extension)
dest_model = m_to_m(self.model).transform()
self.result.append(subclass().calculate_metamodel_metrics(dest_model))
return self

def _search_transformations(self,orig:str,dest:str) -> ModelToModel:
result=[]

def _search_transformations(self, orig: str, dest: str) -> ModelToModel:
try:
for m_to_m in ModelToModel.__subclasses__():
_orig = m_to_m.get_source_extension()
_dest = m_to_m.get_destination_extension()
if (_orig==orig and _dest==dest):
if (_orig == orig and _dest == dest):
return m_to_m
except FlamaException("No transformation found that is required in the Metrics operation"):
except FlamaException:
LOGGER.exception("No transformation found that is required in the Metrics operation")
raise FlamaException("No transformation found")

@staticmethod
def get_result(self) -> List[Dict[str, Any]]:
def get_result(self) -> list[dict[str, Any]]:
return self.result
def get_result_json(self):
json_object = json.dumps(self.get_result(), indent = 4)
return json_object

def get_result_json(self) -> str:
return json.dumps(self.get_result(), indent=4)

@staticmethod
def get_ratio(collection1: Collection, collection2: Collection, precision: int = 4) -> float:
def get_ratio(collection1: Collection[Any],
collection2: Collection[Any],
precision: int = 4) -> float:
if not collection1 and not collection2:
# Handle case where both collections are empty
return 0.0
if not collection2:
return 0.0
return float(round(len(collection1) / len(collection2), precision))

@staticmethod
def construct_result(
name: Optional[str] = None,
doc: Optional[str] = None,
result: Optional[Any] = None,
size: Optional[int] = None,
ratio: Optional[float] = None
) -> Dict[str, Any]:
def construct_result(name: Optional[str] = None,
doc: Optional[str] = None,
result: Optional[Any] = None,
size: Optional[int] = None,
ratio: Optional[float] = None
) -> dict[str, Any]:
"""Constructs a dictionary with named keys from the provided list and other arguments.

property name: The property name.
description: The description of the property
value (optional): the list of abstract features.
size (optional): the length of the list.
ratio (optional): the percentage of abstract features with regards the total number of features."""

ratio (optional): the percentage of abstract features with regards the total number
of features.
"""

return {
"name": name or "Default Name", # Using a default value if name is None
"documentation": doc or "Default Documentation",
"result": result or [],
"size": size or 0,
"ratio": ratio or 0.0
}

@staticmethod
def only_these_metrics(self, filter: List[str]) -> None:
self.filter = filter
4 changes: 2 additions & 2 deletions flamapy/core/operations/products.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import abstractmethod
from typing import Any

from flamapy.core.operations import Operation
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration


class Products(Operation):
Expand All @@ -11,5 +11,5 @@ def __init__(self) -> None:
pass

@abstractmethod
def get_products(self) -> list[Any]:
def get_products(self) -> list[Configuration]:
pass
28 changes: 18 additions & 10 deletions flamapy/core/operations/sampling.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from abc import abstractmethod
from typing import Optional

from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
from flamapy.core.operations import Operation
Expand All @@ -11,12 +10,21 @@ class Sampling(Operation):
"""

@abstractmethod
def sample(self, size: int, with_replacement: bool = False,
partial_configuration: Optional[Configuration] = None) -> list[Configuration]:
"""Return a sample of configurations.

Keyword arguments:
size -- number of configurations of the sample.
with_replacement -- allow repeated configurations in the sample (default False).
partial_configuration -- from which the sample is built (default empty configuration).
"""
def __init__(self) -> None:
pass

@abstractmethod
def set_sample_size(self, sample_size: int) -> None:
"""Number of configurations of the sample."""

@abstractmethod
def set_with_replacement(self, with_replacement: bool) -> None:
"Allow repeated configurations in the sample (default False)."

@abstractmethod
def set_partial_configuration(self, partial_configuration: Configuration) -> None:
"From which the sample is built (default empty configuration)."

@abstractmethod
def get_sample(self) -> list[Configuration]:
"""Return a sample of configurations."""
Loading