Быстрое решение уравнения с помощью SymPy

Имеется некоторое уравнение, описывающее состав компонентов газа. Количество компонентов N может варьироваться (от 2 до ~50), как и количество корней J этого уравнения (обычно, J<N). На данный момент решение осуществляется следующим образом: Из функции get_sum возвращается строка - уравнение

def Wapor_finder(Wapor_result):
    eq = get_sum(Wapor_result)
    eq2 = sympify(eq, rational=False, strict=False)
    x = symbols('x')
    eq3 = Eq(eq2, rhs=0)
    solution = solve(eq3, x, check=False)
    print(solution)
    Wapor = solution[3]
    return Wapor

Проблема в том, что решение уравнения на всей области (поиск всех корней) занимает большое количество времени - примерно 30 с. Каким способом можно ускорить работу функции? Также стоит отметить, что среди J корней, корень X зачастую один и принадлежит промежутку [0,1].

Пример уравнения, которое находится в переменной eq2:

0.000965315027005431/(42.3383783774312*x + 1) +
0.130558956077151/(15.6212108541903*x + 1) +
0.000143666330482448/(2.37465009061897*x + 1) +
0.000889776726935506/(1.20240098234528*x + 1) -
0.000165767766880803/(1 - 0.495568809808081*x) -
6.13258440394361e^-5/(1 - 0.812262834959418*x) -
8.35671329085777e^-5/(1 - 0.86868121526588*x) -
3.21097701586257e^-5/(1 - 0.94999319995934*x) -
3.04033228739349e^-5/(1 - 0.962130470694144*x) -
3.51696655775184e^-5/(1 - 0.987911954424673*x) -
4.8147821393156e^-5/(1 - 0.996849304206127*x) -
5.92247573833024e^-5/(1 - 0.99873115317542*x) -
2.74857659912139e^-5/(1 - 0.999482399680507*x) -
2.96938154545349e^-5/(1 - 0.999791766145955*x) - 
1.62992744082793e^-5/(1 - 0.999955485170511*x) - 
1.11998924928786e^-5/(1 - 0.999990401149874*x) - 
8.99998645388585e^-6/(1 - 0.999998494876206*x) - 
3.49999886245156e^-6/(1 - 0.99999967498616*x) - 
3.89999979169195e^-6/(1 - 0.999999946587679*x) - 
2.09999999191464e^-6/(1 - 0.999999996149829*x) - 
7.99999999842176e^-7/(1 - 0.99999999980272*x) - 
9.99999999999502e-8/(1 - 0.999999999999502*x) = 0

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Можно представить выражение в виде рациональной функции, взять числитель (многочлен), вычислить его корни. Работает быстро:

import sympy

text = '''
0.000965315027005431/(42.3383783774312*x + 1)
+ 0.130558956077151/(15.6212108541903*x + 1)
+ 0.000143666330482448/(2.37465009061897*x + 1)
+ 0.000889776726935506/(1.20240098234528*x + 1)
- 0.000165767766880803/(1 - 0.495568809808081*x)
- 6.13258440394361e-5/(1 - 0.812262834959418*x)
- 8.35671329085777e-5/(1 - 0.86868121526588*x)
- 3.21097701586257e-5/(1 - 0.94999319995934*x)
- 3.04033228739349e-5/(1 - 0.962130470694144*x)
- 3.51696655775184e-5/(1 - 0.987911954424673*x)
- 4.8147821393156e-5/(1 - 0.996849304206127*x)
- 5.92247573833024e-5/(1 - 0.99873115317542*x)
- 2.74857659912139e-5/(1 - 0.999482399680507*x)
- 2.96938154545349e-5/(1 - 0.999791766145955*x)
- 1.62992744082793e-5/(1 - 0.999955485170511*x)
- 1.11998924928786e-5/(1 - 0.999990401149874*x)
- 8.99998645388585e-6/(1 - 0.999998494876206*x)
- 3.49999886245156e-6/(1 - 0.99999967498616*x)
- 3.89999979169195e-6/(1 - 0.999999946587679*x)
- 2.09999999191464e-6/(1 - 0.999999996149829*x)
- 7.99999999842176e-7/(1 - 0.99999999980272*x)
- 9.99999999999502e-8/(1 - 0.999999999999502*x)
'''

expr = sympy.sympify(text, rational=False, strict=False)
# print(expr)
numer = sympy.numer(sympy.ratsimp(expr))
# print(numer)
solution = sympy.nroots(numer)
print(*solution, sep='\n')
$ time python roots.py
-0.771951952001311
-0.418403363891386
-0.0237288907337462
0.831751455805850
1.95109964842774
0.839505580583856 - 0.0571933498084203*I
0.839505580583856 + 0.0571933498084203*I
0.863830901118666 - 0.112636723077199*I
0.863830901118666 + 0.112636723077199*I
0.906694330419874 - 0.162460480670462*I
0.906694330419874 + 0.162460480670462*I
0.969296556651912 - 0.200266247590756*I
0.969296556651912 + 0.200266247590756*I
1.05040816885601 - 0.21694089834209*I
1.05040816885601 + 0.21694089834209*I
1.14344069499961 - 0.201528815060721*I
1.14344069499961 + 0.201528815060721*I
1.23298803838187 - 0.145571009454562*I
1.23298803838187 + 0.145571009454562*I
1.29312805289712 - 0.0530740362950097*I
1.29312805289712 + 0.0530740362950097*I

real  0m2.333s
user  0m2.296s
sys   0m0.036s
→ Ссылка