summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--polymatrix/expression/expression.py5
-rw-r--r--polymatrix/expression/from_.py4
-rw-r--r--polymatrix/expression/impl.py24
-rw-r--r--polymatrix/expression/mixins/determinantexprmixin.py133
-rw-r--r--polymatrix/expression/mixins/divisionexprmixin.py109
-rw-r--r--polymatrix/expression/mixins/toquadraticexprmixin.py97
6 files changed, 1 insertions, 371 deletions
diff --git a/polymatrix/expression/expression.py b/polymatrix/expression/expression.py
index 0e15f44..9d910db 100644
--- a/polymatrix/expression/expression.py
+++ b/polymatrix/expression/expression.py
@@ -501,8 +501,6 @@ class Expression(ExpressionBaseMixin, ABC):
)
-# This is here and not in impl.py because of circular imports
-# FIXME: this is not ideal
@dataclassabc(frozen=True, repr=False)
class ExpressionImpl(Expression):
underlying: ExpressionBaseMixin
@@ -517,9 +515,6 @@ class ExpressionImpl(Expression):
)
-
-# This is here and not in init.py because of circular imports
-# FIXME: this is not ideal
def init_expression(
underlying: ExpressionBaseMixin,
):
diff --git a/polymatrix/expression/from_.py b/polymatrix/expression/from_.py
index 378a4b7..6fdb672 100644
--- a/polymatrix/expression/from_.py
+++ b/polymatrix/expression/from_.py
@@ -11,11 +11,9 @@ from polymatrix.statemonad.abc import StateMonad
# NP: this function name makes no sense to me,
-# NP: also why does this allow None return type? init_expression always return
-# NP: something so None object is in the underlying, not the returned object, which is confusing.
def from_expr_or_none(
data: FromDataTypes,
-) -> Expression | None:
+) -> Expression:
return init_expression(
underlying=polymatrix.expression.init.init_from_expr_or_none(
data=data,
diff --git a/polymatrix/expression/impl.py b/polymatrix/expression/impl.py
index 7e23329..8551fc5 100644
--- a/polymatrix/expression/impl.py
+++ b/polymatrix/expression/impl.py
@@ -13,10 +13,8 @@ from polymatrix.expression.mixins.blockdiagexprmixin import BlockDiagExprMixin
from polymatrix.expression.mixins.cacheexprmixin import CacheExprMixin
from polymatrix.expression.mixins.combinationsexprmixin import CombinationsExprMixin
from polymatrix.expression.mixins.derivativeexprmixin import DerivativeExprMixin
-from polymatrix.expression.mixins.determinantexprmixin import DeterminantExprMixin
from polymatrix.expression.mixins.diagexprmixin import DiagExprMixin
from polymatrix.expression.mixins.divergenceexprmixin import DivergenceExprMixin
-from polymatrix.expression.mixins.divisionexprmixin import DivisionExprMixin
from polymatrix.expression.mixins.elemmultexprmixin import ElemMultExprMixin
from polymatrix.expression.mixins.evalexprmixin import EvalExprMixin
from polymatrix.expression.mixins.eyeexprmixin import EyeExprMixin
@@ -62,7 +60,6 @@ from polymatrix.expression.mixins.subtractmonomialsexprmixin import (
from polymatrix.expression.mixins.sumexprmixin import SumExprMixin
from polymatrix.expression.mixins.symmetricexprmixin import SymmetricExprMixin
from polymatrix.expression.mixins.toconstantexprmixin import ToConstantExprMixin
-from polymatrix.expression.mixins.toquadraticexprmixin import ToQuadraticExprMixin
from polymatrix.expression.mixins.tosymmetricmatrixexprmixin import (
ToSymmetricMatrixExprMixin,
)
@@ -114,11 +111,6 @@ class DerivativeExprImpl(DerivativeExprMixin):
@dataclassabc.dataclassabc(frozen=True)
-class DeterminantExprImpl(DeterminantExprMixin):
- underlying: ExpressionBaseMixin
-
-
-@dataclassabc.dataclassabc(frozen=True)
class DiagExprImpl(DiagExprMixin):
underlying: ExpressionBaseMixin
@@ -130,17 +122,6 @@ class DivergenceExprImpl(DivergenceExprMixin):
@dataclassabc.dataclassabc(frozen=True)
-class DivisionExprImpl(DivisionExprMixin):
- left: ExpressionBaseMixin
- right: ExpressionBaseMixin
- stack: tuple[FrameSummary]
-
- # implement custom __repr__ method that returns a representation without the stack
- def __repr__(self):
- return f"{self.__class__.__name__}(left={self.left}, right={self.right})"
-
-
-@dataclassabc.dataclassabc(frozen=True)
class ElemMultExprImpl(ElemMultExprMixin):
left: ExpressionBaseMixin
right: ExpressionBaseMixin
@@ -371,11 +352,6 @@ class ToConstantExprImpl(ToConstantExprMixin):
@dataclassabc.dataclassabc(frozen=True)
-class ToQuadraticExprImpl(ToQuadraticExprMixin):
- underlying: ExpressionBaseMixin
-
-
-@dataclassabc.dataclassabc(frozen=True)
class ToSortedVariablesImpl(ToSortedVariablesExprMixin):
underlying: ExpressionBaseMixin
diff --git a/polymatrix/expression/mixins/determinantexprmixin.py b/polymatrix/expression/mixins/determinantexprmixin.py
deleted file mode 100644
index 4659ded..0000000
--- a/polymatrix/expression/mixins/determinantexprmixin.py
+++ /dev/null
@@ -1,133 +0,0 @@
-from __future__ import annotations
-
-import abc
-import collections
-import dataclasses
-import typing
-
-if typing.TYPE_CHECKING:
- from polymatrix.expressionstate.abc import ExpressionState
-
-from polymatrix.polymatrix.init import init_poly_matrix
-from polymatrix.expression.mixins.expressionbasemixin import ExpressionBaseMixin
-from polymatrix.polymatrix.abc import PolyMatrix
-
-
-class DeterminantExprMixin(ExpressionBaseMixin):
- @property
- @abc.abstractmethod
- def underlying(self) -> ExpressionBaseMixin: ...
-
- # NP: delete this code?
- # # overwrites the abstract method of `ExpressionBaseMixin`
- # @property
- # def shape(self) -> tuple[int, int]:
- # return self.underlying.shape[0], 1
-
- # overwrites the abstract method of `ExpressionBaseMixin`
- def apply(
- self,
- state: ExpressionState,
- ) -> tuple[ExpressionState, PolyMatrix]:
- # raise Exception('not implemented')
-
- if self in state.cache:
- return state, state.cache[self]
-
- state, underlying = self.underlying.apply(state=state)
-
- assert underlying.shape[0] == underlying.shape[1]
-
- inequality_data = {}
- auxillary_equations = {}
-
- index_start = state.n_param
- rel_index = 0
-
- # NP: consider providing a reference eg algorithm name if it has one
- # NP: or at least a minimal overview / explaination.
-
- for row in range(underlying.shape[0]):
- # FIXME: type annotations of dictionaries inside method
- polynomial = collections.defaultdict(float)
-
- # f in f-v^T@x-r^2
- # terms = underlying.get_poly(row, row)
- try:
- underlying_poly = underlying.get_poly(row, row)
-
- # NP: this is polymatrix leaking the abstraction, you should not
- # NP: need to care about these problems here. => Fix inside PolyMatrix
- except KeyError:
- pass
- else:
- for monomial, value in underlying_poly.items():
- polynomial[monomial] += value
-
- for inner_row in range(row):
- # -v^T@x in f-v^T@x-r^2
- # terms = underlying.get_poly(row, inner_row)
- try:
- underlying_poly = underlying.get_poly(row, inner_row)
- except KeyError:
- pass
- else:
- for monomial, value in underlying_poly.items():
- new_monomial = monomial + (index_start + rel_index + inner_row,)
- polynomial[new_monomial] -= value
-
- # auxillary terms
- # ---------------
-
- auxillary_polynomial = collections.defaultdict(float)
-
- for inner_col in range(row):
- # P@x in P@x-v
- key = tuple(reversed(sorted((inner_row, inner_col))))
- try:
- underlying_poly = underlying.get_poly(*key)
- except KeyError:
- pass
- else:
- for monomial, value in underlying_poly.items():
- new_monomial = monomial + (
- index_start + rel_index + inner_col,
- )
- auxillary_polynomial[new_monomial] += value
-
- # -v in P@x-v
- try:
- underlying_poly = underlying.get_poly(row, inner_row)
- except KeyError:
- pass
- else:
- for monomial, value in underlying_poly.items():
- auxillary_polynomial[monomial] -= value
-
- x_variable = index_start + rel_index + inner_row
- assert x_variable not in state.auxillary_equations
- auxillary_equations[x_variable] = dict(auxillary_polynomial)
-
- rel_index += row
- inequality_data[row, 0] = dict(polynomial)
-
- # NP: Type checker does not like the fact that state is of type
- # NP: ExpressionState, while register returns ExpressionStateMixinis this
- # NP: was a common problem I had while coding mdpoly, that eventually led
- # NP: me to abandoning mixins because they are a pain to get right with typing
- # NP: such that the type checker (mypy) is happy. This problem happens all over the
- # NP: place, I don't have a quick solution.
- state = state.register(rel_index)
-
- poly_matrix = init_poly_matrix(
- data=inequality_data,
- shape=(underlying.shape[0], 1),
- )
-
- state = dataclasses.replace(
- state,
- auxillary_equations=state.auxillary_equations | auxillary_equations,
- cache=state.cache | {self: poly_matrix},
- )
-
- return state, poly_matrix
diff --git a/polymatrix/expression/mixins/divisionexprmixin.py b/polymatrix/expression/mixins/divisionexprmixin.py
deleted file mode 100644
index 6dd2bd6..0000000
--- a/polymatrix/expression/mixins/divisionexprmixin.py
+++ /dev/null
@@ -1,109 +0,0 @@
-from __future__ import annotations
-
-import abc
-import dataclasses
-import typing
-
-if typing.TYPE_CHECKING:
- from polymatrix.expressionstate.abc import ExpressionState
-
-from polymatrix.expression.mixins.elemmultexprmixin import ElemMultExprMixin
-from polymatrix.utils.getstacklines import FrameSummary
-from polymatrix.utils.tooperatorexception import to_operator_exception
-from polymatrix.polymatrix.init import init_poly_matrix
-from polymatrix.expression.mixins.expressionbasemixin import ExpressionBaseMixin
-from polymatrix.polymatrix.abc import PolyMatrix
-
-
-class DivisionExprMixin(ExpressionBaseMixin):
- @property
- @abc.abstractmethod
- def left(self) -> ExpressionBaseMixin: ...
-
- @property
- @abc.abstractmethod
- def right(self) -> ExpressionBaseMixin: ...
-
- @property
- @abc.abstractmethod
- def stack(self) -> tuple[FrameSummary]: ...
-
- # overwrites the abstract method of `ExpressionBaseMixin`
- def apply(
- self,
- state: ExpressionState,
- ) -> tuple[ExpressionState, PolyMatrix]:
- state, left = self.left.apply(state=state)
- state, right = self.right.apply(state=state)
-
- # if left.shape == (1, 1):
- # left, right = right, left
-
- # assert right.shape == (1, 1)
-
- if not (right.shape == (1, 1)):
- raise AssertionError(
- to_operator_exception(
- message=f"{right.shape=} is not (1, 1)",
- stack=self.stack,
- )
- )
-
- right_poly = right.get_poly(0, 0)
-
- if len(right_poly) == 1 and tuple() in right_poly:
- right_inv = {(0, 0): {tuple(): 1 / right_poly[tuple()]}}
- return ElemMultExprMixin.elem_mult(
- state=state,
- left=left,
- right=init_poly_matrix(
- data=right_inv,
- shape=(1, 1),
- ),
- )
-
- # add an auxillary equation and, therefore, needs to be cached
- if self in state.cache:
- return state, state.cache[self]
-
- poly_matrix_data = {}
-
- division_variable = state.n_param
- state = state.register(n_param=1)
-
- for row in range(left.shape[0]):
- for col in range(left.shape[1]):
- underlying_poly = left.get_poly(row, col)
- if underlying_poly is None:
- continue
-
- def gen_polynomial():
- for monomial, value in underlying_poly.items():
- yield monomial + ((division_variable, 1),), value
-
- poly_matrix_data[row, col] = dict(gen_polynomial())
-
- def gen_auxillary_polynomials():
- for monomial, value in right_poly.items():
- yield monomial + ((division_variable, 1),), value
-
- auxillary_poly = dict(gen_auxillary_polynomials())
-
- if tuple() not in auxillary_poly:
- auxillary_poly[tuple()] = 0
-
- auxillary_poly[tuple()] -= 1
-
- poly_matrix = init_poly_matrix(
- data=poly_matrix_data,
- shape=left.shape,
- )
-
- state = dataclasses.replace(
- state,
- auxillary_equations=state.auxillary_equations
- | {division_variable: auxillary_poly},
- cache=state.cache | {self: poly_matrix},
- )
-
- return state, poly_matrix
diff --git a/polymatrix/expression/mixins/toquadraticexprmixin.py b/polymatrix/expression/mixins/toquadraticexprmixin.py
deleted file mode 100644
index 27fe628..0000000
--- a/polymatrix/expression/mixins/toquadraticexprmixin.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from __future__ import annotations
-
-import abc
-import collections
-import dataclasses
-import typing
-
-if typing.TYPE_CHECKING:
- from polymatrix.expressionstate.abc import ExpressionState
-
-from polymatrix.polymatrix.init import init_poly_matrix
-from polymatrix.expression.mixins.expressionbasemixin import ExpressionBaseMixin
-from polymatrix.polymatrix.abc import PolyMatrix
-
-
-class ToQuadraticExprMixin(ExpressionBaseMixin):
- """
- [[1 + x1**2 + x1**3]] -> [[1 + x1**2 + x2*x1]]
-
- with auxilliary equation: x1**2 - x2
- """
-
- @property
- @abc.abstractmethod
- def underlying(self) -> ExpressionBaseMixin: ...
-
- # overwrites the abstract method of `ExpressionBaseMixin`
- def apply(
- self,
- state: ExpressionState,
- ) -> tuple[ExpressionState, PolyMatrix]:
- state, underlying = self.underlying.apply(state=state)
-
- state = [state]
-
- poly_matrix_data = {}
- auxillary_equations_from_quadratic = {}
-
- def to_quadratic(monomial_terms):
- polynomial = collections.defaultdict(float)
-
- for monomial, value in monomial_terms.items():
- if 2 < len(monomial):
- current_aux = state[0].n_param
- polynomial[(monomial[0], current_aux)] += value
- state[0] = state[0].register(n_param=1)
-
- for variable in monomial[1:-2]:
- auxillary_equations_from_quadratic[current_aux] = {
- (variable, current_aux + 1): 1,
- (current_aux,): -1,
- }
- state[0] = state[0].register(n_param=1)
- current_aux += 1
-
- auxillary_equations_from_quadratic[current_aux] = {
- (monomial[-2], monomial[-1]): 1,
- (current_aux,): -1,
- }
-
- else:
- polynomial[monomial] += value
-
- # return dict(terms_row_col)
- return polynomial
-
- for row in range(underlying.shape[0]):
- for col in range(underlying.shape[1]):
- polynomial = underlying.get_poly(row, col)
- if polynomial is None:
- continue
-
- polynomial = to_quadratic(
- monomial_terms=polynomial,
- )
-
- poly_matrix_data[row, col] = polynomial
-
- def gen_auxillary_equations():
- for key, monomial_terms in state[0].auxillary_equations.items():
- polynomial = to_quadratic(
- monomial_terms=monomial_terms,
- )
- yield key, polynomial
-
- state = dataclasses.replace(
- state[0],
- auxillary_equations=dict(gen_auxillary_equations())
- | auxillary_equations_from_quadratic,
- )
-
- poly_matrix = init_poly_matrix(
- data=poly_matrix_data,
- shape=underlying.shape,
- )
-
- return state, poly_matrix