Как внутренняя лямбда использует внешнюю лямбда-функцию в этом 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) )
Оттуда это всего лишь короткий шаг к читабельно написанному методу Рунге-Кутты.