diff options
Diffstat (limited to '')
-rw-r--r-- | polymatrix/expression/expression.py | 5 | ||||
-rw-r--r-- | polymatrix/expression/from_.py | 4 | ||||
-rw-r--r-- | polymatrix/expression/impl.py | 24 | ||||
-rw-r--r-- | polymatrix/expression/mixins/determinantexprmixin.py | 133 | ||||
-rw-r--r-- | polymatrix/expression/mixins/divisionexprmixin.py | 109 | ||||
-rw-r--r-- | polymatrix/expression/mixins/toquadraticexprmixin.py | 97 |
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 |