diff options
Diffstat (limited to 'mdpoly/operations/exp.py')
-rw-r--r-- | mdpoly/operations/exp.py | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/mdpoly/operations/exp.py b/mdpoly/operations/exp.py new file mode 100644 index 0000000..fbc67f5 --- /dev/null +++ b/mdpoly/operations/exp.py @@ -0,0 +1,52 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +from operator import mul as opmul +from typing import cast +from functools import reduce +from dataclasses import dataclass + +from ..abc import Expr, Const +from ..errors import AlgebraicError + +from ..expressions import BinaryOp, Reducible +from ..expressions.matrix import MatrixExpr +from ..expression.poly import PolyRingExpr + + +# TODO: implement matrix exponential, use caley-hamilton thm magic +@dataclass(eq=False) +class MatExp(BinaryOp, MatrixExpr, Reducible): + def __init__(self): + raise NotImplementedError + + +@dataclass(eq=False) +class PolyExp(BinaryOp, PolyRingExpr, Reducible): + """ Exponentiation operator between scalar polynomials. """ + + @property # type: ignore[override] + def right(self) -> Const: # type: ignore[override] + if not isinstance(super().right, Const): + raise AlgebraicError(f"Cannot raise {self.left} to {self.right} because" + f"{self.right} is not a constant.") + + return cast(Const, super().right) + + @right.setter + def right(self, right: Expr) -> None: + # Workaround necessary because of a bug + # https://bugs.python.org/issue14965 + BinaryOp.right.fset(self, right) # type: ignore + + def reduce(self) -> Expr: + """ See :py:meth:`mdpoly.expressions.Reducible.reduce`. """ + var = self.left + if not isinstance(self.right.value, int): + raise NotImplementedError("Cannot raise to non-integer powers (yet).") + + ntimes = self.right.value - 1 + return reduce(opmul, (var for _ in range(ntimes)), var) + + def __str__(self) -> str: + return f"({self.left} ** {self.right})" |