Source code for symba.core.expression

import math
from abc import (ABC,
                 abstractmethod)
from numbers import Real
from typing import (Optional,
                    Tuple,
                    Union)

from .hints import SqrtEvaluator
from .utils import BASE


[docs]class Expression(ABC): __slots__ = () @property @abstractmethod def degree(self) -> int: """Returns degree of the expression.""" @property @abstractmethod def is_finite(self) -> bool: """Checks if the expression is finite."""
[docs] @abstractmethod def evaluate(self, sqrt_evaluator: Optional[SqrtEvaluator] = None) -> Real: """Evaluates the expression."""
[docs] @abstractmethod def extract_common_denominator(self) -> Tuple[int, 'Expression']: """ Returns a pair of the common denominator of the expression and the rest of the expression. """
[docs] @abstractmethod def extract_common_numerator(self) -> Tuple[int, 'Expression']: """ Returns a pair of the common numerator of the expression and the rest of the expression. """
[docs] @abstractmethod def inverse(self) -> 'Expression': """Returns the expression inverted."""
[docs] @abstractmethod def is_positive(self) -> bool: """Checks if the expression is positive."""
[docs] @abstractmethod def lower_bound(self) -> Real: """Returns lower bound of the expression."""
[docs] @abstractmethod def perfect_sqrt(self) -> 'Expression': """Returns perfect square root part of the expression."""
[docs] @abstractmethod def significant_digits_count(self) -> int: """Returns significant digits count of the expression."""
[docs] @abstractmethod def square(self) -> 'Expression': """Returns the expression squared."""
[docs] @abstractmethod def upper_bound(self) -> Real: """Returns upper bound of the expression."""
[docs] def __abs__(self) -> 'Expression': """Returns an absolute value of the expression.""" return self if self.is_positive() else -self
[docs] @abstractmethod def __add__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns sum of the expression with the other."""
[docs] def __ceil__(self) -> int: """Return the ceiling of the expression.""" return math.ceil(self.upper_bound())
[docs] def __floor__(self) -> int: """Return the floor of the expression.""" return math.floor(self.lower_bound())
[docs] def __floordiv__(self, other: Union[Real, 'Expression']) -> int: """Returns quotient of the division of the expression by the other.""" return math.floor(self / other)
[docs] def __ge__(self, other: Union[Real, 'Expression']) -> bool: """Checks if the expression is greater than or equal to the other.""" from .constant import to_expression other = to_expression(other) return ((not (other - self).is_positive() if other.is_finite else other <= self) if isinstance(other, Expression) else NotImplemented)
[docs] def __gt__(self, other: Union[Real, 'Expression']) -> bool: """Checks if the expression is greater than the other.""" from .constant import to_expression other = to_expression(other) return (((self - other).is_positive() if other.is_finite else other < self) if isinstance(other, Expression) else NotImplemented)
[docs] @abstractmethod def __hash__(self) -> int: """Returns hash value of the expression."""
[docs] def __le__(self, other: Union[Real, 'Expression']) -> bool: """Checks if the expression is lower than or equal to the other.""" from .constant import to_expression other = to_expression(other) return ((not (self - other).is_positive() if other.is_finite else other >= self) if isinstance(other, Expression) else NotImplemented)
[docs] def __lt__(self, other: Union[Real, 'Expression']) -> bool: """Checks if the expression is lower than the other.""" from .constant import to_expression other = to_expression(other) return (((other - self).is_positive() if other.is_finite else other > self) if isinstance(other, Expression) else NotImplemented)
[docs] def __mod__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns remainder of the division of the expression by the other.""" return self - other * (self // other)
[docs] @abstractmethod def __mul__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns multiplication of the expression with the other."""
[docs] @abstractmethod def __neg__(self) -> 'Expression': """Returns the expression negated."""
[docs] def __pos__(self) -> 'Expression': """Returns the expression positive.""" return self
[docs] def __pow__(self, exponent: int) -> 'Expression': """Returns the expression raised to the given exponent.""" if not isinstance(exponent, int): return NotImplemented from .constant import One if not exponent: return One result, step = One, self if exponent < 0: exponent, step = -exponent, step.inverse() while exponent > 1: if exponent & 1: result *= step step = step.square() exponent >>= 1 result *= step return result
[docs] @abstractmethod def __radd__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns sum of the other with the expression."""
[docs] def __rfloordiv__(self, other: Union[Real, 'Expression']) -> int: """Returns quotient of the division of the other by the expression.""" return math.floor(other / self)
[docs] def __rmod__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns remainder of the division of the other by the expression.""" return other - self * (other // self)
[docs] @abstractmethod def __rmul__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns multiplication of the other with the expression."""
[docs] def __round__(self, precision: Optional[int] = None) -> 'Expression': """Returns the expression rounded to the given precision.""" scale = BASE ** (1 if precision is None else precision + 1) return round(int(scale * self) / scale, precision)
[docs] def __rsub__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns difference of the other with the expression.""" return (other + (-self) if isinstance(other, (Real, Expression)) else NotImplemented)
[docs] def __rtruediv__(self, other: Real) -> 'Expression': """Returns division of the other by the expression.""" return (self.inverse() * other if isinstance(other, Real) else NotImplemented)
[docs] def __sub__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns difference of the expression with the other.""" return (self + (-other) if isinstance(other, (Real, Expression)) else NotImplemented)
[docs] def __truediv__(self, other: Union[Real, 'Expression']) -> 'Expression': """Returns division of the expression by the other.""" from .constant import to_expression other = to_expression(other) return (self * other.inverse() if isinstance(other, Expression) else NotImplemented)
[docs] def __trunc__(self) -> int: """Returns the expression truncated to a nearest-to-zero integer.""" return self.__floor__() if self.is_positive() else self.__ceil__()