Create a formal linear function in Sympy - python

I have an expression in Sympy (like
-M - n + x(n)
) and I would
like to create a formal linear function, says f, and apply it to my expression, in order to get, after simplification:
-f(M) - f(n) + f(x(n))
Is it possible to tell sympy that a property such as linearity is verified?
A very hacky way to do it would be to apply the function f to every subexpression which is in a sum.
For instance when given an expressions like the first one I gave, it would be nice to simply access the terms appearing in the sum (here it would be
[-M, -n , x(n)]
Then mapping f on the list and sum it to get what is expected.
Is there an easy way to do so, or have I necessarily to go trough the syntactic tree of the expression ?

This works:
>>> x,f = map(Function, 'xf'); n,M = symbols('n,M'); expr = -M - n + x(n)
>>> Add(*[f(a) for a in Add.make_args(expr)])
f(-M) + f(-n) + f(x(n))
If you have an expression like f(n*(M + 1)) and you expand it you will get f(n*M + n). Can you tell SymPy to apply the function to the args of f's args? Yes:
>>> expr = f(n*(M + 1))
>>> expr.expand().replace(lambda x: x.func == f,
... lambda x: Add(*[f(a) for a in Add.make_args(x.args[0])]))
f(n) + f(M*n)
If you call such a replacement linapp you can use it for any function that you want:
def linapp(expr, *f):
return expr.expand().replace(
lambda x: x.func in f,
lambda x: Add(*[x.func(a) for a in Add.make_args(x.args[0])]))
>>> print(linapp(cos(x+y) + sin(x + y), cos, sin))
sin(x) + sin(y) + cos(x) + cos(y)
(Not saying that it's a true result, just that you can do it. And if you replace a variable with something else and you want to reapply the linearization, you can:
>>> linapp(_.subs(y, z + 1), cos)
sin(x) + sin(z + 1) + cos(x) + cos(z) + cos(1)

Here's a hackey way that goes through the syntactic tree:
from sympy import *
init_session()
M,n=symbols('M n')
thing=-f(M) - f(n) + f(x(n))
def linerize_element(bro):
return bro.args[0] if len(bro.args) == 1 else bro.args[0] * bro.args[1].args[0]
print([ linerize_element(tmp) for tmp in thing.args])

Related

How can i change a variable name in a sympy expression

I am working on a project where I need to change all variables that are named 'a' to a new variable ai, where i is the order of the variable a in the expression. For instance if we use the expression: 1 + x + a + a ** 2, the output should be: 1 + x + a0 + a1 ** 2. Here is a code that I've written to solve this but it doesn't work, the expression remains unchanged.
import sympy.parsing.sympy_parser as sp1
import sympy as sp
I=sp1.parse_expr('1 + x + a + a**2', evaluate=False)
a,x=sp.symbols('a x')
def pre(expr):
i=0
for arg in sp.postorder_traversal(expr):
if arg==a:
tmp=sp.symbols('a'+str(i))
arg=tmp
print(arg)
i=i+1
pre(I)
print(I)
One way to achieve that is:
from sympy import Pow, Mul, Symbol, degree
def change_symbol(expr, a):
"""expr: the expression to modify
a: the symbol to look for and substitute
"""
# define a wild symbol to look for Symbols, Multiplications and Powers
# containing the specified symbol
w = Wild("w", properties=[
lambda t: isinstance(t, (Pow, Mul, Symbol)) and ((a in t.args) or (t == a))
])
# find the terms that satisfy the above criteria
terms = list(expr.find(w))
terms.sort(key=lambda t: degree(t), reverse=True)
# loop over those terms and performs the substitution with new symbols
name = a.name
for t in terms:
o = degree(t)
s = Symbol(name + "%s" % (o - 1))
expr = expr.subs(t, s**o)
return expr
change_symbol(I, a)
# out: a0 + a1**2 + x + 1
Your code did not work because you never changed the expression. When you say arg = tmp that assigns a value of tmp to arg but this does not update expr. #Davide_sd shows a way to recreate an expression with pieces that have been modified. You can also let replace do the traversal and let it replace a as it encounters it.
suffix = [0] #mutable suffix
def na():
rv = Symbol('a%s'%suffix[0])
suffix[0]+=1 # modify for next time
return rv
>>> a,x=var('a x')
>>> (1 + x + 2*a + a**2).replace(lambda x: x==a, lambda x: na())
a0**2 + 2*a1 + x + 1
Note that you said "order in expression" and coded as though you meant "order encountered" but in the polynomial sense, "higher order" terms will not necessarily appear later in the ordered terms. Note that a**2 appears before 2*a and that is why the replace gave it a value of a0:
>>> (1 + x + 2*a + a**2).args
(1, x, a**2, 2*a)

nth derivative with sympy

I'm a bit new to sympy
I would like to compute nth derivative of an expression using sympy; however, I don't understand how the diff function works for nth derivative:
from sympy import diff, symbols
x = symbols("x")
f = ((x**2-1)**5)
# for n = 2
# from the sympy docs, I do:
d_doc = diff(f, x, x)
# using the diff two times
d_2 = diff(diff(f, x), x)
I get two different results:
>>> d_doc
10*(x**2 - 1)**3*(9*x**2 - 1)
>>> d_2
80*x**2*(x**2 - 1)**3 + 10*(x**2 - 1)**4
d_2 is the correct answer in this case.
Why is this?
is there a way to make a function that takes a n and returns the nth derivative?
The answer in an easy place, (from Pranav Hosangadi's comment):
It is the same, diff(f, x, x) simplifies the expression
>>> simplify(diff(f,x,x))
(x**2 - 1)**3*(90*x**2 - 10)
>>> simplify(diff(diff(f,x),x))
(x**2 - 1)**3*(90*x**2 - 10)

Redefine a SymPy symbol globally (global subs)

I can't seem to find what I'm looking for in the SymPy docs: basically what I'd like to do is to redefine a symbol so it changes in every expression.
Something like this:
from sympy import *
x, y = symbols("x y")
expr1 = 2*x + y
expr2 = x**2 + 2*y
x.redefine("foo")
print(expr1, expr2)
x.redefine(2)
print(expr1, expr2)
Output:
2*foo + y, foo**2 + 2*y
4 + y, 4 + 2*y
Is it possible?
Sympy is designed in such a way that it cannot be redefined permanently. However, you can use the below command to substitute your symbol in an expression. Here is the documentation for it.
expr1.subs({x:"foo"}) #for changing only one symbol.
expr2.subs({x:10, y:20}) #for changing both the symbols.
SymPy expressions are immutable: they never change. Hence, there can be no global switch that implicitly modifies all preexisting expressions.
To handle substitution in multiple expressions, one can use loops, list comprehension, or apply subs to a matrix. Examples:
expressions = [2*x + y, x**2 + 2*y, x - y/2]
print([expr.subs(x, 3) for expr in expressions])
mat = Matrix(expressions)
print(mat.subs(x, 3))
This prints:
[y + 6, 2*y + 9, -y/2 + 3]
Matrix([[y + 6], [2*y + 9], [-y/2 + 3]])

Sympy outputs a derivative with log(e)

I'm using Sympy to calculate derivatives and some other things. I tried to calculate the derivative of "e**x + x + 1", and it returns e**x*log(e) + 1 as the result, but as far as I know the correct result should be e**x + 1. What's going on here?
Full code:
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
x = symbols("x")
_fOfX = "e**x + x + 1"
sympyFunction = parse_expr(_fOfX)
dSeconda = diff(sympyFunction,x,1)
print(dSeconda)
The answer correctly includes log(e) because you never specified what "e" is. It's just a letter like "a" or "b".
The Euler number 2.71828... is represented as E in SymPy. But usually, writing exp(x) is preferable because the notation is unambiguous, and also because SymPy is going to return exp(x) anyway. Examples:
>>> fx = E**x + x + 1
>>> diff(fx, x, 1)
exp(x) + 1
or with exp notation:
>>> fx = exp(x) + x + 1
>>> diff(fx, x, 1)
exp(x) + 1
Avoid creating expressions by parsing strings, unless you really need to and know why you need it.

Collecting like term of an expression in Sympy

I am currently dealing with functions of more than one variable and need to collect like terms in an attempt to simplify an expression.
Say the expression is written as follows:
x = sympy.Symbol('x')
y = sympy.Symbol('y')
k = sympy.Symbol('k')
a = sympy.Symbol('a')
z = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zEx = z.expand()
print type(z)
print type(zEx)
EDIT: Formatting to add clarity and changed the expression z to make the problem easier to understand.
Say z contains so many terms, that sifting through them by eye. and selecting the appropriate terms, would take an unsatisfactory amount of time.
I want to collect all of the terms which are ONLY a multiple of a**1. I do not care for quadratic or higher powers of a, and I do not care for terms which do not contain a.
The type of z and zEx return the following:
print type(z)
print type(zEx)
>>>
<class 'sympy.core.add.Add'>
<class 'sympy.core.mul.Mul'>
Does anyone know how I can collect the terms which are a multiple of a , not a^0 or a^2?
tl'dr
Where z(x,y) with constants a and k described by z and zEx and their type(): How can one remove all non-a terms from z AND remove all quadratic or higher terms of a from the expression? Such that what is left is only the terms which contain a unity power of a.
In addition to the other answers given, you can also use collect as a dictionary.
print(collect(zEx,a,evaluate=False)[a])
yields the expression
k*x**2 + k*y**2
In the end it is just an one-liner. #asmeurer brought me on the right track (check the comments below this post). Here is the code; explanations can be found below:
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys
x, y, k, a = symbols('x y k a')
# modified string: I added a few terms
z = x*(k*a**9) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*(k*a**1) - k*a**3 + y*a**5
zmod = Add(*[argi for argi in z.args if argi.has(a)])
Then zmod is
a**9*k*x - a**8*k + a**5*y - a**3*k + a*k*x
So let's look at this more carefully:
z.args
is just a collection of all individual terms in your expression (please note, that also the sign is parsed which makes things easier):
(k*x**2, a**5*y, -a**3*k, -a**8*k, a*k*x, a**9*k*x, k**2*x*y, k**3*x**2*y)
In the list comprehension you then select all the terms that contain an a using the function has. All these terms can then be glued back together using Add which gives you the desired output.
EDIT
The above returns all all the expressions that contain an a. If you only want to filter out the expressions that contain a with unity power, you can use collect and Mul:
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys
x, y, k, a = symbols('x y k a')
z2 = x**2*(k*a**1) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*k*a - k*a**3 + y*a**1
zc = collect(z2, a, evaluate=False)
zmod2 = Mul(zc[a], a)
then zmod2 is
a*(k*x**2 + k*x + y)
and zmod2.expand()
a*k*x**2 + a*k*x + a*y
which is correct.
With the updated z you provide I run:
z3 = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zc3 = collect(z3.expand(), a, evaluate=False)
zmod3 = Mul(zc3[a], a)
and then obtain for zmod3.expand():
a*k*x**2 + a*k*y**2
Is this the result you were looking for?
PS: Thanks to #asmeurer for all these helpful comments!
To iterate over the terms of an expression use expr.args.
I'm unclear what a is supposed to be, but the collect function may do what you want.

Categories

Resources