Каков наилучший способ решения пары нелинейных уравнений с использованием Python. (Numpy, Scipy или Sympy)
например:
- x + y ^ 2 = 4
- e ^ x + xy = 3
Фрагмент кода, который решает вышеупомянутую пару, будет отличным
Каков наилучший способ решения пары нелинейных уравнений с использованием Python. (Numpy, Scipy или Sympy)
например:
- x + y ^ 2 = 4
- e ^ x + xy = 3
Фрагмент кода, который решает вышеупомянутую пару, будет отличным
для численного решения, вы можете использовать fsolve:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fsolve.html#scipy.optimize.fsolve
from scipy.optimize import fsolve
import math
def equations(p):
x, y = p
return (x+y**2-4, math.exp(x) + x*y - 3)
x, y = fsolve(equations, (1, 1))
print equations((x, y))
Если вы предпочитаете sympy, вы можете использовать nsolve.
>>> nsolve([x+y**2-4, exp(x)+x*y-3], [x, y], [1, 1])
[0.620344523485226]
[1.83838393066159]
Первый аргумент - это список уравнений, второй - список переменных, а третий - исходное предположение.
Попробуйте это, я заверяю вас, что он будет работать отлично.
import scipy.optimize as opt
from numpy import exp
import timeit
st1 = timeit.default_timer()
def f(variables) :
(x,y) = variables
first_eq = x + y**2 -4
second_eq = exp(x) + x*y - 3
return [first_eq, second_eq]
solution = opt.fsolve(f, (0.1,1) )
print(solution)
st2 = timeit.default_timer()
print("RUN TIME : {0}".format(st2-st1))
->
[ 0.62034452 1.83838393]
RUN TIME : 0.0009331008900937708
FYI. как упоминалось выше, вы также можете использовать "приближение Бройдена", заменив "fsolve" на "broyden1". Оно работает. Я сделал это.
Я точно не знаю, как работает приближение Бройдена, но это заняло 0,02 с.
И я рекомендую вам не использовать функции Sympy < - удобно, но с точки зрения скорости это довольно медленно. Ты увидишь.
from scipy.optimize import fsolve
def double_solve(f1,f2,x0,y0):
func = lambda x: [f1(x[0], x[1]), f2(x[0], x[1])]
return fsolve(func,[x0,y0])
def n_solve(functions,variables):
func = lambda x: [ f(*x) for f in functions]
return fsolve(func, variables)
f1 = lambda x,y : x**2+y**2-1
f2 = lambda x,y : x-y
res = double_solve(f1,f2,1,0)
res = n_solve([f1,f2],[1.0,0.0])
Вы можете использовать пакет openopt и его метод NLP. Он имеет множество алгоритмов динамического программирования для решения нелинейных алгебраических уравнений, состоящих из:
goldenSection, scipy_fminbound, scipy_bfgs, scipy_cg, scipy_ncg, amsg2p, scipy_lbfgsb, scipy_tnc, bobyqa, ralg, ipopt, scipy_slsqp, scipy_cobyla, lincher, algencan,, которые вы можете выбрать.
Некоторые из последних алгоритмов могут решить проблему ограниченного нелинейного программирования.
Итак, вы можете ввести свою систему уравнений в openopt.NLP() с такой функцией:
lambda x: x[0] + x[1]**2 - 4, np.exp(x[0]) + x[0]*x[1]
Я получил метод Бройдена для работы с связанными нелинейными уравнениями (как правило, с участием многочленов и экспонент) в IDL, но я не пробовал его в Python:
scipy.optimize.broyden1
scipy.optimize.broyden1(F, xin, iter=None, alpha=None, reduction_method='restart', max_rank=None, verbose=False, maxiter=None, f_tol=None, f_rtol=None, x_tol=None, x_rtol=None, tol_norm=None, line_search='armijo', callback=None, **kw)[source]
Найти корень функции, используя первое приближение Я. Я. Брайденса.
Этот метод также известен как "хороший метод Бройденса".
Альтернативой fsolve
является root
:
import numpy as np
from scipy.optimize import root
def your_funcs(X):
x, y = X
# all RHS have to be 0
f = [x + y**2 - 4,
np.exp(x) + x * y - 3]
return f
sol = root(your_funcs, [1.0, 1.0])
print(sol.x)
Это напечатает
[0.62034452 1.83838393]
Если вы затем проверите
print(your_funcs(sol.x))
вы получаете
[4.4508396968012676e-11, -1.0512035686360832e-11]
подтверждая правильность решения.
Как упоминалось в других ответах, самое простое решение конкретной поставленной вами проблемы - использовать что-то вроде fsolve
:
from scipy.optimize import fsolve
from math import exp
def f(vars):
x, y = vars
eq1 = x+y**2-4
eq2 = exp(x) + x*y - 3
return [eq1, eq2]
x, y = fsolve(equations, (1, 1))
print(x, y)
Выход:
0.6203445234801195 1.8383839306750887
Вы говорите, как "решить", но есть разные варианты решения. Поскольку вы упоминаете SymPy, я должен указать на самое большое различие между тем, что это может означать, а именно между аналитическими и числовыми решениями. Конкретный пример, который вы привели, не имеет (простого) аналитического решения, как другие системы нелинейных уравнений. Когда есть доступные аналитические решения, SymPY часто может найти их для вас:
In [29]: from sympy import *
In [30]: x, y = symbols('x, y')
In [31]: eq1 = Eq(x+y**2, 4)
In [32]: eq2 = Eq(x**2 + y, 4)
In [33]: solve([eq1, eq2], [x, y])
Out[33]:
⎡⎛ ⎛ 5 √17⎞ ⎛3 √17⎞ √17 1⎞ ⎛ ⎛ 5 √17⎞ ⎛3 √17⎞ 1 √17⎞ ⎛ ⎛ 3 √13⎞ ⎛√13 5⎞ 1 √13⎞ ⎛ ⎛5 √13⎞ ⎛ √13 3⎞ 1 √13⎞⎤
⎢⎜-⎜- ─ - ───⎟⋅⎜─ - ───⎟, - ─── - ─⎟, ⎜-⎜- ─ + ───⎟⋅⎜─ + ───⎟, - ─ + ───⎟, ⎜-⎜- ─ + ───⎟⋅⎜─── + ─⎟, ─ + ───⎟, ⎜-⎜─ - ───⎟⋅⎜- ─── - ─⎟, ─ - ───⎟⎥
⎣⎝ ⎝ 2 2 ⎠ ⎝2 2 ⎠ 2 2⎠ ⎝ ⎝ 2 2 ⎠ ⎝2 2 ⎠ 2 2 ⎠ ⎝ ⎝ 2 2 ⎠ ⎝ 2 2⎠ 2 2 ⎠ ⎝ ⎝2 2 ⎠ ⎝ 2 2⎠ 2 2 ⎠⎦
Обратите внимание, что в этом примере SymPy находит все решения и не требует предварительной оценки.
Однако большинство систем нелинейных уравнений не будет иметь подходящего аналитического решения, поэтому использование SymPy, как описано выше, прекрасно, когда оно работает, но не всегда применимо. Вот почему мы в конечном итоге ищем числовые решения, хотя и с числовыми решениями: 1) У нас нет гарантии, что мы нашли все решения или "правильное" решение, когда их много. 2) Мы должны предоставить первоначальное предположение, которое не всегда легко.
Приняв, что нам нужны числовые решения, что-то вроде fsolve
, как правило, сделает все, что вам нужно. Для такого рода проблем SymPy, вероятно, будет намного медленнее, но он может предложить что-то еще, что более точно находит (числовые) решения:
In [50]: from sympy import *
In [51]: x, y = symbols('x, y')
In [52]: nsolve([Eq(x+y**2, 4), Eq(exp(x)+x*y, 3)], [x, y], [1, 1])
Out[52]:
⎡0.620344523485226⎤
⎢ ⎥
⎣1.83838393066159 ⎦
In [53]: nsolve([Eq(x+y**2, 4), Eq(exp(x)+x*y, 3)], [x, y], [1, 1], prec=50)
Out[53]:
⎡0.62034452348522585617392716579154399314071550594401⎤
⎢ ⎥
⎣ 1.838383930661594459049793153371142549403114879699 ⎦