Проблема с функцией SymPy diff()

Я работаю над реализацией различных численных методов на питоне, включая обратный Эйлер. Таким образом, я решил реализовать быстрый метод Ньютона-Рафсона, который дал бы мне желаемый корень для уравнений с переменными, с которыми придется иметь дело моему калькулятору. Вот:

def Newton(y0, f, tol=1e-10):
    y = Symbol('y')
    df = diff(f, y)
    while f.subs(y, y0) > tol:
        y0 -= f.subs(y, y0)/df.subs(y, y0)
    return y0

Фрагмент кода, связанный с вызовом функции Newton():

def InverseEuler(f, y0, t0, tf, h):
    coords = [[t0, y0]]
    t, y = symbols('t y')

    while round(t0, 7) < round(tf, 7):
        aux = sympify(y0 - y + h*f.subs(t, t0 + h))
        print aux
        y0 = utils.Newton(y0, aux)
        t0 += h
        coords.append([t0, y0])
    return coords

Где f — это «упрощенная» строка. В моем неудачном тестовом случае это было: f = sympify('(y**2 + t)/(y - t)')

Как видите, я печатаю содержимое aux, чтобы отследить, где именно происходит сбой функции diff. Это было в первой итерации для y(0) = 1 с h = 0,1, где aux было: -y + 1 + 0.1*(y**2 + 0.1)/(y - 0.1). При передаче aux как f в Newton() и последующем запуске diff(f, y) это дает мне:

Traceback (most recent call last):
  File "C:\Users\Gabriel Vasconcelos\Documents\python\Metodos\metodos.py", line 97, in <module>
    GPHandler.replot(InverseEuler(f, 1, 0, 4, 0.1))
  File "C:\Users\Gabriel Vasconcelos\Documents\python\Metodos\metodos.py", line 31, in InverseEuler
    y0 = utils.Newton(y0, aux)
  File "C:\Users\Gabriel Vasconcelos\Documents\python\Metodos\utils.py", line 6, in Newton
    df = diff(f, y)
  File "C:\Python27\lib\site-packages\sympy\mpmath\calculus\differentiation.py", line 188, in diff
    values, norm, workprec = hsteps(ctx, f, x, n, prec, **options)
  File "C:\Python27\lib\site-packages\sympy\mpmath\calculus\differentiation.py", line 61, in hsteps
    values = [f(x+k*h) for k in steps]
TypeError: 'Add' object is not callable

Удивительно, но когда я вручную «упрощаю» это же уравнение и «дифференцирую» его, оно работает. Метод Ньютона также работает как шлейф. Тем не менее, я не знаю, что может быть не так.


person Gabriel Vasconcelos    schedule 06.11.2014    source источник


Ответы (1)


Похоже, вы используете mpmath diff вместо SymPy. Попробуйте "from sympy import diff", прежде чем вызывать свою процедуру. Вы можете проверить, какой из них вы используете, обратившись за помощью:

>>> help(diff)
Help on method diff in module sympy.mpmath.calculus.differentiation:

vs

>>> from sympy import diff
>>> help(diff)
Help on function diff in module sympy.core.function:

Когда я запускаю вашу программу с разницей SymPy, я получаю

>>> InverseEuler(f,1, 0, 1, 0.1)[-1]
-y + 1 + 0.1*(y**2 + 0.1)/(y - 0.1)
-y + 1.13404207225556 + 0.1*(y**2 + 0.2)/(y - 0.2)
-y + 1.30637177730098 + 0.1*(y**2 + 0.3)/(y - 0.3)
-y + 1.52036600337727 + 0.1*(y**2 + 0.4)/(y - 0.4)
-y + 1.77886566311632 + 0.1*(y**2 + 0.5)/(y - 0.5)
-y + 2.08466045990054 + 0.1*(y**2 + 0.6)/(y - 0.6)
-y + 2.44089877798719 + 0.1*(y**2 + 0.7)/(y - 0.7)
-y + 2.85134771320082 + 0.1*(y**2 + 0.8)/(y - 0.8)
-y + 3.32053168504081 + 0.1*(y**2 + 0.9)/(y - 0.9)
-y + 3.85380349564978 + 0.1*(y**2 + 1.0)/(y - 1.0)
[0.99999999999999989, 4.45738956363267]
person smichr    schedule 06.11.2014
comment
Спасибо! Мне нужно привыкнуть к этим конфликтам... Естественно, поменяв местами, где я импортировал sympy, и где я импортировал mpmath, все заработало нормально! - person Gabriel Vasconcelos; 07.11.2014