четверг, 7 апреля 2011 г.

Functional programming


Я тут, как всегда, Америку открыл.

Известно, что программирование в Mathematica основном функциональное. Такой тип программирования, кажется, наиболее естественен для символьных вычислений и, как я подозреваю, более близок к человеческому мышлению, чем традиционное, процедурное программирование. Например, циклы в функциональном программировании не нужны — их роль выполняют меппирование и рекурсия. Я, по крайней мере, уже настолько проникся функциональным программированием, что написание даже маленького кусочка обычного кода (на Фортране или C) вызывает со мне непереносимые страдания, практически несовместимые с жизнью. Всё же совсем без процедур не прожить, и Mathematica на procedural programmimg забила не полностью. Оформляя функции как compound expression и пользуясь отжившим шлаком типа Do, While, ++, If, можно с тем или иным успехом вспоминать молодость. Это однако, как оказалось, плохо сказывается на производительности.

Допустим, у меня есть выборка событий в детекторе, скажем 104 штук, и мне надо каждое из них обработать функцией RestoreEvent. Ну, меппируем функцию на данные, и вот что выходит:

RestoreEvent /@ Sample;// Timing
{6.989, Null}

То есть всё это хозяйство Mathematica прожевала примерно за семь секунд. Перейдем теперь к procedural programming и воспользуемся простым циклом Do, получим вот что:

Do[RestoreEvent[Sample[[i]]], {i, Length[Sample]}];// Timing
{251.162, Null}

Фигасе, да? Пока писал этот пост, левым глазом просматривал что Гугль знает об этой проблеме. Гугль знает. Он мне дал ссылку вот на этот сайт Девида Бейли, где приводятся просто крышесносящие примеры. Например, listable functions по умолчанию работают в двенадцать раз быстрее чем mapping, а неаккуратное обращение к List может привести к внутренней распаковке packed arrays, что увеличит время меппирования ещё в пятьдесят раз — “This is a dramatic illustration of yet another feature of Mathematica programming”. Так что, если пришлось залезть в List ручками, то упаковывайте его обратно функцией Developer`ToPackedArray.

З.Ы. Ну ты, Гриша, дубина. Примеры с производительностью приведены в хелпе для атрибута listable, в разделе Applications.

9 комментариев:

  1. Этот комментарий был удален автором.

    ОтветитьУдалить
  2. Твой пример, Гриша, выглядит очень сомнительно. А вот это сколько работает?

    Do[Sample[[i]], {i, Length[Sample]}];// Timing

    ОтветитьУдалить
  3. Так сколько мой цикл работает?

    ОтветитьУдалить
  4. А, я понял, у тебя написано $10^4$ а не $104$. Но все равно суммы не сходятся :)

    ОтветитьУдалить
  5. Какие суммы? Я действительно первый раз описАлся. На самом деле, мне надо было обработать 100000 событий. Меппинг обрабатывал где-то минуту. Исправил на Do, — всё перестало работать. После это сравнил для выборки в 10000.

    ОтветитьУдалить
  6. > Какие суммы?
    Ну, время на извлечение элемента+ время на твою процедуру RestoreEvent

    ОтветитьУдалить