import cmath
import math
from ..interface import Interface
from ..scalar.ref import deref, is_literal, Get, Post
from ..uri import URI
[docs]class Boolean(Interface):
[docs] def logical_and(self, other):
"""Return `True` where both this :class:`Boolean` and the `other` are `True`."""
return Post(URI(self, "and"), {'r': other})
[docs] def logical_not(self):
"""Return `True` where this :class:`Boolean` is False and vice-versa."""
return Get(URI(self, "and"))
[docs] def logical_or(self, other):
"""Return `True` where this :class:`Boolean` or the `other` is `True`."""
return Post(URI(self, "or"), {'r': other})
[docs] def logical_xor(self, other):
"""Return `True` where either this :class:`Boolean` or the `other` is `True`, but not both."""
return Post(URI(self, "xor"), {'r': other})
[docs]class Numeric(Interface):
def __add__(self, other):
return self.add(other)
def __abs__(self):
return self.abs()
def __radd__(self, other):
return self.add(other)
def __mod__(self, other):
return self.modulo(other)
def __mul__(self, other):
return self.mul(other)
def __rmul__(self, other):
return self.mul(other)
def __neg__(self):
return self * -1
def __pow__(self, other):
return self.pow(other)
def __sub__(self, other):
return self.sub(other)
def __rsub__(self, other):
return -(self - other)
def __truediv__(self, other):
return self.div(other)
def __rtruediv__(self, other):
return other * (self.pow(-1))
@property
def shape(self):
"""The shape of this :class:`Numeric` state"""
from ..shape import Shape
return self._get("shape", rtype=Shape)
[docs] def abs(self):
"""Absolute value"""
return self._get("abs", rtype=self.__class__)
[docs] def add(self, other):
"""Addition"""
return self._post("add", {"r": other}, self.__class__)
[docs] def div(self, other):
"""Division"""
return self._post("div", {"r": other}, self.__class__)
[docs] def exp(self):
"""Raise `e` to the power of this `Numeric`."""
if is_literal(self):
form = deref(self)
if isinstance(form, complex):
return self.__class__(form=cmath.exp(form))
else:
return self.__class__(form=math.exp(deref(self)))
else:
return self._get("exp", rtype=self.__class__)
[docs] def log(self, base=None):
"""
Calculate the logarithm of this :class:`Numeric` with respect to the given `base`.
If no base is given, this will return the natural logarithm (base e).
"""
return self._get("log", base, self.__class__)
[docs] def modulo(self, other):
"""Return the remainder of `self` divided by `other`."""
return self._get("mod", other, self.__class__)
[docs] def mul(self, other):
"""Multiplication"""
return self._post("mul", {"r": other}, self.__class__)
[docs] def pow(self, other):
"""Raise this :class:`Numeric` to the given power."""
return self._post("pow", {"r": other}, self.__class__)
[docs] def round(self, digits=None):
"""
Round this :class:`Numeric` to the given number of `digits` from the decimal point.
If `digits` is not specified, this will round to the nearest integer.
"""
if digits is None:
return self._get("round", rtype=self.__class__)
else:
from ..scalar.number import UInt
places = UInt(10) ** digits
return (self * places).round() / places
[docs] def sub(self, other):
"""Subtraction"""
return self._post("sub", {"r": other}, self.__class__)
# TODO: define `angle`, `conj`, and `norm` methods
[docs]class Complex(Numeric):
@property
def imag(self):
"""The imaginary component of this :class:`Complex` :class:`Numeric`"""
return Get(URI(self, "imag"))
@property
def real(self):
"""The real component of this :class:`Complex` :class:`Numeric`"""
return Get(URI(self, "real"))
[docs] def angle(self):
"""
Return the angle of this :class:`Complex` number with respect to the origin of the complex plane.
The angle is given in radians.
"""
# from: https://en.wikipedia.org/wiki/Atan2#Definition_and_computation
if isinstance(deref(self), complex):
form = deref(self)
return math.atan2(form.imag, form.real)
else:
return 2 * (self.imag / ((self.real**2 + self.imag**2)**0.5 + self.real)).atan()
[docs]class Trigonometric(Interface):
[docs] @classmethod
def trig_rtype(cls):
raise NotImplementedError(f"trigonometric return type for {cls} is not defined")
[docs] def acos(self):
"""Arccosine"""
return self._get("acos", rtype=self.trig_rtype())
[docs] def acosh(self):
"""Hyperbolic arccosine"""
return self._get("acosh", rtype=self.trig_rtype())
[docs] def asin(self):
"""Arcsine"""
return self._get("asin", rtype=self.trig_rtype())
[docs] def asinh(self):
"""Hyperbolic arcsine"""
return self._get("asinh", rtype=self.trig_rtype())
[docs] def atan(self):
"""Arctangent"""
return self._get("atan", rtype=self.trig_rtype())
[docs] def atanh(self):
"""Hyperbolic arctangent"""
return self._get("atanh", rtype=self.trig_rtype())
[docs] def cos(self):
"""Cosine"""
return self._get("cos", rtype=self.trig_rtype())
[docs] def cosh(self):
"""Hyperbolic cosine"""
return self._get("cosh", rtype=self.trig_rtype())
[docs] def sin(self):
"""Sine"""
return self._get("sin", rtype=self.trig_rtype())
[docs] def sinh(self):
"""Hyperbolic sine"""
return self._get("sinh", rtype=self.trig_rtype())
[docs] def tan(self):
"""Tangent"""
return self._get("tan", rtype=self.trig_rtype())
[docs] def tanh(self):
"""Hyperbolic tangent"""
return self._get("tanh", rtype=self.trig_rtype())