Source code for pumas.desirability.exponential_decay

import math
import sys
from functools import partial
from types import ModuleType
from typing import Any, Callable, Dict, Optional, Union, cast

from pumas.desirability.base_models import Desirability
from pumas.uncertainty_management.uncertainties.uncertainties_wrapper import (
    UFloat,
    umath,
)


[docs] def exponential_decay( x: Union[float, UFloat], k: float, shift: float = 0.0, math_module: ModuleType = math, ) -> Union[float, UFloat]: """ Exponential decay function: exp(-k*x) for x >= 0, clamped to 1.0 for x < 0. Args: x (Union[float, UFloat]): The input value. k (float): The decay rate parameter. shift (float, optional): The vertical shift. Defaults to 0.0. math_module (ModuleType, optional): The math module to use. It uses math for numerical computations and umath for uncertain computations. Defaults to math. Returns: Union[float, UFloat]: The result of the exponential decay function. """ if x < 0: # type: ignore result = 1.0 else: result = math_module.exp(-k * x) # type: ignore # Apply the shift result = result * (1 - shift) + shift return result
compute_numeric_exponential_decay: Callable[[float, float, float], float] = cast( Callable[[float, float, float], float], partial(exponential_decay, math_module=math), ) compute_ufloat_exponential_decay: Callable[[UFloat, float, float], UFloat] = cast( Callable[[UFloat, float, float], UFloat], partial(exponential_decay, math_module=umath), )
[docs] class ExponentialDecay(Desirability): name = "exponential_decay" """ Exponential decay desirability function implementation. Mathematical Definition: The exponential decay function is defined as: .. math:: f(x) = \\begin{cases} 1.0 & \\text{if } x < 0 \\\\ e^{-k \\cdot x} & \\text{if } x \\geq 0 \\end{cases} With optional shift transformation: .. math:: f_{final}(x) = f(x) \\cdot (1 - shift) + shift Where: * `x` is the input value. * `k` is the decay rate parameter (k > 0). Higher values result in faster decay. * `shift` is the vertical shift applied to the entire curve, ranging from 0 (no shift) to 1 (maximum shift). For x < 0, the function is "rectified" or "clamped" to 1.0, meaning full desirability. Parameters: params (Optional[Dict[str, Any]]): Initial parameters for the exponential decay function. Defaults to None. Attributes: k (float): The decay rate parameter (k > 0). Higher values result in faster decay. shift (float): The vertical shift applied to the entire curve, ranging from 0 (no shift) to 1 (maximum shift). Usage Example: >>> from pumas.desirability import desirability_catalogue >>> desirability_class = desirability_catalogue.get("exponential_decay") >>> params = {'k': 1.0, 'shift': 0.0} >>> desirability = desirability_class(params=params) >>> print(desirability.get_parameters_values()) {'k': 1.0, 'shift': 0.0} >>> result = desirability.compute_numeric(x=0.0) >>> print(f"{result:.2f}") 1.00 >>> result = desirability.compute_numeric(x=1.0) >>> print(f"{result:.2f}") 0.37 >>> result = desirability(x=-1.0) # Clamped to 1.0 >>> print(f"{result:.2f}") 1.00 >>> from uncertainties import ufloat >>> result = desirability.compute_ufloat(x=ufloat(1.0, 0.1)) >>> print(result) 0.37+/-0.04 """ def __init__(self, params: Optional[Dict[str, Any]] = None): """ Initialize the ExponentialDecay desirability function. Args: params (Optional[Dict[str, Any]]): Initial parameters for the exponential decay function. """ super().__init__() self._set_parameter_definitions( { "k": { "type": "float", "min": sys.float_info.epsilon, "max": float("inf"), "default": 1.0, }, "shift": { "type": "float", "min": 0.0, "max": 1.0, "default": 0.0, }, } ) self._validate_and_set_parameters(params)
[docs] def compute_numeric(self, x: Union[int, float]) -> float: """ Compute the exponential decay desirability for a numeric input. Args: x (Union[int, float]): The numeric input value. Returns: float: The computed desirability value. Raises: InvalidParameterTypeError: If the input is not a float. ParameterValueNotSet: If any required parameter is not set. """ self._validate_compute_input(item=x, expected_type=(int, float)) self._check_parameters_values_none() parameters = self.get_parameters_values() return compute_numeric_exponential_decay(x=x, **parameters) # type: ignore
[docs] def compute_ufloat(self, x: UFloat) -> UFloat: """ Compute the exponential decay desirability for an uncertain float input. Args: x (UFloat): The uncertain float input value. Returns: UFloat: The computed desirability value with uncertainty. Raises: InvalidParameterTypeError: If the input is not a UFloat. ParameterValueNotSet: If any required parameter is not set. """ self._validate_compute_input(x, UFloat) self._check_parameters_values_none() parameters = self.get_parameters_values() return compute_ufloat_exponential_decay(x=x, **parameters) # type: ignore
__call__ = compute_numeric