aboutsummaryrefslogtreecommitdiffstats
path: root/mdpoly/operations/exp.py
diff options
context:
space:
mode:
Diffstat (limited to 'mdpoly/operations/exp.py')
-rw-r--r--mdpoly/operations/exp.py52
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})"