Skip to content

Commit

Permalink
docs: bumping to 1.6.0 dev0 before meeting. Also integrating all othe…
Browse files Browse the repository at this point in the history
…r commits from develop
  • Loading branch information
jagalindo committed Jan 8, 2024
2 parents b7d66d3 + 7f1be9e commit 26b06d2
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 4 deletions.
38 changes: 38 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"customizations": {
"codespaces": {
"repositories": {
"flamapy/fm_metamodel": {
"permissions": {
"contents": "write",
"pull_requests": "write"
}
},
"flamapy/pysat_metamodel": {
"permissions": {
"contents": "write",
"pull_requests": "write"
}
},
"flamapy/bdd_metamodel": {
"permissions": {
"contents": "write",
"pull_requests": "write"
}
},
"flamapy/afmparser": {
"permissions": {
"contents": "write",
"pull_requests": "write"
}
},
"flamapy/flamapy-fm-dist": {
"permissions": {
"contents": "write",
"pull_requests": "write"
}
}
}
}
}
}
43 changes: 41 additions & 2 deletions flamapy/core/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,54 @@ 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,
vm_orig: VariabilityModel,
plugin_name: Optional[str] = None,
configuration_file: Optional[str] = None
) -> Any:

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

if plugin_name is not None:
plugin = self.plugins.get_plugin_by_name(plugin_name)
#vm_temp = plugin.use_transformation_t2m(file)
else:
#vm_temp = self.__transform_to_model_from_file(file)
plugin = self.plugins.get_plugin_by_extension(
vm_orig.get_extension())

if operation_name not in self.get_name_operations_by_plugin(plugin.name):
transformation_way = self.__search_transformation_way(
plugin, operation_name)

for (_, dst) in transformation_way:
_plugin = self.plugins.get_plugin_by_extension(dst)
vm_temp = _plugin.use_transformation_m2m(vm_temp, dst)
plugin = _plugin

operation = plugin.get_operation(operation_name)
if isinstance(operation, OperationWithConfiguration):
if configuration_file is None:
raise ConfigurationNotFound()
configuration = self.__transform_to_model_from_file(configuration_file)
operation.set_configuration(cast(Configuration, configuration))

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 Expand Up @@ -215,7 +255,6 @@ def use_operation_from_file(
operation.set_configuration(cast(Configuration, configuration))

operation = plugin.use_operation(operation, vm_temp)

return operation.get_result()

def __transform_to_model_from_file(self, file: str) -> VariabilityModel:
Expand Down
2 changes: 2 additions & 0 deletions flamapy/core/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class FlamaException(Exception):
pass

class ParsingException(Exception):
pass

class PluginNotFound(FlamaException):
pass
Expand Down
20 changes: 20 additions & 0 deletions flamapy/core/models/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ class ASTOperation(Enum):
IMPLIES = 'IMPLIES'
NOT = 'NOT'
EQUIVALENCE = 'EQUIVALENCE'
# Comparison operators
EQUALS = 'EQUALS'
LOWER = 'LOWER'
GREATER = 'GREATER'
LOWER_EQUALS = 'LOWER_EQUALS'
GREATER_EQUALS = 'GREATER_EQUALS'
NOT_EQUALS = 'NOT_EQUALS'
# Arithmetic operators
ADD = 'ADD'
SUB = 'SUB'
MUL = 'MUL'
DIV = 'DIV'
# Aggregation operators
SUM ='SUM'
AVG = 'AVG'
# Set operators
LEN = 'LEN'
# Numeric agregation operators
FLOOR = 'FLOOR'
CEIL = 'CEIL'


class Node:
Expand Down
3 changes: 2 additions & 1 deletion flamapy/core/operations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
from .variability import Variability # pylint: disable=cyclic-import
from .sampling import Sampling # pylint: disable=cyclic-import
from .atomic_sets import AtomicSets # pylint: disable=cyclic-import
from .metrics_operation import Metrics # pylint: disable=cyclic-import

__all__ = ["Commonality", "DeadFeatures", "CoreFeatures", "FalseOptionalFeatures",
"ErrorDetection", "ErrorDiagnosis", "Operation", "Products", "Valid",
"ValidConfiguration", "ValidProduct", "Variability", "CountLeafs",
"AverageBranchingFactor", "ProductsNumber", "Filter", "Sampling",
"EstimatedProductsNumber", "AtomicSets"]
"EstimatedProductsNumber", "AtomicSets", 'Metrics']
102 changes: 102 additions & 0 deletions flamapy/core/operations/metrics_operation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from abc import abstractmethod
import logging
import json

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

from flamapy.core.exceptions import FlamaException
from flamapy.core.transformations.model_to_model import ModelToModel
from flamapy.core.operations import Operation
from flamapy.core.models import VariabilityModel

LOGGER = logging.getLogger('Metrics')


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
"""
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) -> 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 execute(self, model: VariabilityModel) -> 'Metrics':
self.model = model
#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()

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
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()
self.result.append(subclass().calculate_metamodel_metrics(dest_model))
return self

def _search_transformations(self,orig:str,dest:str) -> ModelToModel:
result=[]
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):
return m_to_m
except FlamaException("No transformation found that is required in the Metrics operation"):
LOGGER.exception("No transformation found that is required in the Metrics operation")

@staticmethod
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
@staticmethod
def get_ratio(collection1: Collection, collection2: Collection, 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]:
"""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."""

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
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",
version="1.1.3",
version="1.6.0.dev0",
author="Flamapy",
author_email="[email protected]",
description="Flamapy is a Python-based AAFM framework that takes into consideration previous AAFM tool designs and enables multi-solver and multi-metamodel support for the integration of AAFM tooling on the Python ecosystem.",
Expand Down

0 comments on commit 26b06d2

Please sign in to comment.