Sympy Solve возвращает пустой набор - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь решить следующие полиномиальные уравнения, используя решение. Однако он возвращает пустой набор.

    `3*d*x**2 + 2*w*x = 0,` 
    `3*d*y**2 + 2*w*y = 0,`
    `-d + 2*w*z + 1 =0,`
    `x**3 + y**3 - z = 0,`
    `x**2 + y**2 + z**2 - 1 = 0`

wolfram-alpha возвращает следующие реальные решения.

    `d≈0.417238, w≈-0.516977, x = 0, y≈0.826031, z≈0.563624`
    `d≈0.417238, w≈-0.516977, x≈0.826031, y = 0, z≈0.563624`
    `d≈0.417238, w≈0.516977, x = 0, y≈-0.826031, z≈-0.563624`
    `d≈0.417238, w≈0.516977, x≈-0.826031, y = 0, z≈-0.563624`
    `d≈0.528689, w≈-0.492358, x≈0.620853, y≈0.620853, z≈0.478626`

Как мне обеспечить что я получу решения, если они существуют? Есть ли другой метод с более надежной обработкой 0 и другими условиями?

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Если вы используете SymPy в качестве расширения для бумаги и карандаша и работаете с уравнениями, как если бы вы решали их вручную, вы обнаружите, что вся система может быть сведена к одному полиномиальному выражению, которое (в данном случае ) имеет явное решение или может быть решена численно; затем решения для этой единственной переменной могут быть возвращены в другие уравнения. Есть некоторые подсказки , что SymPy однажды решит такую ​​систему более автоматически, но я надеюсь, что есть некоторая радость, увидев отношения для себя, как я сделал со следующим:

Определите уравнения

>>> from sympy.abc import *
>>> eqs = (3*d*x**2 + 2*w*x,
... 3*d*y**2 + 2*w*y ,
... -d + 2*w*z + 1 ,
... x**3 + y**3 - z ,
... x**2 + y**2 + z**2 - 1 )

Найдите линейное уравнение в некоторой переменной и решите его, сохраняя решение

>>> reps=[(w,solve(eqs[0],w)[0])]

обновите уравнения

>>> eqs=[i.subs(reps) for i in eqs]; eqs
[0, -3*d*x*y + 3*d*y**2, -3*d*x*z - d + 1, x**3 + y**3 - z, x**2 + y**2 + z**2 - 1]

повтор

>>> reps.append((d, solve(eqs[2],d)[0]))
>>> eqs=[i.subs(reps) for i in eqs]; eqs
[0, -3*x*y/(3*x*z + 1) + 3*y**2/(3*x*z + 1), -3*x*z/(3*x*z + 1) + 1 - 1/(3*x*z + 1), x**3 + y**3 - z, x**2 + y**2 + z**2 - 1]
>>> [cancel(i) for i in eqs]
[0, -(3*x*y - 3*y**2)/(3*x*z + 1), 0, x**3 + y**3 - z, x**2 + y**2 + z**2 - 1]

>>> reps.append((z, solve(eqs[-2],z)[0]))
>>> [cancel(i.subs(reps)) for i in eqs]
[0, -(3*x*y - 3*y**2)/(3*x**4 + 3*x*y**3 + 1), 0, 0, x**6 + 2*x**3*y**3 + x**2 + y**6 + y**2 - 1]

>>> reps.append((x, solve(eqs[1],x)[0]))
>>> [cancel(i.subs(reps)) for i in eqs]
[0, 0, 0, 0, 4*y**6 + 2*y**2 - 1]

пока не будет только 1 уравнения. Это кубический c в y**2, поэтому будет шесть решений

>>> yy=solve(eqs[-1].subs(reps),y)
>>> [i.n(2) for i in yy]
[-0.62, 0.62, 0.55 - 0.71*I, 0.55 + 0.71*I, -0.55 - 0.71*I, -0.55 + 0.71*I]

Теперь создайте полное решение для каждого y

>>> for i in yy:
...     sol=[(y,i)]
...     for v,e in reversed(reps):
...         sol.append((v,e.subs(sol).n(2)))
...     sol[0] = sol[0][0],sol[0][1].n(2)
...     print(sol)
[(y, -0.62), (x, -0.62), (z, -0.48), (d, 0.53), (w, 0.49)]
[(y, 0.62), (x, 0.62), (z, 0.48), (d, 0.53), (w, -0.49)]
[(y, 0.55 - 0.71*I), (x, 0.55 - 0.71*I), (z, -1.3 - 0.59*I), (d, -0.26 - 0.2*I), (w, 0.43 - 0.12*I)]
[(y, 0.55 + 0.71*I), (x, 0.55 + 0.71*I), (z, -1.3 + 0.59*I), (d, -0.26 + 0.2*I), (w, 0.43 + 0.12*I)]
[(y, -0.55 - 0.71*I), (x, -0.55 - 0.71*I), (z, 1.3 - 0.59*I), (d, -0.26 + 0.2*I), (w, -0.43 - 0.12*I)]
[(y, -0.55 + 0.71*I), (x, -0.55 + 0.71*I), (z, 1.3 + 0.59*I), (d, -0.26 - 0.2*I), (w, -0.43 + 0.12*I)]

Это поможет вам в будущем для анализа этого набора уравнений. Решения, которые я создал, предназначены только для демонстрационных целей; более точные решения были бы получены, если вы не оценивали каждое добавление, но ждали до конца, а затем выполнили sol = {k:v.n(2) for k,v in sol} перед печатью.

Работая по уравнениям, вы обнаружите, что в основном у вас есть 4 линейных отношения и полином от одной переменной.

0 голосов
/ 02 мая 2020

Что ж, sympy's solve ищет полностью символические c решения. Текущая версия возвращает пустой список, если уравнения слишком трудно решить символически (без вывода ошибки или предупреждения).

Чтобы получить численное решение c, sympy имеет nsolve, для которого требуется начальная буква угадать, и (в настоящее время) возвращает только одно решение.

from sympy import nsolve, symbols

d, w, x, y, z = symbols('d w x y z', real=True)

nsolve([3 * d * x ** 2 + 2 * w * x,
        3 * d * y ** 2 + 2 * w * y,
        -d + 2 * w * z + 1,
        x ** 3 + y ** 3 - z,
        x ** 2 + y ** 2 + z ** 2 - 1], (d, w, x, y, z), (1, 1, 1, 1, 1))

Сообщаемое решение:

Matrix([[ 0.528689459190352],
        [-0.492357687731282],
        [ 0.620853041008598],
        [ 0.620853041008598],
        [ 0.478626161989451]])
...