Python SymPy weird expression result - python

import sympy
import math
from sympy import *
a, b, c, d, stf, lc = symbols('a b c d stf lc')
init_printing()
expr = (2*(sin (a) + sin (b)/2)*(sin (c) + sin (d)/2)*stf)+(2*(cos (a) + cos (b)/2)*(cos (c)+ cos (d)/2)*lc)*2
expr
when I run this ine ig gives me as result:
2*lc*(2*cos(a) + cos(b))(cos(c) + cos(d)/2) + stf(2*sin(a) + sin(b))*(sin(c) + sin(d)/2)
I realize that first formula in expr is not the simplest, but when I try to only print it out, it makes some weird simplification.
when I
substiute all variables and print it out again, it goes even further:
(2sin(30)+sin(40))(250sin(30)+500sin(60))+(cos(40)+2cos(30))(5000cos(60)+2500cos(30))
is there any option to make SymPy not to change the order of elements in formula and just print it out in nice latex and then substiute variables and print again but keeping order of all elements from first formula?
I don't want to call any kind of simplification, at least not yet, as this formula is simple enough.

The order of the elements that is printed is the order in which it is stored -- and because the operator "+" is commutative by fiat, you can't specify an order for them to be printed.
For multiplication and multiplicative operators, you can specify that the indeterminate are non-commutative; e.g.
A,B = symbols('A B', commutative=False)
B*A
# B*A
A*B
# A*B
What you want to keep in mind is that, when you type something like "a+b" in the REPL loop, the interpreter creates a new object with a SymPy class, evaluates the expression "a+b", and sets the created object to the result of that evaluation. What is being stored isn't the formula "a+b", but an object that represents the mathematical object that "a+b" represents. Likewise, if you type:
a = 3 + 4
a is set to 7, not to the "formula" 3+4.
On the other hand, if you do not want to actually evaluate the expression, or want to keep track of its original string form, you can use the UnevaluatedExpr property:
from sympy import UnevaluatedExpr
UnevaluatedExpr( A ) + UnevaluatedExpr( B )
# A + B
UnevaluatedExpr( B ) + UnevaluatedExpr( A )
# B + A
Be careful though:
UnevaluatedExpr( A + B)
# A + B
UnevaluatedExpr( B + A)
# A + B

Related

Sympy: How can I store an equation in order to solve it later numerically?

Hello wonderful people,
I am building a physics model for some project. I have found a nice equation for my interest variable, but I would like to be able to solve the problem repeatedly with different parameters. What I would like to do is to save my equation as an object in a file (using pickle for example), then loading it at runtime and feed it the parameters it needs.
How would you achieve this?
With a simple example, the whole process would look like this:
(in a jupyter notebook)
import sympy as sp
import pickle
a, b, c = symbols("a b c")
eqn = sp.Eq(b + c, a) #for a real equation I would simplify it before using sympy
with open("eqn.txt") as f:
pickle.dump(eqn, f)
and then later in the app's code:
...
with open("eqn.txt") as f:
eqn = pickle.load(f)
b = 1
c = 2
#magic line to put b and c into the equation
a = sp.solve(eqn, a)
print(a) # 3
Implementing the whole equation directly in a function is probably not an option although I am considering how to implement it manually. It just looks really, really hard to do and if I could do it in two lines using simpy, that'd be great.
Thanks for your time!
with open("eqn.txt") as f:
eqn = pickle.load(f)
b, c = 1, 2 # b,c are python symbols here
reps = dict(zip(symbols('b c'), (b, c))) # keys are SymPy Symbols, values are 1,2
eqn = eqn.xreplace(reps) #magic line to put b and c into the equation
a = sp.solve(eqn, a)
print(a) # 3
It is important to keep in mind the distinction between b = 1 and b = Symbol('b'). The left hand side of the expressions are Python variables and on the right, an int or a SymPy Symbol, respectively. In a SymPy expression you might reference a Python variable and its value will be included in the equation:
>>> from sympy import *
>>> b = 1
>>> b + 1
2
>>> b = Symbol('b')
>>> b + 1
b + 1
>>> eq = _
>>> eq.subs(b,1)
2
>>> b=2 # assigning a new value to b does not change the object in eq
>>> eq
b + 1
>>> eq.subs(b, 2) # i.e., eq.subs(2,2) doesn't work -- no 2 in eq
b + 1
>>> eq.subs(Symbol('b'), 2) # replace the Symbol with value of 2 works
3
So in reps above, zipping the symbols to their corresponding values creates a mapping that can be used to do the replacement.
There is more discussion of such issues in the documentation gotchas file, but this should help with your current issue.

How to fix solver values when returned only the formula

