Using a matrix multiplication operator in a sympy expression - python

I am trying to implement a function using a Sympy expression with multiple parameters. For example, I used the following code:
import sympy
a = sympy.symbols("a")
ad = sympy.symbols("ad")
x = sympy.symbols("x")
c = sympy.symbols("c")
f = (ad*a)*c + x
func = sympy.lambdify((a,ad,x,c),f)
And what I would like to evaluate is the following:
func(M_A,M_B,0,1)
When I use two matrices M_A and M_B, the function performs just an element-wise multiplication, but I need it to be a matrix multiplication for the objects a and ad. I do know that it is possible to do so when I define the variables using MatrixSymbol instead of symbols, but this is not possible in my case as I have implemented a scenario which uses diagonal matrices where element-wise or matrix multiplication would not make a difference. Further, it is also possible to do something like this with normal symbols
x_vars = [symbols("x"+i) for i in range(1,4)]
trans_mat = np.random.random([3,3])
y_vars = trans_mat.dot(x_vars)
which just does not seem to work when I am using MatrixSymbol.
So, I was thinking if I could just compute the expression and perform all the manipulations using the regular symbols and at the end replace all the multiplication operators with numpy.matmul. Please let me know if this is possible somehow, or any other suggestion which can help is also welcome.
Thanks!

Doing help(func) we can see the code produced by lambdify:
Help on function _lambdifygenerated:
_lambdifygenerated(a, ad, x, c)
Created with lambdify. Signature:
func(a, ad, x, c)
Expression:
a*ad*c + x
Source code:
def _lambdifygenerated(a, ad, x, c):
return a*ad*c + x
That's a straightforward translation to python/numpy. Sounds like you want (a#ad)*c+x.

Related

Convert symbolic expression to array in python

I'm trying to convert a symbolic expression to an array in python.
For example, I have this symbolic expression:
import sympy as sp
import numpy as np
A,B = sp.symbols("A B")
G = 3*A**2*B - 2*A*B + A**2
What I want is to convert this to an array looking as follows:
[3*A**2*B,-2*A*B,A**2]
I know how to do this in Matlab, but I need to do it in Python as well.
What I've tried:
I've converted the symbolic expression to a polynomial, which allowed me to collect the coefficients.
C = G.as_poly().coeffs()
This gets me halfway there:
C = [3,-2,1]
But I want to have at least a similar list for all the variables.
Does anyone have an idea?
You can use as_ordered_terms to get an ordered list of all the terms:
G.as_ordered_terms()
gives
[3*A**2*B, A**2, -2*A*B]
Alternatively, you can use args to get all the top-level arguments of the object.
G.args
This will give a tuple:
(A**2, -2*A*B, 3*A**2*B)

Finding coefficients of x in a string

I am trying to make an algebra solver, so I have to find the coefficients of x in an expression. Currently this is the code I have to take an input:
equation = input("Enter equation: ")
LHS, RHS = equation.split("=")[0], equation.split("=")[1]
##Remove whitespaces
LHS, RHS = LHS.replace(" ",""), RHS.replace(" ","")
Now I want to get the coefficients of x in the expressions LHS and RHS, how can I do this?
And also, the coefficients may not be just numbers but they may be of the form (2*3+4)x. I think this can be done using the eval() function but I don't know how to apply it.
Note: I want to do this with plain python, without using any modules which are not built-in.
In case it's only one variable and thus only one coefficient you could divide the respective variable/site by x.
Taking your example:
(2*3+4)x
dividing by x gives us the coefficient:
(2*3.4)
If that's not the approach you want to take, you could also convert the expression into a string and exclude "x", as such:
coefficientLHS = LHS.replace("x", "")
However, you should use this cautious as you might have algebra expressions in front of your variable, so regex implementation would be advisable.
Another approach would be to use the module Poly:
x = symbols("x")
coefLHS = Poly(LHS, x)
coefLHS.coeffs()

Is there a way to define a function through symbolic derivation?

Is there a way to define a function through symbolic derivation? For example,
def f(x):return x**x
def df(x) : return diff(f(x),x)
This code doesn't work, since df(1) would not be possible (diff(f(1),1) doesn't make sense.) But is there a way to take advantage of the result of "diff"? When printing df(x), there is a pretty function form with variable x, so neat.
Don't need Maple or Mathematica. Python has sympy.
import numpy as np
from sympy import symbols, diff, lambdify
x = symbols('x')
def f(x):
return x**x
def df(x):
return diff(f(x))
print(df(x))
This returns the symbolic derivative, x**x*(log(x) + 1). Now, it depends on what you want to do with that. It seems like you wanted to calculate numeric values without necessarily knowing that the derivative is x**x*(log(x) + 1). sympy's recommended way for calculating many numeric values is to use its lambdify.
df_numeric = lambdify(x, df(x), modules=['numpy'])
df_numeric(5)
This gives 8154.4934763565643. You can check it against a regular, manual function:
def df_manual(n):
return n**n*(np.log(n) + 1)
df_manual(5)

Is there a vectorized way to calculate the gradient in sympy?

How does one calculate the (symbolic) gradient of a multivariate function in sympy?
Obviously I could calculate separately the derivative for each variable, but is there a vectorized operation that does this?
For example
m=sympy.Matrix(sympy.symbols('a b c d'))
Now for i=0..3 I can do:
sympy.diff(np.sum(m*m.T),m[i])
which will work, but I rather do something like:
sympy.diff(np.sum(m*m.T),m)
Which does not work ("AttributeError: ImmutableMatrix has no attribute _diff_wrt").
Just use a list comprehension over m:
[sympy.diff(sum(m*m.T), i) for i in m]
Also, don't use np.sum unless you are working with numeric values. The builtin sum is better.
Here is an alternative to #asmeurer. I prefer this way because it returns a SymPy object instead of a Python list.
def gradient(scalar_function, variables):
matrix_scalar_function = Matrix([scalar_function])
return matrix_scalar_function.jacobian(variables)
mf = sum(m*m.T)
gradient(mf, m)

compute x-component of vector in sympy

I'm sure this is a really basic question, but I've googled and haven't found it. Supposed I have a vector in sympy
z = 3*x + 4*y
How do I compute the x-component of the vector (i.e. the 3)? z/x doesn't give it (there's still the y-part), nor does z[x] or z.x. Surely there's a way to do this, right?
Is it as simple as:
>>> from sympy.abc import x, y
>>> z = 3*x + 4*y
>>> z.coeff(x)
3
I think that calling this expression a vector is somewhat incorrect. Indeed, if you keep in your mind the assumption that x and y are some base vectors, it will work in your mind. However the library will not provide any vector-like functionality because it does not know that you want to treat this as vectors.
For vector with all the nice helper methods you can use the diffgeom submodule of sympy which provides predefined R^2 and R^3 spaces with numerous coordinate systems.
However, for your case pattern matching seems a much more natural choice. After all pattern matching is one of the basic building blocks of CASes like Mathematica and others.
In SymPy as in all other CASes you work with symbolic expressions which are basically big trees with operators at each node and some symbols at the leafs. You can match trees against some predefined patterns much in the same way in which you can use regex on strings. In sympy you use Wild to do that:
x, y = Symbols("x y")
a, b = Wild('a', exclude=[x, y]), Wild('b', exclude=[x, y])
(2*x + 3*y).match(a*x + b*y)
For the special case of linear combinations check coeff which is described in the other answer.
See: https://github.com/sympy/sympy/wiki/Idioms-and-Antipatterns#wild-and-match

Categories

Resources