Module FuzzyMath.class_factories

Factory classes

Expand source code
"""Factory classes"""
import re
from abc import ABC
from decimal import Decimal, InvalidOperation
from typing import List, Optional, Union

from .class_fuzzy_number import FuzzyNumber
from .class_interval import Interval


class FactoryBase(ABC):
    """Base class for factories"""

    @staticmethod
    def validate_variable(variable: Union[float, int, str, Decimal], variable_name: str) -> Decimal:
        """Checks that input variable can be converted to valid Decimal.

        Args:
            variable (Union[float, int, str, Decimal]): value to convert to Decimal.
            variable_name (str): name of variable for error message.

        Raises:
            InvalidOperation: if variable cannot be converted to Decimal.

        Returns:
            Decimal
        """
        try:
            var = Decimal(variable)
        except InvalidOperation as e:
            raise InvalidOperation(f"Cannot convert `{variable_name}` value ({variable}) to number.") from e
        return var

    @staticmethod
    def validate_alphas(alphas: List[Union[str, int, float, Decimal]], variable_name: str = "alphas") -> List[Decimal]:
        """Validate that all alphas are valid alpha values and converts them to Decimals.

        Args:
            alphas (List[Union[str, int, float, Decimal]]): List of alpha cut values.
            variable_name (str, optional): Name of variable for error message. Defaults to "alphas".

        Raises:
            InvalidOperation: If any alphas value cannot be converted to Decimal.

        Returns:
            List[Decimal]
        """
        decimal_alphas = []
        for alpha in alphas:
            try:
                decimal_alphas.append(Decimal(alpha))
            except InvalidOperation as e:
                raise InvalidOperation(f"Cannot convert `{variable_name}` value ({alpha}) to number.") from e
        return decimal_alphas


