Source code for eclypse.placement.strategies.best_fit

"""Module for a Best Fit placement strategy.

It overrides the `place` method of the
PlacementStrategy class to place services of an application on
infrastructure nodes based on the node that best fits the requirements
of the service, i.e. the node that satisfies the requirements and has
the least amount of resources left after the placement.
"""

from __future__ import annotations

import random as rnd
from typing import (
    TYPE_CHECKING,
    Any,
)

from .strategy import PlacementStrategy

if TYPE_CHECKING:
    from eclypse.graph import (
        Application,
        Infrastructure,
    )
    from eclypse.placement import (
        Placement,
        PlacementView,
    )


[docs] class BestFitStrategy(PlacementStrategy): """BestFitStrategy class. A placement strategy that places services onto the node that best fits the requirements. """
[docs] def place( self, infrastructure: Infrastructure, application: Application, _: dict[str, Placement], placement_view: PlacementView, ) -> dict[str, str]: """Performs the placement according to a best-fit logic. Places the services of an application on the infrastructure nodes based on the node that best fits the requirements of the service. Args: infrastructure (Infrastructure): The infrastructure to place the application on. application (Application): The application to place on the infrastructure. _ (dict[str, Placement]): The placement of all the applications in the simulations. placement_view (PlacementView): The snapshot of the current state of the infrastructure. Returns: dict[str, str]: A mapping of services to infrastructure nodes. """ if not self.is_feasible(infrastructure, application): return {} mapping = {} infrastructure_nodes = list(placement_view.residual.nodes(data=True)) rnd.shuffle(infrastructure_nodes) for service, sattr in application.nodes(data=True): best_fit: str | None = None best_nattr: dict[str, Any] | None = None best_idx: int | None = None for idx, (node, nattr) in enumerate(infrastructure_nodes): if infrastructure.node_assets.satisfies(nattr, sattr) and ( best_fit is None or infrastructure.node_assets.satisfies( placement_view.residual.nodes[best_fit], nattr ) ): best_fit = node best_nattr = nattr best_idx = idx if best_fit is None or best_nattr is None or best_idx is None: continue mapping[service] = best_fit infrastructure_nodes[best_idx] = ( best_fit, infrastructure.node_assets.consume(best_nattr, sattr), ) return mapping