Skip to content

math

frequenz.core.math ¤

Math tools.

Attributes¤

frequenz.core.math.LessThanComparableOrNoneT module-attribute ¤

LessThanComparableOrNoneT = TypeVar(
    "LessThanComparableOrNoneT",
    bound=LessThanComparable | None,
)

Type variable for a value that a LessThanComparable or None.

Classes¤

frequenz.core.math.Interval dataclass ¤

Bases: Generic[LessThanComparableOrNoneT]

An interval to test if a value is within its limits.

The start and end are inclusive, meaning that the start and end limites are included in the range when checking if a value is contained by the interval.

If the start or end is None, it means that the interval is unbounded in that direction.

If start is bigger than end, a ValueError is raised.

The type stored in the interval must be comparable, meaning that it must implement the __lt__ method to be able to compare values.

Source code in frequenz/core/math.py
@dataclass(frozen=True, repr=False)
class Interval(Generic[LessThanComparableOrNoneT]):
    """An interval to test if a value is within its limits.

    The `start` and `end` are inclusive, meaning that the `start` and `end` limites are
    included in the range when checking if a value is contained by the interval.

    If the `start` or `end` is `None`, it means that the interval is unbounded in that
    direction.

    If `start` is bigger than `end`, a `ValueError` is raised.

    The type stored in the interval must be comparable, meaning that it must implement
    the `__lt__` method to be able to compare values.
    """

    start: LessThanComparableOrNoneT
    """The start of the interval."""

    end: LessThanComparableOrNoneT
    """The end of the interval."""

    def __post_init__(self) -> None:
        """Check if the start is less than or equal to the end."""
        if self.start is None or self.end is None:
            return
        start = cast(LessThanComparable, self.start)
        end = cast(LessThanComparable, self.end)
        if start > end:
            raise ValueError(
                f"The start ({self.start}) can't be bigger than end ({self.end})"
            )

    def __contains__(self, item: LessThanComparableOrNoneT) -> bool:
        """
        Check if the value is within the range of the container.

        Args:
            item: The value to check.

        Returns:
            bool: True if value is within the range, otherwise False.
        """
        if item is None:
            return False
        casted_item = cast(LessThanComparable, item)

        if self.start is None and self.end is None:
            return True
        if self.start is None:
            start = cast(LessThanComparable, self.end)
            return not casted_item > start
        if self.end is None:
            return not self.start > item
        # mypy seems to get confused here, not being able to narrow start and end to
        # just LessThanComparable, complaining with:
        #   error: Unsupported left operand type for <= (some union)
        # But we know if they are not None, they should be LessThanComparable, and
        # actually mypy is being able to figure it out in the lines above, just not in
        # this one, so it should be safe to cast.
        return not (
            casted_item < cast(LessThanComparable, self.start)
            or casted_item > cast(LessThanComparable, self.end)
        )

    def __repr__(self) -> str:
        """Return a string representation of this instance."""
        return f"Interval({self.start!r}, {self.end!r})"

    def __str__(self) -> str:
        """Return a string representation of this instance."""
        start = "∞" if self.start is None else str(self.start)
        end = "∞" if self.end is None else str(self.end)
        return f"[{start}, {end}]"
Attributes¤
end instance-attribute ¤

The end of the interval.

start instance-attribute ¤

The start of the interval.

Functions¤
__contains__ ¤
__contains__(item: LessThanComparableOrNoneT) -> bool

Check if the value is within the range of the container.

PARAMETER DESCRIPTION
item

The value to check.

TYPE: LessThanComparableOrNoneT

RETURNS DESCRIPTION
bool

True if value is within the range, otherwise False.

TYPE: bool

Source code in frequenz/core/math.py
def __contains__(self, item: LessThanComparableOrNoneT) -> bool:
    """
    Check if the value is within the range of the container.

    Args:
        item: The value to check.

    Returns:
        bool: True if value is within the range, otherwise False.
    """
    if item is None:
        return False
    casted_item = cast(LessThanComparable, item)

    if self.start is None and self.end is None:
        return True
    if self.start is None:
        start = cast(LessThanComparable, self.end)
        return not casted_item > start
    if self.end is None:
        return not self.start > item
    # mypy seems to get confused here, not being able to narrow start and end to
    # just LessThanComparable, complaining with:
    #   error: Unsupported left operand type for <= (some union)
    # But we know if they are not None, they should be LessThanComparable, and
    # actually mypy is being able to figure it out in the lines above, just not in
    # this one, so it should be safe to cast.
    return not (
        casted_item < cast(LessThanComparable, self.start)
        or casted_item > cast(LessThanComparable, self.end)
    )
__post_init__ ¤
__post_init__() -> None

Check if the start is less than or equal to the end.

Source code in frequenz/core/math.py
def __post_init__(self) -> None:
    """Check if the start is less than or equal to the end."""
    if self.start is None or self.end is None:
        return
    start = cast(LessThanComparable, self.start)
    end = cast(LessThanComparable, self.end)
    if start > end:
        raise ValueError(
            f"The start ({self.start}) can't be bigger than end ({self.end})"
        )
__repr__ ¤
__repr__() -> str

Return a string representation of this instance.

Source code in frequenz/core/math.py
def __repr__(self) -> str:
    """Return a string representation of this instance."""
    return f"Interval({self.start!r}, {self.end!r})"
__str__ ¤
__str__() -> str

Return a string representation of this instance.

Source code in frequenz/core/math.py
def __str__(self) -> str:
    """Return a string representation of this instance."""
    start = "∞" if self.start is None else str(self.start)
    end = "∞" if self.end is None else str(self.end)
    return f"[{start}, {end}]"

frequenz.core.math.LessThanComparable ¤

Bases: Protocol

A protocol that requires the __lt__ method to compare values.

Source code in frequenz/core/math.py
class LessThanComparable(Protocol):
    """A protocol that requires the `__lt__` method to compare values."""

    def __lt__(self, other: Self, /) -> bool:
        """Return whether self is less than other."""
Functions¤
__lt__ ¤
__lt__(other: Self) -> bool

Return whether self is less than other.

Source code in frequenz/core/math.py
def __lt__(self, other: Self, /) -> bool:
    """Return whether self is less than other."""

Functions¤

frequenz.core.math.is_close_to_zero ¤

is_close_to_zero(
    value: float, abs_tol: float = 1e-09
) -> bool

Check if a floating point value is close to zero.

A value of 1e-9 is a commonly used absolute tolerance to balance precision and robustness for floating-point numbers comparisons close to zero. Note that this is also the default value for the relative tolerance. For more technical details, see https://peps.python.org/pep-0485/#behavior-near-zero

PARAMETER DESCRIPTION
value

The floating point value to compare to.

TYPE: float

abs_tol

The minimum absolute tolerance. Defaults to 1e-9.

TYPE: float DEFAULT: 1e-09

RETURNS DESCRIPTION
bool

Whether the floating point value is close to zero.

Source code in frequenz/core/math.py
def is_close_to_zero(value: float, abs_tol: float = 1e-9) -> bool:
    """Check if a floating point value is close to zero.

    A value of 1e-9 is a commonly used absolute tolerance to balance precision
    and robustness for floating-point numbers comparisons close to zero. Note
    that this is also the default value for the relative tolerance.
    For more technical details, see https://peps.python.org/pep-0485/#behavior-near-zero

    Args:
        value: The floating point value to compare to.
        abs_tol: The minimum absolute tolerance. Defaults to 1e-9.

    Returns:
        Whether the floating point value is close to zero.
    """
    zero: float = 0.0
    return math.isclose(a=value, b=zero, abs_tol=abs_tol)