class FuzzyNumberFactory(FactoryBase):
    """
    Class that supports creation of fuzzy numbers based on different functions. All the functions are static.
    """

    @staticmethod
    def triangular(
        minimum: Union[str, int, float, Decimal],
        kernel: Union[str, int, float, Decimal],
        maximum: Union[str, int, float, Decimal],
        number_of_cuts: Optional[int] = None,
    ) -> FuzzyNumber:
        """
        Creates triangular `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]
            Minimal value of fuzzy number.

        kernel: Union[str, int, float, Decimal]
            Kernel (midpoint) value of fuzzy number.

        maximum: Union[str, int, float, Decimal]
            Maximal value of fuzzy number.

        number_of_cuts: int
            Number of alpha cuts.

        Returns
        -------
        FuzzyNumber
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
        kernel = FuzzyNumberFactory.validate_variable(kernel, "kernel")

        if not minimum <= kernel <= maximum:
            raise ValueError(
                "The fuzzy number is invalid. The structure needs to be `minimum` <= `kernel` "
                f"<= `maximum`. Currently it is `{minimum}` <= `{kernel}` <= `{maximum}`, which does not hold."
            )

        if number_of_cuts is None or number_of_cuts <= 2:
            return FuzzyNumber(
                alphas=[Decimal(0), Decimal(1)],
                alpha_cuts=[
                    IntervalFactory.infimum_supremum(minimum, maximum),
                    IntervalFactory.infimum_supremum(kernel, kernel),
                ],
            )

        else:
            alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

            intervals = [IntervalFactory.empty()] * len(alphas)

            i = 0
            for alpha in alphas:
                if alpha == 0:
                    intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
                elif alpha == 1:
                    intervals[i] = IntervalFactory.infimum_supremum(kernel, kernel)
                else:
                    int_min = ((kernel - minimum) / (number_of_cuts - 1)) * i + minimum
                    int_max = maximum - ((maximum - kernel) / (number_of_cuts - 1)) * i
                    intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
                i += 1

            return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)

    @staticmethod
    def trapezoidal(
        minimum: Union[str, int, float, Decimal],
        kernel_minimum: Union[str, int, float, Decimal],
        kernel_maximum: Union[str, int, float, Decimal],
        maximum: Union[str, int, float, Decimal],
        number_of_cuts: Optional[int] = None,
    ) -> FuzzyNumber:
        """
        Creates trapezoidal `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]
            Minimal value of fuzzy number.

        kernel_minimum: Union[str, int, float, Decimal]
            Minimum kernel value of fuzzy number.

        kernel_maximum: Union[str, int, float, Decimal]
            Maximal kernel value of fuzzy number.

        maximum: Union[str, int, float, Decimal]
            Maximal value of fuzzy number.

        number_of_cuts: int
            Number of alpha cuts.

        Returns
        -------
        FuzzyNumber
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
        kernel_minimum = FuzzyNumberFactory.validate_variable(kernel_minimum, "kernel_minimum")
        kernel_maximum = FuzzyNumberFactory.validate_variable(kernel_maximum, "kernel_maximum")

        if not minimum <= kernel_minimum <= kernel_maximum <= maximum:
            raise ValueError(
                "The fuzzy number is invalid. The structure needs to be "
                "`minimum` <= `kernel_minimum` <= `kernel_maximum` <= `maximum`. "
                f"Currently it is `{minimum}` <= `{kernel_minimum}` <= `{kernel_maximum}` <= `{maximum}`"
                ", which does not hold."
            )

        if number_of_cuts is None or number_of_cuts <= 2:
            return FuzzyNumber(
                alphas=[Decimal(0), Decimal(1)],
                alpha_cuts=[
                    IntervalFactory.infimum_supremum(minimum, maximum),
                    IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum),
                ],
            )

        else:
            alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

            intervals = [IntervalFactory.empty()] * len(alphas)

            i = 0
            for alpha in alphas:
                if alpha == 0:
                    intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
                elif alpha == 1:
                    intervals[i] = IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum)
                else:
                    int_min = ((kernel_minimum - minimum) / (number_of_cuts - 1)) * i + minimum
                    int_max = maximum - ((maximum - kernel_maximum) / (number_of_cuts - 1)) * i
                    intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
                i += 1

            return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)

    @staticmethod
    def crisp_number(value: Union[str, int, float, Decimal]) -> FuzzyNumber:
        """
        Creates `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        value: Union[str, int, float, Decimal]
            Value fuzzy number.

        Returns
        -------
        FuzzyNumber
        """

        value = FuzzyNumberFactory.validate_variable(value, "value")

        return FuzzyNumber(
            alphas=[Decimal(0), Decimal(1)],
            alpha_cuts=[IntervalFactory.infimum_supremum(value, value), IntervalFactory.infimum_supremum(value, value)],
        )

    @staticmethod
    def parse_string(string: str) -> FuzzyNumber:
        """
        Creates `FuzzyNumber` based on input string. The input string should be output of `__repr__()` function of
        `FuzzyNumber`.

        Parameters
        ----------
        string: str

        Returns
        -------
        FuzzyNumber
        """

        re_a_cuts = re.compile(r"([0-9\.;,]+)")
        re_numbers = re.compile(r"[0-9\.]+")

        elements = re_a_cuts.findall(string)

        alphas: List[Decimal] = [Decimal(0)] * len(elements)
        alpha_cuts: List[Interval] = [IntervalFactory.empty()] * len(elements)

        i: int = 0

        for a_cut_def in elements:
            numbers = re_numbers.findall(a_cut_def)

            if len(numbers) != 3:
                raise ValueError(
                    "Cannot parse FuzzyNumber from this definition. "
                    "Not all elements provide 3 values (alpha cut value and interval)."
                )

            numbers = [Decimal(x) for x in numbers]

            try:
                FuzzyNumber._validate_alpha(numbers[0])  # pylint: disable=W0212
            except ValueError as err:
                raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

            alphas[i] = Decimal(numbers[0])

            try:
                alpha_cuts[i] = IntervalFactory.infimum_supremum(numbers[1], numbers[2])
            except ValueError as err:
                raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

            i += 1

        return FuzzyNumber(alphas, alpha_cuts)


class IntervalFactory:
    """
    Class that supports creation of intervals based on different functions. All the functions are static.
    """

    @staticmethod
    def empty() -> Interval:
        """
        Creates empty interval, which has no values.

        Returns
        -------
        Interval
        """
        return Interval(Decimal("nan"), Decimal("nan"))

    @staticmethod
    def infimum_supremum(
        minimum: Union[str, int, float, Decimal], maximum: Union[str, int, float, Decimal]
    ) -> Interval:
        """
        Interval defined by minimum and maximum.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]

        maximum: Union[str, int, float, Decimal]

        Returns
        -------
        Interval

        Raises
        -------
        ValueError
            If `minimum > maximum` which is not valid interval for this definition.
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")

        if minimum > maximum:
            raise ValueError(
                "The interval is invalid. `minimum` must be lower or equal to"
                f" `maximum`. Currently it is `{minimum}` <= `{maximum}`, which does not hold."
            )

        return Interval(minimum, maximum)

    @staticmethod
    def two_values(a: Union[str, int, float, Decimal], b: Union[str, int, float, Decimal]) -> Interval:
        """
        Interval defined by two values.

        Parameters
        ----------
        a: Union[str, int, float, Decimal]

        b: Union[str, int, float, Decimal]

        Returns
        -------
        Interval
        """
        return Interval(a, b)

    @staticmethod
    def midpoint_width(midpoint: Union[str, int, float, Decimal], width: Union[str, int, float, Decimal]) -> Interval:
        """
        Interval defined by midpoint and width. The interval is [midpoint - width, midpoint + width].

        Parameters
        ----------
        midpoint: Union[str, int, float, Decimal]

        width: Union[str, int, float, Decimal]

        Returns
        -------
        Interval

        Raises
        -------
        ArithmeticError
            If `width < 0` which is not valid width definition.
        """
        width = FuzzyNumberFactory.validate_variable(width, "width")
        midpoint = FuzzyNumberFactory.validate_variable(midpoint, "midpoint")

        if width < 0:
            raise ArithmeticError(
                "`width` of interval must number higher or at least equal to 0. "
                f"The value `{width}` does not fulfill this."
            )

        a = midpoint - (width / Decimal(2))
        b = midpoint + (width / Decimal(2))

        return Interval(a, b)

    @staticmethod
    def parse_string(string: str) -> Interval:
        """
        Creates `Interval` based on input string. The input string should be output of `__repr__()` function of
        `Interval`.

        Parameters
        ----------
        string: str

        Returns
        -------
        Interval
        """

        re_values = re.compile(r"\d+\.?\d*")

        numbers = re_values.findall(string)

        if len(numbers) != 2:
            raise ValueError(
                "Cannot parse Interval from this definition. "
                "Element does not provide 2 values (minimal and maximal)."
            )

        return Interval(numbers[0], numbers[1])

