Spaces:
Sleeping
Sleeping
from .matexpr import MatrixExpr | |
from sympy.core.function import FunctionClass, Lambda | |
from sympy.core.symbol import Dummy | |
from sympy.core.sympify import _sympify, sympify | |
from sympy.matrices import Matrix | |
from sympy.functions.elementary.complexes import re, im | |
class FunctionMatrix(MatrixExpr): | |
"""Represents a matrix using a function (``Lambda``) which gives | |
outputs according to the coordinates of each matrix entries. | |
Parameters | |
========== | |
rows : nonnegative integer. Can be symbolic. | |
cols : nonnegative integer. Can be symbolic. | |
lamda : Function, Lambda or str | |
If it is a SymPy ``Function`` or ``Lambda`` instance, | |
it should be able to accept two arguments which represents the | |
matrix coordinates. | |
If it is a pure string containing Python ``lambda`` semantics, | |
it is interpreted by the SymPy parser and casted into a SymPy | |
``Lambda`` instance. | |
Examples | |
======== | |
Creating a ``FunctionMatrix`` from ``Lambda``: | |
>>> from sympy import FunctionMatrix, symbols, Lambda, MatPow | |
>>> i, j, n, m = symbols('i,j,n,m') | |
>>> FunctionMatrix(n, m, Lambda((i, j), i + j)) | |
FunctionMatrix(n, m, Lambda((i, j), i + j)) | |
Creating a ``FunctionMatrix`` from a SymPy function: | |
>>> from sympy import KroneckerDelta | |
>>> X = FunctionMatrix(3, 3, KroneckerDelta) | |
>>> X.as_explicit() | |
Matrix([ | |
[1, 0, 0], | |
[0, 1, 0], | |
[0, 0, 1]]) | |
Creating a ``FunctionMatrix`` from a SymPy undefined function: | |
>>> from sympy import Function | |
>>> f = Function('f') | |
>>> X = FunctionMatrix(3, 3, f) | |
>>> X.as_explicit() | |
Matrix([ | |
[f(0, 0), f(0, 1), f(0, 2)], | |
[f(1, 0), f(1, 1), f(1, 2)], | |
[f(2, 0), f(2, 1), f(2, 2)]]) | |
Creating a ``FunctionMatrix`` from Python ``lambda``: | |
>>> FunctionMatrix(n, m, 'lambda i, j: i + j') | |
FunctionMatrix(n, m, Lambda((i, j), i + j)) | |
Example of lazy evaluation of matrix product: | |
>>> Y = FunctionMatrix(1000, 1000, Lambda((i, j), i + j)) | |
>>> isinstance(Y*Y, MatPow) # this is an expression object | |
True | |
>>> (Y**2)[10,10] # So this is evaluated lazily | |
342923500 | |
Notes | |
===== | |
This class provides an alternative way to represent an extremely | |
dense matrix with entries in some form of a sequence, in a most | |
sparse way. | |
""" | |
def __new__(cls, rows, cols, lamda): | |
rows, cols = _sympify(rows), _sympify(cols) | |
cls._check_dim(rows) | |
cls._check_dim(cols) | |
lamda = sympify(lamda) | |
if not isinstance(lamda, (FunctionClass, Lambda)): | |
raise ValueError( | |
"{} should be compatible with SymPy function classes." | |
.format(lamda)) | |
if 2 not in lamda.nargs: | |
raise ValueError( | |
'{} should be able to accept 2 arguments.'.format(lamda)) | |
if not isinstance(lamda, Lambda): | |
i, j = Dummy('i'), Dummy('j') | |
lamda = Lambda((i, j), lamda(i, j)) | |
return super().__new__(cls, rows, cols, lamda) | |
def shape(self): | |
return self.args[0:2] | |
def lamda(self): | |
return self.args[2] | |
def _entry(self, i, j, **kwargs): | |
return self.lamda(i, j) | |
def _eval_trace(self): | |
from sympy.matrices.expressions.trace import Trace | |
from sympy.concrete.summations import Sum | |
return Trace(self).rewrite(Sum).doit() | |
def _eval_as_real_imag(self): | |
return (re(Matrix(self)), im(Matrix(self))) | |