Как внутренняя лямбда использует внешнюю лямбда-функцию в этом ODE-решателе RK4? питон

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

from math import sqrt

def RK4(f):
    return lambda t, y, dt: (
        lambda dy1: (
            lambda dy2: (
                lambda dy3: (
                    lambda dy4: (dy1 + 2 * dy2 + 2 * dy3 + dy4) / 6
                )(dt * f(t + dt, y + dy3))
            )(dt * f(t + dt / 2, y + dy2 / 2))
        )(dt * f(t + dt / 2, y + dy1 / 2))
    )(dt * f(t, y))

def theory(t): 
    return (t**2 + 4)**2 / 16

dy = RK4(lambda t, y: t * sqrt(y))

t, y, dt = 0., 1., .1
while t <= 10:
    if abs(round(t) - t) < 1e-5:
        print("y(%2.1f)\t= %4.6f \t error: %4.6g" % (t, y, abs(y - theory(t))))
    t, y = t + dt, y + dy(t, y, dt)

Теперь программа работает отлично и может видеть общий алгоритм работы программы. Но я не могу понять, как работает лямбда-вложение. Если я правильно понимаю все dyN в RK4 являются функциями, которые определены внутри, поскольку они необходимы для этого метода решения ODE. Но я не знаю, как внутренние лямбды используют внешние лямбды в своем определении. Возможно, я неправильно понимаю синтаксис лямбды.

1 ответ

Решение

Здесь происходит то, что лямбда-функции определены и немедленно вызваны. Во-первых, осознайте, что следующее - это просто сложный способ вычисления квадрата y:

( lambda x:
    x**2
)( y )

Вложенность в свою очередь проходит, оборачивает другую lambda вокруг такой конструкции, чтобы изменить свой аргумент. Опять же, следующий будет сложным способом для вычисления квадрата синуса wт.е. (math.sin(w))**2

( lambda z: (
        lambda x: x**2
    )(math.sin(z))
) (w)

Итак, способ прочитать это - применить шаги снизу вверх друг к другу.

Написание lambda-строительство из вашего примера с обычными функциями и без вложенных вызовов, становится:

def step_5(f,dy1,dy2,dy3,dy4):
    return (dy1 + 2 * dy2 + 2 * dy3 + dy4) / 6

def step_4(f,dy1,dy2,dy3):
    return step_5( dy1,dy2,dy3, dt * f(t + dt, y + dy3) )

def step_3(f,dy1,dy2):
    return step_4( dy1,dy2, dt * f(t + dt / 2, y + dy2 / 2) )

def step_2(f,dy1):
    return step_3( dy1, dt * f(t + dt / 2, y + dy1 / 2))

def RK4(f):
    return step_2( dt * f(t, y) )

Оттуда это всего лишь короткий шаг к читабельно написанному методу Рунге-Кутты.

Другие вопросы по тегам