Classes

class FactoryBase

Base class for factories

Expand source code
class FactoryBase(ABC):
    """Base class for factories"""

    @staticmethod
    def validate_variable(variable: Union[float, int, str, Decimal], variable_name: str) -> Decimal:
        """Checks that input variable can be converted to valid Decimal.

        Args:
            variable (Union[float, int, str, Decimal]): value to convert to Decimal.
            variable_name (str): name of variable for error message.

        Raises:
            InvalidOperation: if variable cannot be converted to Decimal.

        Returns:
            Decimal
        """
        try:
            var = Decimal(variable)
        except InvalidOperation as e:
            raise InvalidOperation(f"Cannot convert `{variable_name}` value ({variable}) to number.") from e
        return var

    @staticmethod
    def validate_alphas(alphas: List[Union[str, int, float, Decimal]], variable_name: str = "alphas") -> List[Decimal]:
        """Validate that all alphas are valid alpha values and converts them to Decimals.

        Args:
            alphas (List[Union[str, int, float, Decimal]]): List of alpha cut values.
            variable_name (str, optional): Name of variable for error message. Defaults to "alphas".

        Raises:
            InvalidOperation: If any alphas value cannot be converted to Decimal.

        Returns:
            List[Decimal]
        """
        decimal_alphas = []
        for alpha in alphas:
            try:
                decimal_alphas.append(Decimal(alpha))
            except InvalidOperation as e:
                raise InvalidOperation(f"Cannot convert `{variable_name}` value ({alpha}) to number.") from e
        return decimal_alphas

Ancestors

  • abc.ABC

Subclasses

Static methods

def validate_alphas(alphas: List[Union[str, int, float, decimal.Decimal]], variable_name: str = 'alphas') ‑> List[decimal.Decimal]

Validate that all alphas are valid alpha values and converts them to Decimals.

Args

alphas : List[Union[str, int, float, Decimal]]
List of alpha cut values.
variable_name : str, optional
Name of variable for error message. Defaults to "alphas".

Raises

InvalidOperation
If any alphas value cannot be converted to Decimal.

Returns

List[Decimal]

Expand source code
@staticmethod
def validate_alphas(alphas: List[Union[str, int, float, Decimal]], variable_name: str = "alphas") -> List[Decimal]:
    """Validate that all alphas are valid alpha values and converts them to Decimals.

    Args:
        alphas (List[Union[str, int, float, Decimal]]): List of alpha cut values.
        variable_name (str, optional): Name of variable for error message. Defaults to "alphas".

    Raises:
        InvalidOperation: If any alphas value cannot be converted to Decimal.

    Returns:
        List[Decimal]
    """
    decimal_alphas = []
    for alpha in alphas:
        try:
            decimal_alphas.append(Decimal(alpha))
        except InvalidOperation as e:
            raise InvalidOperation(f"Cannot convert `{variable_name}` value ({alpha}) to number.") from e
    return decimal_alphas
def validate_variable(variable: Union[float, int, str, decimal.Decimal], variable_name: str) ‑> decimal.Decimal

Checks that input variable can be converted to valid Decimal.

Args

variable : Union[float, int, str, Decimal]
value to convert to Decimal.
variable_name : str
name of variable for error message.

Raises

InvalidOperation
if variable cannot be converted to Decimal.