I am using solver to find the zeros in the following equation. Solver returns only the formula of each one. How can i make it return for me a list of all the values calculated.
from sympy import *
A, B, C, D, r_w, r_j, r, R = symbols('A B C D rw1 rj1 r R')
equation=-pi*r**2*(A + B/(r/r_j + 1)) + pi*r**2*(C + D/(r/r_w + 1))
substitued=equation.subs([(A,232),(B,9768),(C,590),(D,7410),(rj1,1),
(rw1,2),(r,1)])
x=diff(substitued.subs(r,R),R)
solve(x,R)
`
why do i get returned the equations and not the values as a list. Please HELP!
0,−2337716−2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2−−2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716−2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+−2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716−−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246+2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716+−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246+2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2
It looks like things are a little scrambled here. But the short answer is that SymPy is a symbolic calculator and, except for combining numbers together automatically (like 1 + 2 -> 3), it doesn't compute sqrt(2) + 1 as 2.414... unless you tell it to. And one way to "tell it to do it" is nfloat:
>>> sol = solve(substitued.diff(r), r)
>>> nfloat(sol,3)
[0.0, -6.07 - 2.81*I, -6.07 + 2.81*I, -1.29, 0.386]
There is also nsolve if you want numerical approximations of your solutions, but for an equation like this where there are multiple roots, you will have to supply an initial guess to help the solver find the root in which you are interested. Here is a simpler equation to demonstrate:
>>> sol = solve(x**2+x-sqrt(3))
>>> sol
[-1/2 + sqrt(1 + 4*sqrt(3))/2, -sqrt(1 + 4*sqrt(3))/2 - 1/2]
>>> nfloat(sol, 3)
[0.908, -1.91]
>>> nsolve(x**2+x-sqrt(3), x, 1)
0.907853262086954
>>> nsolve(x**2+x-sqrt(3), x, -1)
-1.90785326208695

SymPy: Swap two variables

In an expression like
import sympy
a = sympy.Symbol('a')
b = sympy.Symbol('b')
x = a + 2*b
I'd like to swap a and b to retrieve b + 2*a. I tried
y = x.subs([(a, b), (b, a)])
y = x.subs({a: b, b: a})
but neither works; the result is 3*a in both cases as b, for some reason, gets replaced first.
Any hints?
There is a simultaneous argument you can pass to the substitution, which will ensure that all substitutions happen simultaneously and don't interfere with one another as they are doing now.
y = x.subs({a:b, b:a}, simultaneous=True)
Outputs:
2*a + b
From the docs for subs:
If the keyword simultaneous is True, the subexpressions will not be evaluated until all the substitutions have been made.

Plotting with SymPy

With SymPy, I can plot a function with:
f, a = symbols('f a')
f = a + 10
plot(f)
However, if I define the function as:
f, a, b = symbols('f a b')
f = a + b
b = 10
plot(f)
Then I get an error stating:
ValueError: The same variable should be used in all univariate
expressions being plotted.
How can I plot f if I define f = a + b, considering that b is assigned a constant value before plotting the function?
The lines
f, a, b = symbols('f a b')
f = a + b
b = 10
don't change b in the expression. If you print f you'll see that it is still defined as a + b.
You are confusing Python variables with SymPy symbols. In the first line, the Python variable b points to a SymPy symbol named b (in fact, they need not be the same name; you could have also written x = Symbol('b') and y = a + x). In the second line, the variable f points to a SymPy expression containing the symbol b. In the third line, the variable b points to the integer 10. This doesn't not change any previous lines that used the variable b, since they have already been run. It's no different than if you ran
a = 1
b = 1
c = a + b
b = 2
You would expect the value of c at the end to be 2, not 3. Similarly, when b points to a Symbol, expressions you create with it use a Symbol, but if you change it to point to a number, it doesn't affect previous lines from when it was a Symbol.
The recommended way to deal with this in SymPy is to avoid assigning the same variable to a symbol and then later to a non-symbol (it's worth pointing out that your definition of f in the first line is completely useless, since you immediately redefine it in the second line). To replace a symbol in an expression, use subs:
a, b = symbols('a b')
f = a + b
f1 = f.subs(b, 10)
Note that subs does not change the original f. It returns a new expression.
This document may also help clear this confusion up.
If you didn't want to use substitution as in the other answer, you could make f an actual function of course
def f(a, b):
return a + b
a = symbols('a')
b = 10
plot(f(a,b))
You must substitute b into f:
plot(f.subs('b', b))

Why SymPy can't solve quadratic equation with complicated coefficients

SymPy can easily solve quadratic equations with short simple coefficients.
For example:
from pprint import pprint
from sympy import *
x,b,f,Lb,z = symbols('x b f Lb z')
eq31 = Eq((x*b + f)**2, 4*Lb**2*z**2*(1 - x**2))
pprint(eq31)
sol = solve(eq31, x)
pprint(sol)
But with a little bit larger coefficients - it can't:
from pprint import pprint
from sympy import *
c3,b,f,Lb,z = symbols('c3 b f Lb z')
phi,Lf,r = symbols('phi Lf r')
eq23 = Eq(
(
c3 * (2*Lb*b - 2*Lb*f + 2*Lb*r*cos(phi + pi/6))
+ (Lb**2 - Lf**2 + b**2 - 2*b*f + 2*b*r*cos(phi + pi/6) + f**2 - 2*f*r*cos(phi + pi/6) + r**2 + z**2)
)**2,
4*Lb**2*z**2*(1 - c3**2)
)
pprint(eq23)
print("\n\nSolve (23) for c3:")
solutions_23 = solve(eq23, c3)
pprint(solutions_23)
Why?
This is not specific to Sympy - other programs like Maple or Mathematica suffer from same the problem: When solving an equation, solve needs to choose a proper solution strategy (see e.g. Sympy's Solvers) based on assumptions about the variables and the structure of the equation. These are choices are normally heuristic and often incorrect (hence no solution, or false strategies are tried first). Furthermore, the assumptions of variables is often to broad (e.g., complex instead of reals).
Thus, for complex equations the solution strategy often has to be given by the user. For your example, you could use:
sol23 = roots(eq23.lhs - eq23.rhs, c3)
Since symbolic solutions are supported, one thing you can do is solve the generic quadratic and substitute in your specific coefficients:
>>> eq = eq23.lhs-eq23.rhs
>>> a,b,c = Poly(eq,c3).all_coeffs()
>>> var('A:C')
(A, B, C)
>>> ans=[i.xreplace({A:a,B:b,C:c}) for i in solve(A*x**2 + B*x + C,x)]
>>> print filldedent(ans)
...
But you can get the same result if you just shut of simplification and checking:
>>> ans=solve(eq23,c3,simplify=False,check=False)
(Those are the really expensive parts of the call to solve.)

Categories

Resources