How to match real numeric coefficients for two expression in Sympy - python

If you look at this example:
2Bsin(x)+ (B + ¾A)*cos(x) = sin(x) + 2cos(x)
it’s easy to see that
2B = 1, B + ¾A = 2
and applying some basic linear algebra
B = ½, A = 2
In Python, using sympy, however, you run this code:
from sympy import *; var('x A B')
P1 = (B/2)*sin(x) + (B + 3*A/4)*cos(x)
P2 = sin(x) + 2*cos(x)
solve(Eq(P1, P2), [A,B])
you get this
[(-2*B*tan(x)/3 - 4*B/3 + 4*tan(x)/3 + 4/3, B)]
Is there a way to get the result in terms of A and B?

It seems like a little bit of a hack but works. I substitute sin(x) and cos(x) by x and y and turn it into a polynomial. Then I can just get the coefficients, make an equation out of those and solve it just fine.
from sympy import *; var('x y A B')
P1 = (B/2)*sin(x) + (B + 3*A/4)*cos(x)
P2 = sin(x) + 2*cos(x)
P1s = P1.subs({sin(x):x, cos(x):y})
P2s = P2.subs({sin(x):x, cos(x):y})
eqs = tuple(map(lambda x:Eq(*x),zip(Poly(P1s,[x,y]).coeffs(), Poly(P2s,[x,y]).coeffs())))
Those sympy does solve
sol = solve(eqs)
{A: 0, B: 2}
And I can even put those into the original equation to see if something weird happened:
P1.subs(sol), P2.subs(sol)
(sin(x) + 2*cos(x), sin(x) + 2*cos(x))

Related

How to solve system of nonlinear equations with parameters in Python

