generic fourth-order Runge-Kutta method
Jun. 22nd, 2016 01:37 pmКогда понадобилось численно просчитать эволюцию системы из ее производной по времени, и наивное решение не заработало, вспомнил слова "Рунге-Кутта", которые со студенческой скамьи не использовал. Быстро находимые описания в интернетах не супер понятные, а конкретные примеры порой слишком частные, но оказалось, что алгоритм можно очень просто выразить в довольно общем виде. Он работает для любого типа (представления состояния системы), для которого даны всего три операции: сложение, умножение на вещественное число и вычисление производной по времени. Такой вот тайпкласс. Например, состоянием может быть набор координат и скоростей точек, тогда сложение и умножение на число делается с координатами и скоростями поэлементно, а производная по времени ставит скорости вместо координат и вычисленные из координат и скоростей ускорения - вместо скоростей. У меня состоянием был массив комплексных чисел - волновая ф-я. Весь код получения состояния системы через шаг времени dt выглядит так:
(тут на Elm'e)
Если выразить на языке с нормальными тайпклассами или ООЯ с определяемыми операторами, получится еще проще. С другой стороны, возможно операцию вычисления производной стоит не вносить в тайпкласс, а передавать явно. Тогда можно для одного типа состояния считать его эволюцию при разных внешних условиях (разных методах вычисления сил/ускорений/операторов/whatever), что у меня активно используется в программе.
type alias DiffVecSpace v = { timeDerivative : v -> v, mulByFloat : Float -> v -> v, add : v -> v -> v } evolveRK : DiffVecSpace v -> Float -> v -> v evolveRK ops dt state = let a = ops.timeDerivative state b = ops.add state (ops.mulByFloat (dt/2) a) |> ops.timeDerivative c = ops.add state (ops.mulByFloat (dt/2) b) |> ops.timeDerivative d = ops.add state (ops.mulByFloat dt c) |> ops.timeDerivative in List.foldl ops.add state [ops.mulByFloat (dt/6) a, ops.mulByFloat (dt/3) b, ops.mulByFloat (dt/3) c, ops.mulByFloat (dt/6) d]
(тут на Elm'e)
Если выразить на языке с нормальными тайпклассами или ООЯ с определяемыми операторами, получится еще проще. С другой стороны, возможно операцию вычисления производной стоит не вносить в тайпкласс, а передавать явно. Тогда можно для одного типа состояния считать его эволюцию при разных внешних условиях (разных методах вычисления сил/ускорений/операторов/whatever), что у меня активно используется в программе.
no subject
Date: 2016-06-22 06:53 am (UTC)а не проще счтать в переменных мпульс-плотность?
Date: 2016-07-02 04:30 am (UTC)Re: а не проще счтать в переменных мпульс-плотность?
Date: 2016-07-02 07:55 am (UTC)Re: а не проще счтать в переменных мпульс-плотность?
Date: 2016-07-02 09:33 am (UTC)пространство импульсов-плотностей....
no subject
Date: 2016-06-22 07:45 am (UTC)лет 12 назад учил этому студентов. с тех пор не пользовался. хотя все могло сложиться и иначе.
no subject
Date: 2016-06-22 08:46 am (UTC)Тут запрограммирован RK-2,3 теоретически даёт качество третьего порядка o(dt^3) при количестве вычислений второго порядка.
Плюс ещё можно оптимизировать, что `a` на следующем шаге получает значение `d` из предыдущего успешного.
no subject
Date: 2016-06-22 12:15 pm (UTC)no subject
Date: 2016-06-22 01:59 pm (UTC)Габриель Гонзалес, помнится, в своё время, наоборот, предлагал вместо тайпклассов носить руками словари: http://www.haskellforall.com/2012/05/scrap-your-type-classes.html
no subject
Date: 2016-06-22 03:15 pm (UTC)Хочется же умножение и сложение как + и * записывать, для чего и хочется хотя бы свои инстансы для number уметь определять.
А еще хочу умножать разные типы (число на вектор, матрицу на вектор и т.п.), т.е. наивных тайпклассов тоже недостаточно для щастья.
А Рунге с Куттом разве не муж и жена?
Date: 2016-06-22 04:58 pm (UTC)У Страуструпа эти мотивы тоже проглядывались в его ранних книгах. А до чего они его довели!