Returns

Decimal

Expand source code
@staticmethod
def validate_variable(variable: Union[float, int, str, Decimal], variable_name: str) -> Decimal:
    """Checks that input variable can be converted to valid Decimal.

    Args:
        variable (Union[float, int, str, Decimal]): value to convert to Decimal.
        variable_name (str): name of variable for error message.

    Raises:
        InvalidOperation: if variable cannot be converted to Decimal.

    Returns:
        Decimal
    """
    try:
        var = Decimal(variable)
    except InvalidOperation as e:
        raise InvalidOperation(f"Cannot convert `{variable_name}` value ({variable}) to number.") from e
    return var
class FuzzyNumberFactory

Class that supports creation of fuzzy numbers based on different functions. All the functions are static.

Expand source code
class FuzzyNumberFactory(FactoryBase):
    """
    Class that supports creation of fuzzy numbers based on different functions. All the functions are static.
    """

    @staticmethod
    def triangular(
        minimum: Union[str, int, float, Decimal],
        kernel: Union[str, int, float, Decimal],
        maximum: Union[str, int, float, Decimal],
        number_of_cuts: Optional[int] = None,
    ) -> FuzzyNumber:
        """
        Creates triangular `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]
            Minimal value of fuzzy number.

        kernel: Union[str, int, float, Decimal]
            Kernel (midpoint) value of fuzzy number.

        maximum: Union[str, int, float, Decimal]
            Maximal value of fuzzy number.

        number_of_cuts: int
            Number of alpha cuts.

        Returns
        -------
        FuzzyNumber
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
        kernel = FuzzyNumberFactory.validate_variable(kernel, "kernel")

        if not minimum <= kernel <= maximum:
            raise ValueError(
                "The fuzzy number is invalid. The structure needs to be `minimum` <= `kernel` "
                f"<= `maximum`. Currently it is `{minimum}` <= `{kernel}` <= `{maximum}`, which does not hold."
            )

        if number_of_cuts is None or number_of_cuts <= 2:
            return FuzzyNumber(
                alphas=[Decimal(0), Decimal(1)],
                alpha_cuts=[
                    IntervalFactory.infimum_supremum(minimum, maximum),
                    IntervalFactory.infimum_supremum(kernel, kernel),
                ],
            )

        else:
            alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

            intervals = [IntervalFactory.empty()] * len(alphas)

            i = 0
            for alpha in alphas:
                if alpha == 0:
                    intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
                elif alpha == 1:
                    intervals[i] = IntervalFactory.infimum_supremum(kernel, kernel)
                else:
                    int_min = ((kernel - minimum) / (number_of_cuts - 1)) * i + minimum
                    int_max = maximum - ((maximum - kernel) / (number_of_cuts - 1)) * i
                    intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
                i += 1

            return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)

    @staticmethod
    def trapezoidal(
        minimum: Union[str, int, float, Decimal],
        kernel_minimum: Union[str, int, float, Decimal],
        kernel_maximum: Union[str, int, float, Decimal],
        maximum: Union[str, int, float, Decimal],
        number_of_cuts: Optional[int] = None,
    ) -> FuzzyNumber:
        """
        Creates trapezoidal `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]
            Minimal value of fuzzy number.

        kernel_minimum: Union[str, int, float, Decimal]
            Minimum kernel value of fuzzy number.

        kernel_maximum: Union[str, int, float, Decimal]
            Maximal kernel value of fuzzy number.

        maximum: Union[str, int, float, Decimal]
            Maximal value of fuzzy number.

        number_of_cuts: int
            Number of alpha cuts.

        Returns
        -------
        FuzzyNumber
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
        kernel_minimum = FuzzyNumberFactory.validate_variable(kernel_minimum, "kernel_minimum")
        kernel_maximum = FuzzyNumberFactory.validate_variable(kernel_maximum, "kernel_maximum")

        if not minimum <= kernel_minimum <= kernel_maximum <= maximum:
            raise ValueError(
                "The fuzzy number is invalid. The structure needs to be "
                "`minimum` <= `kernel_minimum` <= `kernel_maximum` <= `maximum`. "
                f"Currently it is `{minimum}` <= `{kernel_minimum}` <= `{kernel_maximum}` <= `{maximum}`"
                ", which does not hold."
            )

        if number_of_cuts is None or number_of_cuts <= 2:
            return FuzzyNumber(
                alphas=[Decimal(0), Decimal(1)],
                alpha_cuts=[
                    IntervalFactory.infimum_supremum(minimum, maximum),
                    IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum),
                ],
            )

        else:
            alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

            intervals = [IntervalFactory.empty()] * len(alphas)

            i = 0
            for alpha in alphas:
                if alpha == 0:
                    intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
                elif alpha == 1:
                    intervals[i] = IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum)
                else:
                    int_min = ((kernel_minimum - minimum) / (number_of_cuts - 1)) * i + minimum
                    int_max = maximum - ((maximum - kernel_maximum) / (number_of_cuts - 1)) * i
                    intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
                i += 1

            return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)

    @staticmethod
    def crisp_number(value: Union[str, int, float, Decimal]) -> FuzzyNumber:
        """
        Creates `FuzzyNumber` based on input parameters.

        Parameters
        ----------
        value: Union[str, int, float, Decimal]
            Value fuzzy number.

        Returns
        -------
        FuzzyNumber
        """

        value = FuzzyNumberFactory.validate_variable(value, "value")

        return FuzzyNumber(
            alphas=[Decimal(0), Decimal(1)],
            alpha_cuts=[IntervalFactory.infimum_supremum(value, value), IntervalFactory.infimum_supremum(value, value)],
        )

    @staticmethod
    def parse_string(string: str) -> FuzzyNumber:
        """
        Creates `FuzzyNumber` based on input string. The input string should be output of `__repr__()` function of
        `FuzzyNumber`.

        Parameters
        ----------
        string: str

        Returns
        -------
        FuzzyNumber
        """

        re_a_cuts = re.compile(r"([0-9\.;,]+)")
        re_numbers = re.compile(r"[0-9\.]+")

        elements = re_a_cuts.findall(string)

        alphas: List[Decimal] = [Decimal(0)] * len(elements)
        alpha_cuts: List[Interval] = [IntervalFactory.empty()] * len(elements)

        i: int = 0

        for a_cut_def in elements:
            numbers = re_numbers.findall(a_cut_def)

            if len(numbers) != 3:
                raise ValueError(
                    "Cannot parse FuzzyNumber from this definition. "
                    "Not all elements provide 3 values (alpha cut value and interval)."
                )

            numbers = [Decimal(x) for x in numbers]

            try:
                FuzzyNumber._validate_alpha(numbers[0])  # pylint: disable=W0212
            except ValueError as err:
                raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

            alphas[i] = Decimal(numbers[0])

            try:
                alpha_cuts[i] = IntervalFactory.infimum_supremum(numbers[1], numbers[2])
            except ValueError as err:
                raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

            i += 1

        return FuzzyNumber(alphas, alpha_cuts)

Ancestors

Static methods

def crisp_number(value: Union[float, int, str, decimal.Decimal]) ‑> FuzzyNumber

Creates FuzzyNumber based on input parameters.

Parameters

value : Union[str, int, float, Decimal]
Value fuzzy number.

Returns

FuzzyNumber
 
Expand source code
@staticmethod
def crisp_number(value: Union[str, int, float, Decimal]) -> FuzzyNumber:
    """
    Creates `FuzzyNumber` based on input parameters.

    Parameters
    ----------
    value: Union[str, int, float, Decimal]
        Value fuzzy number.

    Returns
    -------
    FuzzyNumber
    """

    value = FuzzyNumberFactory.validate_variable(value, "value")

    return FuzzyNumber(
        alphas=[Decimal(0), Decimal(1)],
        alpha_cuts=[IntervalFactory.infimum_supremum(value, value), IntervalFactory.infimum_supremum(value, value)],
    )
def parse_string(string: str) ‑> FuzzyNumber

Creates FuzzyNumber based on input string. The input string should be output of __repr__() function of FuzzyNumber.

Parameters

string : str
 

Returns

FuzzyNumber
 
Expand source code
@staticmethod
def parse_string(string: str) -> FuzzyNumber:
    """
    Creates `FuzzyNumber` based on input string. The input string should be output of `__repr__()` function of
    `FuzzyNumber`.

    Parameters
    ----------
    string: str

    Returns
    -------
    FuzzyNumber
    """

    re_a_cuts = re.compile(r"([0-9\.;,]+)")
    re_numbers = re.compile(r"[0-9\.]+")

    elements = re_a_cuts.findall(string)

    alphas: List[Decimal] = [Decimal(0)] * len(elements)
    alpha_cuts: List[Interval] = [IntervalFactory.empty()] * len(elements)

    i: int = 0

    for a_cut_def in elements:
        numbers = re_numbers.findall(a_cut_def)

        if len(numbers) != 3:
            raise ValueError(
                "Cannot parse FuzzyNumber from this definition. "
                "Not all elements provide 3 values (alpha cut value and interval)."
            )

        numbers = [Decimal(x) for x in numbers]

        try:
            FuzzyNumber._validate_alpha(numbers[0])  # pylint: disable=W0212
        except ValueError as err:
            raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

        alphas[i] = Decimal(numbers[0])

        try:
            alpha_cuts[i] = IntervalFactory.infimum_supremum(numbers[1], numbers[2])
        except ValueError as err:
            raise ValueError(f"`{a_cut_def}` element of Fuzzy Number is incorrectly defined.") from err

        i += 1

    return FuzzyNumber(alphas, alpha_cuts)
def trapezoidal(minimum: Union[float, int, str, decimal.Decimal], kernel_minimum: Union[float, int, str, decimal.Decimal], kernel_maximum: Union[float, int, str, decimal.Decimal], maximum: Union[float, int, str, decimal.Decimal], number_of_cuts: Optional[int] = None) ‑> FuzzyNumber

Creates trapezoidal FuzzyNumber based on input parameters.

Parameters

minimum : Union[str, int, float, Decimal]
Minimal value of fuzzy number.
kernel_minimum : Union[str, int, float, Decimal]
Minimum kernel value of fuzzy number.
kernel_maximum : Union[str, int, float, Decimal]
Maximal kernel value of fuzzy number.
maximum : Union[str, int, float, Decimal]
Maximal value of fuzzy number.
number_of_cuts : int
Number of alpha cuts.

Returns

FuzzyNumber
 
Expand source code
@staticmethod
def trapezoidal(
    minimum: Union[str, int, float, Decimal],
    kernel_minimum: Union[str, int, float, Decimal],
    kernel_maximum: Union[str, int, float, Decimal],
    maximum: Union[str, int, float, Decimal],
    number_of_cuts: Optional[int] = None,
) -> FuzzyNumber:
    """
    Creates trapezoidal `FuzzyNumber` based on input parameters.

    Parameters
    ----------
    minimum: Union[str, int, float, Decimal]
        Minimal value of fuzzy number.

    kernel_minimum: Union[str, int, float, Decimal]
        Minimum kernel value of fuzzy number.

    kernel_maximum: Union[str, int, float, Decimal]
        Maximal kernel value of fuzzy number.

    maximum: Union[str, int, float, Decimal]
        Maximal value of fuzzy number.

    number_of_cuts: int
        Number of alpha cuts.

    Returns
    -------
    FuzzyNumber
    """

    minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
    maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
    kernel_minimum = FuzzyNumberFactory.validate_variable(kernel_minimum, "kernel_minimum")
    kernel_maximum = FuzzyNumberFactory.validate_variable(kernel_maximum, "kernel_maximum")

    if not minimum <= kernel_minimum <= kernel_maximum <= maximum:
        raise ValueError(
            "The fuzzy number is invalid. The structure needs to be "
            "`minimum` <= `kernel_minimum` <= `kernel_maximum` <= `maximum`. "
            f"Currently it is `{minimum}` <= `{kernel_minimum}` <= `{kernel_maximum}` <= `{maximum}`"
            ", which does not hold."
        )

    if number_of_cuts is None or number_of_cuts <= 2:
        return FuzzyNumber(
            alphas=[Decimal(0), Decimal(1)],
            alpha_cuts=[
                IntervalFactory.infimum_supremum(minimum, maximum),
                IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum),
            ],
        )

    else:
        alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

        intervals = [IntervalFactory.empty()] * len(alphas)

        i = 0
        for alpha in alphas:
            if alpha == 0:
                intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
            elif alpha == 1:
                intervals[i] = IntervalFactory.infimum_supremum(kernel_minimum, kernel_maximum)
            else:
                int_min = ((kernel_minimum - minimum) / (number_of_cuts - 1)) * i + minimum
                int_max = maximum - ((maximum - kernel_maximum) / (number_of_cuts - 1)) * i
                intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
            i += 1

        return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)
def triangular(minimum: Union[float, int, str, decimal.Decimal], kernel: Union[float, int, str, decimal.Decimal], maximum: Union[float, int, str, decimal.Decimal], number_of_cuts: Optional[int] = None) ‑> FuzzyNumber

Creates triangular FuzzyNumber based on input parameters.

Parameters

minimum : Union[str, int, float, Decimal]
Minimal value of fuzzy number.
kernel : Union[str, int, float, Decimal]
Kernel (midpoint) value of fuzzy number.
maximum : Union[str, int, float, Decimal]
Maximal value of fuzzy number.
number_of_cuts : int
Number of alpha cuts.

Returns

FuzzyNumber
 
Expand source code
@staticmethod
def triangular(
    minimum: Union[str, int, float, Decimal],
    kernel: Union[str, int, float, Decimal],
    maximum: Union[str, int, float, Decimal],
    number_of_cuts: Optional[int] = None,
) -> FuzzyNumber:
    """
    Creates triangular `FuzzyNumber` based on input parameters.

    Parameters
    ----------
    minimum: Union[str, int, float, Decimal]
        Minimal value of fuzzy number.

    kernel: Union[str, int, float, Decimal]
        Kernel (midpoint) value of fuzzy number.

    maximum: Union[str, int, float, Decimal]
        Maximal value of fuzzy number.

    number_of_cuts: int
        Number of alpha cuts.

    Returns
    -------
    FuzzyNumber
    """

    minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
    maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")
    kernel = FuzzyNumberFactory.validate_variable(kernel, "kernel")

    if not minimum <= kernel <= maximum:
        raise ValueError(
            "The fuzzy number is invalid. The structure needs to be `minimum` <= `kernel` "
            f"<= `maximum`. Currently it is `{minimum}` <= `{kernel}` <= `{maximum}`, which does not hold."
        )

    if number_of_cuts is None or number_of_cuts <= 2:
        return FuzzyNumber(
            alphas=[Decimal(0), Decimal(1)],
            alpha_cuts=[
                IntervalFactory.infimum_supremum(minimum, maximum),
                IntervalFactory.infimum_supremum(kernel, kernel),
            ],
        )

    else:
        alphas = FuzzyNumber.get_alpha_cut_values(number_of_cuts)

        intervals = [IntervalFactory.empty()] * len(alphas)

        i = 0
        for alpha in alphas:
            if alpha == 0:
                intervals[i] = IntervalFactory.infimum_supremum(minimum, maximum)
            elif alpha == 1:
                intervals[i] = IntervalFactory.infimum_supremum(kernel, kernel)
            else:
                int_min = ((kernel - minimum) / (number_of_cuts - 1)) * i + minimum
                int_max = maximum - ((maximum - kernel) / (number_of_cuts - 1)) * i
                intervals[i] = IntervalFactory.infimum_supremum(int_min, int_max)
            i += 1

        return FuzzyNumber(alphas=alphas, alpha_cuts=intervals)

Inherited members

class IntervalFactory

Class that supports creation of intervals based on different functions. All the functions are static.

Expand source code
class IntervalFactory:
    """
    Class that supports creation of intervals based on different functions. All the functions are static.
    """

    @staticmethod
    def empty() -> Interval:
        """
        Creates empty interval, which has no values.

        Returns
        -------
        Interval
        """
        return Interval(Decimal("nan"), Decimal("nan"))

    @staticmethod
    def infimum_supremum(
        minimum: Union[str, int, float, Decimal], maximum: Union[str, int, float, Decimal]
    ) -> Interval:
        """
        Interval defined by minimum and maximum.

        Parameters
        ----------
        minimum: Union[str, int, float, Decimal]

        maximum: Union[str, int, float, Decimal]

        Returns
        -------
        Interval

        Raises
        -------
        ValueError
            If `minimum > maximum` which is not valid interval for this definition.
        """

        minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
        maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")

        if minimum > maximum:
            raise ValueError(
                "The interval is invalid. `minimum` must be lower or equal to"
                f" `maximum`. Currently it is `{minimum}` <= `{maximum}`, which does not hold."
            )

        return Interval(minimum, maximum)

    @staticmethod
    def two_values(a: Union[str, int, float, Decimal], b: Union[str, int, float, Decimal]) -> Interval:
        """
        Interval defined by two values.

        Parameters
        ----------
        a: Union[str, int, float, Decimal]

        b: Union[str, int, float, Decimal]

        Returns
        -------
        Interval
        """
        return Interval(a, b)

    @staticmethod
    def midpoint_width(midpoint: Union[str, int, float, Decimal], width: Union[str, int, float, Decimal]) -> Interval:
        """
        Interval defined by midpoint and width. The interval is [midpoint - width, midpoint + width].

        Parameters
        ----------
        midpoint: Union[str, int, float, Decimal]

        width: Union[str, int, float, Decimal]

        Returns
        -------
        Interval

        Raises
        -------
        ArithmeticError
            If `width < 0` which is not valid width definition.
        """
        width = FuzzyNumberFactory.validate_variable(width, "width")
        midpoint = FuzzyNumberFactory.validate_variable(midpoint, "midpoint")

        if width < 0:
            raise ArithmeticError(
                "`width` of interval must number higher or at least equal to 0. "
                f"The value `{width}` does not fulfill this."
            )

        a = midpoint - (width / Decimal(2))
        b = midpoint + (width / Decimal(2))

        return Interval(a, b)

    @staticmethod
    def parse_string(string: str) -> Interval:
        """
        Creates `Interval` based on input string. The input string should be output of `__repr__()` function of
        `Interval`.

        Parameters
        ----------
        string: str

        Returns
        -------
        Interval
        """

        re_values = re.compile(r"\d+\.?\d*")

        numbers = re_values.findall(string)

        if len(numbers) != 2:
            raise ValueError(
                "Cannot parse Interval from this definition. "
                "Element does not provide 2 values (minimal and maximal)."
            )

        return Interval(numbers[0], numbers[1])

Static methods

def empty() ‑> Interval

Creates empty interval, which has no values.

Returns

Interval
 
Expand source code
@staticmethod
def empty() -> Interval:
    """
    Creates empty interval, which has no values.

    Returns
    -------
    Interval
    """
    return Interval(Decimal("nan"), Decimal("nan"))
def infimum_supremum(minimum: Union[float, int, str, decimal.Decimal], maximum: Union[float, int, str, decimal.Decimal]) ‑> Interval

Interval defined by minimum and maximum.

Parameters

minimum : Union[str, int, float, Decimal]
 
maximum : Union[str, int, float, Decimal]
 

Returns

Interval
 

Raises

ValueError
If minimum > maximum which is not valid interval for this definition.
Expand source code
@staticmethod
def infimum_supremum(
    minimum: Union[str, int, float, Decimal], maximum: Union[str, int, float, Decimal]
) -> Interval:
    """
    Interval defined by minimum and maximum.

    Parameters
    ----------
    minimum: Union[str, int, float, Decimal]

    maximum: Union[str, int, float, Decimal]

    Returns
    -------
    Interval

    Raises
    -------
    ValueError
        If `minimum > maximum` which is not valid interval for this definition.
    """

    minimum = FuzzyNumberFactory.validate_variable(minimum, "minimum")
    maximum = FuzzyNumberFactory.validate_variable(maximum, "maximum")

    if minimum > maximum:
        raise ValueError(
            "The interval is invalid. `minimum` must be lower or equal to"
            f" `maximum`. Currently it is `{minimum}` <= `{maximum}`, which does not hold."
        )

    return Interval(minimum, maximum)
def midpoint_width(midpoint: Union[float, int, str, decimal.Decimal], width: Union[float, int, str, decimal.Decimal]) ‑> Interval

Interval defined by midpoint and width. The interval is [midpoint - width, midpoint + width].

Parameters

midpoint : Union[str, int, float, Decimal]
 
width : Union[str, int, float, Decimal]
 

Returns

Interval
 

Raises

ArithmeticError
If width < 0 which is not valid width definition.
Expand source code
@staticmethod
def midpoint_width(midpoint: Union[str, int, float, Decimal], width: Union[str, int, float, Decimal]) -> Interval:
    """
    Interval defined by midpoint and width. The interval is [midpoint - width, midpoint + width].

    Parameters
    ----------
    midpoint: Union[str, int, float, Decimal]

    width: Union[str, int, float, Decimal]

    Returns
    -------
    Interval

    Raises
    -------
    ArithmeticError
        If `width < 0` which is not valid width definition.
    """
    width = FuzzyNumberFactory.validate_variable(width, "width")
    midpoint = FuzzyNumberFactory.validate_variable(midpoint, "midpoint")

    if width < 0:
        raise ArithmeticError(
            "`width` of interval must number higher or at least equal to 0. "
            f"The value `{width}` does not fulfill this."
        )

    a = midpoint - (width / Decimal(2))
    b = midpoint + (width / Decimal(2))

    return Interval(a, b)
def parse_string(string: str) ‑> Interval

Creates Interval based on input string. The input string should be output of __repr__() function of Interval.

Parameters

string : str
 

Returns

Interval
 
Expand source code
@staticmethod
def parse_string(string: str) -> Interval:
    """
    Creates `Interval` based on input string. The input string should be output of `__repr__()` function of
    `Interval`.

    Parameters
    ----------
    string: str

    Returns
    -------
    Interval
    """

    re_values = re.compile(r"\d+\.?\d*")

    numbers = re_values.findall(string)

    if len(numbers) != 2:
        raise ValueError(
            "Cannot parse Interval from this definition. "
            "Element does not provide 2 values (minimal and maximal)."
        )

    return Interval(numbers[0], numbers[1])
def two_values(a: Union[float, int, str, decimal.Decimal], b: Union[float, int, str, decimal.Decimal]) ‑> Interval

Interval defined by two values.

Parameters

a : Union[str, int, float, Decimal]
 
b : Union[str, int, float, Decimal]
 

Returns

Interval
 
Expand source code
@staticmethod
def two_values(a: Union[str, int, float, Decimal], b: Union[str, int, float, Decimal]) -> Interval:
    """
    Interval defined by two values.

    Parameters
    ----------
    a: Union[str, int, float, Decimal]

    b: Union[str, int, float, Decimal]

    Returns
    -------
    Interval
    """
    return Interval(a, b)