I am trying to solve a system of nonlinear equations in Python. The equations have the form:
(1) x^2 + y^2 = a
(2)(x-b)^2 + y^2 = c
where x and y are the variables and a,b,c are parameters. I would like to have a function which i can pass the parameters a,b,c to and it returns me the values for x and y. How can I do that ?
What i currently have is
from scipy.optimize import fsolve
def equation(var, *data):
a,b,c = data
x,y = var
eq1 = x**2 + y**2 - a**2
eq2 = (x - b)**2 + y**2 - c**2
return [eq1, eq2]
x,y = fsolve(equation, args=data)
But this does not quite work. Can someone help?
I think it is just missing the initialized values
from scipy.optimize import fsolve
def equation(var, *data):
a,b,c = data
x,y = var
eq1 = x**2 + y**2 - a**2
eq2 = (x - b)**2 + y**2 - c**2
return [eq1, eq2]
x,y = fsolve(equation,[1,1], args=(1,1,1))
print(x,y)
Taking inspiration from geometrical interpretation of Thierry Lathuille, there is maybe no real need to use a nonlinear solver.
First, Eq. (1) requires y^2=a^2-x^2 and thus (x-b)^2+a^2-x^2=c^2 according to Eq. (2). The latter equality simplifies to b^2-2bx+a^2=c^2 with xSol=(a^2+b^2-c^2)/(2b) as the possible solution for x (the symmetry suggest that there'll be only one solution for x). With this solution for x, we can check the sign of a^2-xSol^2. If negative, then there is no solution. If non-negative, then the solutions are (xSol,+ySol) and (xSol,-ySol) with ySol=np.sqrt(a^2-xSol^2).
Based on some testing with the code below, the solution above seems to work (but correct me if I'm wrong).
from scipy.optimize import fsolve
import numpy as np
abc = (1,1,4)
# Nonlinear optimizer
def equation(var, *data):
a,b,c = data
x,y = var
eq1 = x**2 + y**2 - a**2
eq2 = (x - b)**2 + y**2 - c**2
return [eq1, eq2]
x,y = fsolve(equation,[1,1], args=abc)
print(x,y)
# Geometric solution
a = abc[0]; b = abc[1]; c = abc[2]
xSol = (a**2+b**2-c**2)/(2*b)
if a**2-xSol**2<0:
print("No solution")
else:
ySol = np.sqrt(a**2-xSol**2)
print(xSol,ySol)
print(xSol,-ySol)

Find maxima for a negative parabolic equation

I have the following negative quadratic equation
-0.03402645959398278x^{2}+156.003469x-178794.025
I want to know if there is a straight way (using numpy/scipy libraries or any other) to get the value of x when the slope of the derivative is zero (the maxima). I'm aware I could:
change the sign of the equation and apply the scipy.optimize.minima method or
using the derivative of the equation so I can get the value when the slope is zero
For instance:
from scipy.optimize import minimize
quad_eq = np.poly1d([-0.03402645959398278, 156.003469, -178794.025])
############SCIPY####################
neg_quad_eq = np.poly1d(np.negative(quad_eq))
fit = minimize(neg_quad_eq, x0=15)
slope_zero_neg = fit.x[0]
maxima = np.polyval(quad_eq, slope_zero_neg)
print(maxima)
##################numpy######################
import numpy as np
first_dev = np.polyder(quad_eq)
slope_zero = first_dev.r
maxima = np.polyval(quad_eq, slope_zero)
print(maxima)
Is there any straight way to get the same result?
print(maxima)
You don't need all that code... The first derivative of a x^2 + b x + c is 2a x + b, so solving 2a x + b = 0 for x yields x = -b / (2a) that is actually the maximum you are searching for
import numpy as np
import matplotlib.pyplot as plt
def func(x, a=-0.03402645959398278, b=156.003469, c=-178794.025):
result = a * x**2 + b * x + c
return result
def func_max(a=-0.03402645959398278, b=156.003469, c=-178794.025):
maximum_x = -b / (2 * a)
maximum_y = a * maximum_x**2 + b * maximum_x + c
return maximum_x, maximum_y
x = np.linspace(-50000, 50000, 100)
y = func(x)
mx, my = func_max()
print('maximum:', mx, my)
maximum: 2292.384674478263 15.955750522436574
and verify
plt.plot(x, y)
plt.axvline(mx, color='r')
plt.axhline(my, color='r')

How to expand one exponential complex equation to two trigonometric ones in sympy?

I have one exponential equation with two unknowns, say:
y*exp(ix) = sqrt(2) + i * sqrt(2)
Manually, I can transform it to system of trigonometric equations:
y * cos x = sqrt(2)
y * sin x = sqrt(2)
How can I do it automatically in sympy?
I tried this:
from sympy import *
x = Symbol('x', real=True)
y = Symbol('y', real=True)
eq = Eq(y * cos(I * x), sqrt(2) + I * sqrt(2))
print([e.trigsimp() for e in eq.as_real_imag()])
but only got two identical equations except one had "re" before it and another one "im".
You can call the method .rewrite(sin) or .rewrite(cos) to obtain the desired form of your equation. Unfortunately, as_real_imag cannot be called on an Equation directly but you could do something like this:
from sympy import *
def eq_as_real_imag(eq):
lhs_ri = eq.lhs.as_real_imag()
rhs_ri = eq.rhs.as_real_imag()
return Eq(lhs_ri[0], rhs_ri[0]), Eq(lhs_ri[1], rhs_ri[1])
x = Symbol('x', real=True)
y = Symbol('y', real=True)
original_eq = Eq(y*exp(I*x), sqrt(2) + I*sqrt(2))
trig_eq = original_eq.rewrite(sin) # Eq(y*(I*sin(x) + cos(x)), sqrt(2) + sqrt(2)*I)
eq_real, eq_imag = eq_as_real_imag(trig_eq)
print(eq_real) # Eq(y*cos(x), sqrt(2))
print(eq_imag) # Eq(y*sin(x), sqrt(2))
(You might also have more luck just working with expressions (implicitly understood to be 0) instead of an Equation e.g. eq.lhs - eq.rhs in order to call the method as_real_imag directly)

How can I resolve this binomial equation by coding?

I'm having a problem finding out how to discover the write function to solve this problem:
Write a function that will take as an input two numbers (l,m) and return as a tuple the coefficients (a,b,c) for the quadratic equation a x^2 + b x + c found from expanding (x + l) * (x + m).
def func(l,m):
a = 1
equation = (a * (x ** 2)) + (b * x) + c
coef = [a,b,c]
eq2 = (x + m) * (x + l)
coef1 = m + l
coef2 = m * l
if coef1 == coef[1] and coef2 == coef[2]:
return coef
func(2,2)
Just to make it clear:
Your problem states:
return as a tuple the coefficients (a,b,c) for the quadratic equation
a x^2 + b x + c found from expanding (x + l) * (x + m).
Let's find the equation by expanding:
(x + l) * (x + m) =
= x^2 + l*x + m*x + l*m =
= x^2 + (l+m)*x + l*m
Now, by coefficients comparison with a x^2 + b x + c, we get that:
a = 1
b = l + m
c = l * m
So your function can basically return (1, l + m, l * m) directly...
Now that we have your code, I can tell you you're not using Python functions right. You can't create an unknown variable as you can do in math (here you called x)
There are modules who allow such operation with different syntax such as SymPy.
If you don't want to use it and you want to solve it "by-hand" maybe for a school project you'll need to compute a, b and conly from l and m with formulas.
As mentionned Tomerikoo
a = 1
b = l + m
c = l * m

Solving simultaneous equations with Python

Can anyone tell me the python code to solve the equation:
2w + x + 4y + 3z = 5
w - 2x + 3z = 3
3w + 2x - y + z = -1
4x - 5z = -3
I have the following code but it isn't working:
A2 = np.array([[2,1,4,3],[1,-2,3],[3,2,-1, 1],[4, -5]])
b2 = np.array([[5,3,-1, -3]]).T
print('A\n',A2)
print('b\n',b2)
v2 = np.linalg.solve(A2,b2)
print('v')
print(v2)
The problem is how you formatted the missing variables for the equations, remember that you should use 0 instead of nothing, otherwise the arrays (equations) get misinterpreted and provide you a wrong answer/error:
This should work for you now:
import numpy as np
A = [[2,1,4,3],[1,-2,0,3],[3,2,-1,1],[0,4,0,5]]
Y = [5,3,-1,3]
res = np.linalg.inv(A).dot(Y)
print(res)
Output:
[-0.15384615 -0.30769231 0.76923077 0.84615385]
An alternative approach uses sympy, Python's symbolic mathematics package:
from sympy import Eq, solve
from sympy.abc import w, x, y, z
sol = solve([ Eq(2*w + x + 4*y + 3*z, 5),
Eq(w - 2*x + 3*z, 3),
Eq(3*w + 2*x - y + z, -1),
Eq(4*x - 5*z, -3) ])
print(sol)
print({ s:sol[s].evalf() for s in sol })
This prints:
{w: 94/45, x: -20/9, y: 74/45, z: -53/45}
{w: 2.08888888888889, x: -2.22222222222222, y: 1.64444444444444, z: -1.17777777777778}
It is even possible to directly take the string input and find a solution:
from sympy import Eq, solve
from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
eqs = ['2w + x + 4y + 3z = 5',
'w - 2x + 3z = 3',
'3w + 2x - y + z = -1',
'4x - 5z = -3']
transformations=(standard_transformations + (implicit_multiplication_application,))
eqs_sympy = [Eq(parse_expr(e.split('=')[0], transformations=transformations),
parse_expr(e.split('=')[1], transformations=transformations))
for e in eqs]
sol = solve(eqs_sympy)
print(sol)

Categories