Реализация алгоритма Метрополиса на Haskell

Я пытаюсь написать программу MCMC на основе алгоритма Метрополиса в Haskell, и у меня возникают проблемы с выборкой из вероятностных распределений (генерация псевдослучайных чисел) и структурированием программы. На данный момент я доволен использованием генератора с жестко запрограммированным начальным числом, чем иметь дело со сложностью работы с вводом-выводом.

Кажется, что я должен использовать монаду состояния, чтобы отслеживать состояние случайного генератора, предыдущее состояние цепи Маркова, значение хи-квадрат и количество приемок между каждым шагом алгоритма, а затем, наконец, собрать все состояния цепи Маркова и последнее принятие считать. Это лучший/идиоматический способ сделать это? и если да, то каким должен быть макет программы (например, тип подписи функции предложения и функции шага города и т. д.).

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

Редактировать: Временно удален WIP-код.


person Tds    schedule 05.04.2014    source источник


Ответы (1)


Вот некоторые отзывы о написании идиоматического Haskell.

  • Если вы не пишете монадический код, использование do в чистых функциях (т.е. constructMuTable, metropolis) очень неидиоматично для Haskell.

    Вместо

    foo = do
        let x = ...
            y = ...
            z = ...
        bar x y z
    

    просто пиши

    foo =
        let x = ...
            y = ...
            z = ...
        in bar x y z
    

    или используйте where вместо let ... in ....

  • эта-уменьшить. В некоторых местах (zVec, muVec, sigmaVec в main) вы написали (\x -> f x). Это эквивалентно просто f по модулю _|_, seq и т. д.

  • используйте Data.Vector.Unboxed. У вас много V.Vector Double, которые хранят упакованные Doubles и могут быть неэффективными. Для примитивных типов, таких как Double, используйте неупакованные векторы для (потенциально) гораздо более быстрого кода, использующего меньше памяти.

  • по возможности избегайте индексации списков с (!!). Вместо этого используйте Data.Vector, так как V.! — это O(1), а (!!) — это O(n).

  • Кажется, вы могли бы использовать монаду State здесь, чтобы очистить свой код. Однако в его нынешней императивной форме мне трудно увидеть трансформацию.

Возможно, вы можете попытаться применить некоторые из рекомендаций, которые я дал, и упростить некоторые из больших, плотных функций, и тогда отзывы более высокого уровня о вашем алгоритме станут более очевидными.

person cdk    schedule 05.04.2014