Narcisse Doudieu Siewe
Narcisse Doudieu Siewe

Reputation: 649

Is it possible to index numpy array with sympy symbols?

Helle I want to do some summation on a numpy array like this

import numpy as np
import sympy as sy
import cv2

i, j = sy.symbols('i j', Integer=True)
#next read some grayscale image to create a numpy array of pixels  
a = cv2.imread(filename)
b = sy.summation(sy.summation(a[i][j], (i,0,1)), (j,0,1)) #double summation

but I'm facing with an error. is it possible to handle numpy symbols as numpy arrays'indexes? if not can you sugest me a solution? Thanks.

Upvotes: 3

Views: 2373

Answers (2)

unutbu
unutbu

Reputation: 879739

MatrixSymbol is limited to 2-dimensional matrices. To generalize to arrays of any dimension, you can generate the expression with IndexedBase. lambdify is currently incompatible with IndexedBase, but it can be used with DeferredVectors. So the trick is pass a DeferredVector to lambdify:

import sympy as sy
import numpy as np

a = sy.IndexedBase('a')
i, j, k = sy.symbols('i j k', integer=True)
s = sy.Sum(a[i, j, k], (i, 0, 1), (j, 0, 1), (k, 0, 1))
f = sy.lambdify(sy.DeferredVector('a'), s)
b = np.arange(24).reshape(2,3,4)

result = f(b)
expected = b[:2,:2,:2].sum()
assert expected == result

Upvotes: 2

asmeurer
asmeurer

Reputation: 91550

You can't use numpy object directly in SymPy expressions, because numpy objects don't know how to deal with symbolic variables.

Instead, create the thing you want symbolically using SymPy objects, and then lambdify it. The SymPy version of a numpy array is IndexedBase, but it seems there is a bug with it, so, since your array is 2-dimensional, you can also use MatrixSymbol.

In [49]: a = MatrixSymbol('a', 2, 2) # Replace 2, 2 with the size of the array

In [53]: i, j = symbols('i j', integer=True)

In [50]: f = lambdify(a, Sum(a[i, j], (i, 0, 1), (j, 0, 1)))

In [51]: b = numpy.array([[1, 2], [3, 4]])

In [52]: f(b)
Out[52]: 10

(also note that the correct syntax for creating integer symbols is symbols('i j', integer=True), not symbols('i j', Integer=True)).

Note that you have to use a[i, j] instead of a[i][j], which isn't supported.

Upvotes: 5

Related Questions