I'm trying to solve the cosine formula using sympy. (A is angle and a, b, c is sides)
sol = solve(a**2-b**2-c**2+2*b*c*cos(pi/180*A), [A, a, b, c])
print(sol)
And I end up getting results like this:
[(90.0000000000000, 5.00000000000000, 4.00000000000000, 3.00000000000000), (270.000000000000, 5.00000000000000, 4.00000000000000, 3.00000000000000)]
But it's impossible for a triangle to have a 270º interior angle.
I tried to do A, B, C <= 180 and solve(a**2-b**2-c**2+2*b*c*cos(pi/180*A), [A<=180, a, b, c]).I also try to use exclude=[A<=180] in the solve(), but it don't work too.
Let's understand what's happening:
from sympy import *
a, b, c, A = symbols("a, b, c, A")
eq = a**2-b**2-c**2+2*b*c*cos(pi/180*A)
eq is a trigonometric equation involving the cosine function, which is periodic with a period of 2*pi. Suppose you want to solve cos(x) = y where y is contained in (-1, 1]: you will get two solutions! For example, suppose you want to solve cos(x) = 0.5: one solution is x=60deg and the other is x=300deg.
Now let's focus on your equation. You have one equation with 4 symbols. Let's assume that a,b,c are known quantities and asks Sympy to solve for A (the unknown, which I assume it is the angle in degrees).
We can filter out the solutions in two approaches.
First approach
Substitute the known values a, b, c into eq and then solve for A with a specified constraint:
# substitution dictionary
d = {a: 1, b: 1, c: 1}
# solve the equation asking to find the solution for which A <= 180
sol = solve([eq.subs(d), A <= 180], A)
print(sol)
# out: (-oo < A) & (A <= 180) & (Eq(A, 60) | Eq(A, 300))
Here, SymPy produced a boolean solution (meaning it is a combination of one or more solutions with the And and Or objects). Let's try to simplify it a bit:
sol2 = sol.as_set()
print(sol2)
# out: {60}
Now we can extract it with:
A_num = list(sol2)[0]
print(A_num)
# 60
Second approach
Obtain a fully symbolic solution, then substitute the known values and filter out according to your rules:
sol = solve(eq, A)
for i, s in enumerate(sol):
print("sol", i+1, ":", s)
# output:
# sol 1 : 180*(-acos((-a**2 + b**2 + c**2)/(2*b*c)) + 2*pi)/pi
# sol 2 : 180*acos((-a**2 + b**2 + c**2)/(2*b*c))/pi
# substitution dictionary
d = {a: 1, b: 1, c: 1}
sol = [s.subs(d) for s in sol]
# apply custom filter:
sol = [s for s in sol if s <= 180]
sol = sol[0]
print(sol)
# out: 60
Related
Note: I am brand new to sympy and trying to figure it out how it works.
What I have now:
I do get the correct solutions but it takes 35 - 50 seconds.
Goal:
To speed it up the calculations by defining symbolic equation once and then reusing it with different variables.
Set up:
I need to calculate a polynomial G(t) (t = 6 roots) for every iteration of the loop. (220 iterations total)
G(t) have 6 other variables, which are calculated and are known on every iterations.
These variables are different on every iteration.
First try (slow):
I simply put every into one python function, where I defined Gt symbolically and solved for t.
It was running around 35 - 40 seconds. function_G is called on every iteration.
def function_G(f1, f2, a, b, c, d):
t = sp.symbols('t')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = sp.expand(left - right)
roots = sp.solveset(Gt, t)
return roots
Then a person gave me a hint that:
You should only need to (symbolically) solve for the coefficients of the polynomial once, as a preprocessing step. After that, when processing each iterations, you simply calculate the polynomial coefficients, then solve for the roots.
I asked for clarification the person added:
So I defined the function g(t) and then used sympy.expand to work out all parenthesis/exponents, and then sympy.collect to collect terms by powers of t. Finally I used .coeff on the output of collect to get the coefficients to feed into numpy.root.
Second try:
To followed the advice, I defined a G(t) symbolically first and passed it to the function that runs the loop along with its symbolic parameters. Function constructGt() thus is called only once.
def constructGt():
t, a, b, c, d, f1, f2 = sp.symbols('t a b c d f1 f2')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
gt = sp.Eq(left - right, 0)
expanded = sp.expand(gt)
expanded = sp.collect(expanded, t)
g_vars = {
"a": a,
"b": b,
"c": c,
"d": d,
"f1": f1,
"f2": f2
}
return expanded, g_vars
then on every iteration I was passing the function and its parameters to get the roots:
#Variables values:
#a = 0.00011713490404073987
#b = 0.00020253296124588926
#c = 4.235688216068313e-07
#d = 0.012262546040805029
#f1= -0.012553203944721956
#f2 = 0.018529776776949003
def function_G(f1_, f2_, a_, b_, c_, d_, Gt, v):
Gt = Gt.subs([(v['a'], a_), (v['b'], b_),
(v['c'], c_), (v['d'], d_),
(v['f1'], f1_), (v['f2'], f2_)])
roots = sp.solveset(Gt, t)
return roots
But it got even slower around 56 seconds.
Question:
I do not understand what Am I doing wrong? I also do not understand how this person is using .coeff() and then np.roots on the results.
Even if your f1 and f2 are linear in a variable, you are working with a quartic polynomial and the roots of that are very long. If this is univariate then it would be better to just use the expression, solve it at some value of constants where the solution is known and then use that value and new constants that are relatively close to the old ones and use nsolve to get the next root. If you are interested in more than one solution you may have to "follow" each root separately with nsolve...but I think you will be much happier with the overall performance. Using real_roots is another option, especially if the expression is simply a polynomial in some variable.
Given that you are working with a quartic you should keep this in mind: the general solution is so long and complicated (except for very special cases) that it is not efficient to work with the general solution and substitute in values as they are known. It is very easy to solve for numerical values, however, and it is much faster:
First create the symbolic expression into which values will be substituted; assumptionless "vanilla" symbols are used:
t, a, b, c, d, f1, f2 = symbols('t a b c d f1 f2')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = left - right
Next, define a dictionary of replacements to subtitute into the expression noting that dict(x=1) creates {'x': 1} and when this is used with subs a vanilla Symbol will be created for "x":
reps = dict(
a = 0.00011713490404073987 ,
b = 0.00020253296124588926 ,
c = 4.235688216068313e-07 ,
d = 0.012262546040805029 ,
f1= -0.012553203944721956 ,
f2 = 0.018529776776949003)
Evaluate the real roots of the expression:
from time import time
t=time();[i.n(3) for i in real_roots(eq.subs(reps))];'%s sec' % round(time()-t)
[-11.5, -1.73, 8.86, 1.06e+8]
'3 sec'
Find all 6 roots of the expression but take only the real parts:
>>> roots(eq.subs(reps))
{-11.4594523988215: 1, -1.73129179415963: 1, 8.85927293271708: 1, 106354884.4365
42: 1, -1.29328524826433 - 10.3034942999005*I: 1, -1.29328524826433 + 10.3034942
999005*I: 1}
>>> [re(i).n(3) for i in _]
[-11.5, -1.73, 8.86, 1.06e+8, -1.29, -1.29]
Change one or more values and do it again
reps.update(dict(a=2))
[i.n(3) for i in real_roots(eq.subs(reps))]
[-0.0784, -0.000101, 0.0782, 3.10e+16]
Update values in a loop:
>>> a = 1
>>> for i in range(3):
... a += 1
... reps.update(dict(a=a))
... a, real_roots(eq.subs(reps))[0].n(3)
...
(2, -0.0784)
(3, -0.0640)
(4, -0.0554)
Note: when using roots, the real roots will come first in sorted order and then imaginary roots will come in conjugate pairs (but otherwise not in any given order).
I have three variables called a, b and c, each of these can assume a different value defined in a range. I'd like to create a function that tests every possible variable value and gives me their best combination for the output 'f'.
a = list(range(1, 10, 2))
b = list(range(5, 8, 1))
c = list(range(1, 3, 1))
def all_combinations (a, b, c):
#something
f = a + (b * a) - (c*(a ^ b))
return BEST a, b, c for my f
it's possible to do it ? what is the best way to do it?
You can use itertools.product() to get all the possible combinations of a, b, and c.
Then calculate your formula for each unique combination of a b c, keep track of the result, and if the result is better than the previous best, save the current values of a b c.
import itertools
def all_combinations (alist, blist, clist):
best_a = 0
best_b = 0
best_c = 0
best_f = 0
for a,b,c in itertools.product(alist, blist, clist):
f = a + (b * a) - (c*(a ^ b))
if f > best_f: # use your own definition of "better"
best_a = a
best_b = b
best_c = c
best_f = f
return best_a, best_b, best_c
First of all, you said I have three variables called a, b and c, each of these can assume a different value defined in a range. Note that the variables in your code are actually equal to three lists of integers, not three integers.
The naive algorithm to test all possible combinations is 3 nested for loops. Here I assume that by "best" you mean "maximum value":
def all_combinations (list1, list2, list3):
best_f, best_a, best_b, best_c = None, None, None, None
for a in list1:
for b in list2:
for c in list3:
f = a + (b * a) - (c*(a ^ b))
# here you have to define what f being "better" than best_f means:
if not f or f > best_f:
best_f = f
best_a = a
best_b = b
best_c = c
return best_a, best_b, best_c
If you're sure those are the only values you want to test, then the following will work. Otherwise you might want to look into scipy.optimize.
from itertools import product
import numpy as np
parameters = list(product(a, b, c))
results = [my_fun(*x) for x in parameters]
print(parameters[np.argmax(results)])
obviously replace np.argmax with np.argmin if you want to minimize the function
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
I have a sympy expression involving two variables a, b. I would now like to evaluate this expression for specific values of a and b. Using a lambda like
import sympy
def get_expression(a, b):
# Complex function with a simple result. I have no control here.
return a*b + 2
a = sympy.Symbol('a')
b = sympy.Symbol('b')
z = get_expression(a, b)
f = lambda a, b: z
print(f(1, 1))
only gives
a*b + 2
though.
Any hints?
Turns out that lambdify is what I need:
f = sympy.lambdify([a, b], z)
print(f(1, 1))
I have a function named f = 0.5/(z-3). I would like to know what would the coefficients p and q be if f was written in the following form: q/(1-p*z) but unfortunately sympy match function returns None. Am I doing something wrong? or what is the right way of doing something like this?
Here is the code:
z = symbols('z')
p, q = Wild('p'), Wild('q')
print (0.5/(z-3)).match(q/(1-p*z))
EDIT:
My expected answer is: q=-1/6 and p = 1/3
One way of course is
p, q = symbols('p q')
f = 0.5/(z-3)
print solve(f - q/(1-p*z), p, q,rational=True)
But I don't know how to do that in pattern matching, or if it's capable of doing something like this.
Thanks in Advance =)
If you start by converting to linear form,
1 / (2*z - 6) == q / (1 - p*z)
# multiply both sides
# by (2*z - 6) * (1 - p*z)
1 - p*z == q * (2*z - 6)
then
from sympy import Eq, solve, symbols, Wild
z = symbols("z")
p,q = symbols("p q", cls=Wild)
solve(Eq(1 - p*z, q*(2*z - 6)), (p,q))
gives
{p_: 1/3, q_: -1/6}
as expected.
Edit: I found a slightly different approach:
solve(Eq(f, g)) is equivalent to solve(f - g) (implicitly ==0)
We can reduce f - g like simplify(f - g), but by default it doesn't do anything because the resulting equation is more than 1.7 times longer than the original (default value for ratio argument).
If we specify a higher ratio, like simplify(f - g, ratio=5), we get
>>> simplify(1/(2*z-6) - q/(1-p*z), ratio=5)
(z*p_ + 2*q_*(z - 3) - 1)/(2*(z - 3)*(z*p_ - 1))
This is now in a form the solver will deal with:
>>> solve(_, (p,q))
{p_: 1/3, q_: -1/6}
SymPy's pattern matcher only does minimal algebraic manipulation to match things. It doesn't match in this case because there is no 1 in the denominator. It would be better to match against a/(b + c*z) and manipulate a, b, and c into the p and q. solve can show you the exact formula:
In [7]: solve(Eq(a/(b + c*z), q/(1 - p*z)), (q, p))
Out[7]:
⎧ -c a⎫
⎨p: ───, q: ─⎬
⎩ b b⎭
Finally, it's always a good idea to use exclude when constructing Wild object, like Wild('a', exclude=[z]). Otherwise you can get unexpected behavior like
In [11]: a, b = Wild('a'), Wild('b')
In [12]: S(2).match(a + b*z)
Out[12]:
⎧ 2⎫
⎨a: 0, b: ─⎬
⎩ z⎭
which is technically correct, but probably not what you want.