pythonmatlabevalsympycode-conversion

How can I evaluate pre-defined symbolic variables array in Python?


I have a MATLAB code and I'm trying to convert it to Python. I used the eval() to evaluate my symbolic arrays in MATLAB. But I couldn't find how to solve this in Python. Here's a simple example:

MATLAB Code:


%values to be assigned
input = [10 20 30; ...
         15 25 20; ...
         20 20 10]

%decision variables     
x_1_1 = input(1)    
x_2_1 = input(2)    
x_3_1 = input(3)    
x_1_2 = input(4)
x_2_2 = input(5)    
x_3_2 = input(6)
x_1_3 = input(7)    
x_2_3 = input(8)    
x_3_3 = input(9)

%symbolic arrray
symbolic_eq  = sym('x_',[3,3])

%any math operation    
m  =  [-1  0  0 ; ...
        0 -1  0 ; ...
        0  1 -1 ]

% new equations for symbolic array    
multp_eq  = m*symbolic_eq

% get results
results   = eval(multp_eq)

Python code:

from sympy import *
import numpy as np

#values to be assigned
input = np.array([[10, 20, 30, 15, 25, 20, 20, 20, 10]])

#decision variables
x_1_1 = input[0]
x_2_1 = input[1]
x_3_1 = input[2]
x_1_2 = input[3]
x_2_2 = input[4]
x_3_2 = input[5]
x_1_3 = input[6]
x_2_3 = input[7]
x_3_3 = input[8]

#symbolic array (edited)
symbolic_eq = symarray('x', (4, 4))
symbolic_eq = np.array(symbolic_eq [1:, 1:])

#any math operation
m  =  np.array([[-1,  0,  0 ],
                [ 0, -1,  0 ],
                [ 0,  1, -1 ]])

#new equations for symbolic array
multp_eq  = m*symbolic_eq

# get results
results   = eval(multp_eq)

Also, for both MATLAB and Python, how can I define my input() variables easily?


Solution

  • The main problem with your code was you needed to do the substitution (with the method .subs() before you could evaluate your expression. This is done by providing a list tuples containing the variable and its value. Here I build this list in a for loop.

    A few extra comments about your code. In general, avoid the commands like from sympy import * . It fills your namespace for no good reason. Finally, I see no "good" reasons to go to indices starting from 1 rather than 0. I suggest to consider switching to the native indexing, as it often makes the code cleaner.

    import sympy as sp
    import numpy as np
    
    #values to be assigned
    aninput = np.array([[10, 20, 30],
                        [15, 25, 20],
                        [20, 20, 10]])
    
    #symbolic array (edited)
    symbolic_eq = sp.symarray('x', (4, 4))
    symbolic_eq = symbolic_eq [1:, 1:]
    
    thesubs = []
    for index, theinput in np.ndenumerate(aninput):
        thesubs.append((symbolic_eq[index], aninput[index]))
    print(thesubs)
    
    #any math operation
    m  =  sp.Matrix([[-1,  0,  0 ],
                    [ 0, -1,  0 ],
                    [ 0,  1, -1 ]])
    
    #new equations for symbolic array
    multp_eq  = m*symbolic_eq
    
    # get results
    results   = multp_eq.subs(thesubs)
    results
    

    Finally, this code will not run very fast. If you want to do this operation for a large number of input array of values, you should consider using sympy.lambdify instead of .subs.

    function = sp.lambdify(np.array(symbolic_eq).flatten(), multp_eq, modules="numpy" )
    

    Then you just have to call the function to get the answer:

    result = function(*aninput.flatten())
    

    On my machine, and for this simple example, this last line is almost 400 times faster than the one using subs. However, if the size of your imput array can increase, then this solution can run into some limitations (to 256 values if I remember).