Reputation: 225
I already know that the solution to a system of four equations are these:
The SymPy code I'm using:
z1, z2, w1, w2 = symbols( 'z1, z2, w1, w2', real=True )
ex1 = 2 * (z1*w1 + z2*w2)
ex2 = w1**2 + w2**2 + 4*z1*z2*w1*w2
ex3 = 2*w1*w2 * (z1*w2 + z2*w1)
ex4 = w1**2 * w2**2
eq1 = Eq( ex1, 10 )
eq2 = Eq( ex2, 45 )
eq3 = Eq( ex3, 105 )
eq4 = Eq( ex4, 105 )
solve( [ eq1, eq2, eq3, eq4 ], [ z1, z2, w1, w2 ] )
[] # Note that the result is empty.
I can demonstrate the solution I have, though:
solution = { z1:0.620702965049498, z2:0.957974461859108, w1:3.38936579272158, w2:3.02326493881663 }
for i in [ ex1, ex2, ex3, ex4 ]: i.subs( solution )
9.99999999999999 # Very close to 10 in eq1
44.9999999999999 # Very close to 45 in eq2
105.000000000000 # Matches 105 in eq3
105.000000000000 # Matches 105 in eq4
I'm wondering what I may have done wrong in setting this up for SymPy. Or if there's a known solver problem? (My SymPy version is '1.10.1'.)
Note: I'm working on the expression of a homogeneous solution for a 4th order Bessel equation as used in electronics filter design, where I've factored it into two 2nd order expressions.
Upvotes: 1
Views: 248
Reputation: 19135
Oscar has given several nice answers using the Groebner basis; beside the one above see also this one. If you apply that approach to your equations you will find that there are 8 solutions (but mainly 2, with permutations of signs on terms...and mainly 1 when you consider symmetry of exchanging z1 and z2 while exchanging w1 and w2).
First compute the basis of the equations in form f(X) = 0; X = (z1,z2,w1,w2)
from sympy import *
...
...your work from above
...
F = Tuple(*[i.rewrite(Add) for i in (eq1,eq2,eq3,eq4)])
X = (z1,z2,w1,w2)
G, Y = groebner(F, X)
G = Tuple(*G) # to make substitution easier below
G[-1] is a 12th order polynomial in w2 for which the real roots can be found: there are 4.
w2is = real_roots(G[-1])
assert len(w2is) == 4 # [i.n(3) for i in w2is] -> [-3.39, -3.02, 3.02, 3.39]
G[0] and G[1] are linear in z1 and z2, respectively, and G[2] is quadratic in w1. So substituting in a value for w2 and solving should give 2 solutions for each value of w2 for a total of 8 solutions.
sols = []
for _w2 in w2is:
for si in solve(G[:-1].subs(w2,_w2.n()), dict=True):
si.update({w2:_w2})
sols.append(si)
print({k: v.n(2) for k,v in si.items()})
{w1: -3.0, z1: -0.96, z2: -0.62, w2: -3.4}
{w1: 3.0, z1: 0.96, z2: -0.62, w2: -3.4}
{w1: -3.4, z1: -0.62, z2: -0.96, w2: -3.0}
{w1: 3.4, z1: 0.62, z2: -0.96, w2: -3.0}
{w1: -3.4, z1: -0.62, z2: 0.96, w2: 3.0}
{w1: 3.4, z1: 0.62, z2: 0.96, w2: 3.0}
{w1: -3.0, z1: -0.96, z2: 0.62, w2: 3.4}
{w1: 3.0, z1: 0.96, z2: 0.62, w2: 3.4}
Upvotes: 2
Reputation: 13185
Since you are looking for numerical solutions, you probably don't need SymPy.
Here I'm going to use scipy's fsolve
to solve your system of non-linear equations:
from scipy.optimize import fsolve
# convert your equations to numerical functions
eqns = [lambdify([z1, z2, w1, w2], eq.rewrite(Add)) for eq in [eq1, eq2, eq3, eq4]]
def func(p):
# p contains the current iteration parameters: z1, z2, w1, w2
return [eq(*p) for eq in eqns]
sol = fsolve(func, (1, 1, 1, 1))
print(sol)
# [0.62070297 0.95797446 3.38936579 3.02326494]
Note that you can also use Sympy's nsolve
to solve a system of equations for numerical values, but you need to provide some good initial guess, which for your case might not be trivial:
nsolve([eq1, eq2, eq3, eq4], [z1, z2, w1, w2], [0.5, 1, 3, 3])
Upvotes: 2