Как стать автором
Обновить

Wolfram Language (Mathematica) — это просто игрушка

Математика *Функциональное программирование *
Я засомневался в своей точке зрения, см. подробнее в одном из UPD.

Хочу поговорить о Wolfram Language (далее WL). Прошу прощения за сумбурность изложения, пост вырос из попытки ответить на этот коммент от Nilis.

WL — это всё-таки узкоспециальный язык. Просто Wolfram решил подзаработать денег, и для этого стал продвигать свой WL ещё и как язык общего назначения. Если вам понравился именно WL — значит, вы просто ещё не познали другие языки. Также замечу, что WL — это не свободное ПО, в отличие от кучи других языков, включая тот же питон.

Лет 6-10 назад, когда я учился в школе, я знал лишь BASIC, Pascal/Delphi, C/C++ и WL. Из ОС имел дело лишь с Windows. Не знал, что такое скриптовые языки (perl, python, bash), не знал самого понятия «скрипт». Думал, что командный интерфейс — это устаревший интерфейс и что единственный правильный интерфейс программы — это графический. Программировал я на Delphi и WL. Программы на Delphi всегда были графическими. За исключением олимпиадного программирования, там в требованиях к программам было, что они должны быть текстовыми, я их писал на Delphi и C++. Когда я узнал о WL, я был им очарован, также как и вы. Потому что код на WL был гораздо короче, чем на Delphi/C++. И вообще, потому что WL был совершенно не похож на Delphi и C++. Потому что там была возможность программировать функционально. Я познакомился с функциональным программированием на примере WL, я не знал, что существуют «стандартные» функциональные языки — Haskell, Lisp и ML.

Когда мне нужно было написать программу для каких-нибудь манипуляций с файлами, я писал её на Delphi. Причём с гуём. Писал окошки, кнопочки. Поля «введите папку, с которой будете работать» и т. д. Я не понимал, что это можно было сделать однострочником на баше.

Например, меня попросили написать программу для конвертации имён файлов в папке с латиницы на кириллицу. Я написал программу с гуём на Delphi. «Введите папку, где нужно сконвертировать». Код, наверное, был на 100 строк как минимум, если не тысячу. Сейчас я понимаю, что это делается одной командой в GNU/Linux типа такой: prename 'y/abc.../абц.../' *.avi.

У меня появилась идея написать файловый менеджер для Windows (разумеется, для Windows, других ОС я не знал), в котором была бы возможность скриптинга на WL (при этом слова «скриптинг» я не знал). Чтобы там, скажем, была функция Flatten из WL, которая бы делала Flatten для папок, т. е. уничтожала всю иерархию папок внутри данной папки и просто сваливала бы все файлы в кучу.

Потом, 6 лет назад я поступил в университет, познакомился с GNU/Linux, начал программировать на C/C++ и bash под GNU/Linux. Я понял, что всё моё программирование на Delphi и WL (кроме математики) — ерунда. Что все мои программы на Delphi можно было реализовать однострочниками на баше. А WL нужно использовать только для математических задач. Я понял, что командный интерфейс — не устаревший. И понял, что та идея файлового менеджера — ерунда. Потому что весь GNU/Linux в целом представляет собой такой файловый менеджер (а заодно и IDE) с возможностью скриптинга на всех скриптовых языках.

Там у нас началось программирование, преподавателя зовут Богачёв. От него (и от других людей) я узнал, что WL — это просто игрушка, причём даже для математических задач. WL нужно использовать, когда нужно по-быстрому построить график какой-нибудь функции или найти производную. Для задач посложнее его использовать нельзя. Потому что:
  • Mathematica и её язык — это просто сборная солянка. Если нравится WL, используйте языки, от которых он произошёл, например, Lisp. Сам пакет Mathematica содержит кучу математических функций, но никакая из них не развита так, как она развита в узкоспециализированных математических пакетах. Например, если вам нужно быстро и точно обратить большую матрицу (например, 1000 x 1000), то WL использовать нельзя (т. к. могут быть ошибки, неоптимизировано, низкая точность, не предназначено для реальных применений). Пишите свою реализацию или используйте узкоспециализированные пакеты, скажем, для C, C++ или Fortran
  • В WL могут быть ошибки. Вероятность ошибок, скажем, в компиляторе C гораздо ниже, т. к., во-первых, есть полно свободных компиляторов C, во-вторых, эти компиляторы по-настоящему широко используются для реальных задач, и ошибки в них сразу становятся заметны
  • WL имеет куда меньшее быстродействие, чем, скажем, C++
  • WL не является математически правильным. Например:
    In[9]:= Simplify[(x^2 + x) / x /. x -> 0]
                                     1
    Power::infy: Infinite expression - encountered.
                                     0
    Infinity::indet: Indeterminate expression 0 ComplexInfinity encountered.
    Out[9]= Indeterminate
    In[10]:= Simplify[(x^2 + x) / x] /. x -> 0
    Out[10]= 1
    

    С математической точки зрения невозможно объяснить, почему в одном случае мы имеем Indeterminate, а в другом — 1. Simplify вообще не должен менять математический смысл выражения. Правильным поведением было бы вообще не упрощать (x^2 + x) / x, и упрощать его только если есть условие, что x не равен нулю. Solve не учитывает всякие частные случаи. Скажем, Solve[x a == b, x] просто выдаёт b/a, не учитывая, что a может быть равно нулю.
  • WL — это не свободное ПО


Богачёв помимо своей преподавательской деятельности работает в одной фирме техническим директором, и я там у него работал. Мы там делали симулятор месторождения нефти, я думаю, не нужно пояснять, что деньги в этой области крутятся огромные. Так вот, симулятор написан на C++, в том числе код, выполняющий расчёты (решение диффуров и систем линейных уравнений). И разумеется, не на WL, потому что нет нужного быстродействия, нет должного доверия к этому WL, и вообще WL здесь было бы использовать несерьёзно.

Затем я познакомился с формальной математикой, в том числе с системой Isabelle. Так вот, я вам скажу, что формальная математика — это единственный способ проводить математические манипуляции на компьютере так, чтобы быть уверенным в их математической правильности. И всех этих косяков с Simplify, Solve и т. д. в формальной математике нет.

Но такие системы (т. е. системы для работы с формальной математикой) не похожи на WL. Работа с ними происходит так: вы вводите в систему формальное доказательство, а она вам говорит, правильное оно, или нет. Возникает вопрос: можно ли смешать способ работы WL с правильностью формальной математики? Да, можно.

Mathematica, Maple и т. д. относятся к так называемым системам компьютерной алгебры. Так вот, все такие системы грешат отсутствием математической строгости. В связи с этим существует идея написания по-настоящему правильной системы компьютерной алгебры, основанной на формальной математике. Вот здесь специалисты в формальной математике показывают результаты первых экспериментов в этом направлении: www.cs.ru.nl/~freek/pubs/holcas.pdf, прочитайте, пожалуйста, хотя бы первые две страницы.

Итак, по поводу математики на WL: если нужно по-быстрому построить график, вычислить производную и т. д. — юзайте WL. Если серьёзные математические вычисления — пишите код сами на языках общего назначения (типа C++), как это делает Богачёв, либо используйте профессиональные библиотеки, опять-таки для языков общего назначения. Если нужно проводить математические манипуляции, которые не являются вычислением, т. е. не являются численными — то делайте ваши манипуляции вручную, либо с использованием формальной математики (например, Isabelle), либо с использованием формальных систем компьютерной алгебры, например, представленной в статье выше (правда, такие системы на данный момент находятся на начальной стадии развития).

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

Итог. WL — это просто игрушка. Это инструмент студента, но не учёного. Вряд ли, скажем, данные с Большого андронного коллайдера обсчитываются на WL. WL как 1С: плохой, узкоспециализированный, коммерческий, несвободный язык.

Если что-то заинтересовало в этом посте (формальная математика, функциональное программирование, и т. д.), спрашивайте, я отвечу.

UPD от 20 июля 2015 г. Почему WL похож на Lisp: habrahabr.ru/post/263015/#comment_8506383.

UPD от 22 июля 2015 г. Ещё немного про схожесть WL и Lisp, а именно про принцип «программа — это данные»: habrahabr.ru/post/263015/#comment_8506389.

Немного про области, где можно применять WL и про заголовок этого поста. Мне не нравится, что есть много людей, которые серьёзно воспринимают WL. Т. е. которые воспринимают его как инструмент, который может играть главную роль в научном исследовании, или, того хуже, как язык общего назначения. Людей, которые очарованы достоинствами WL (как я в своё время), и не знают, что, скажем, WL — это далеко не единственный функциональный язык программирования. Которые не знают, что вообще-то есть скриптовые языки программирования (Perl, Python, Bash) и что есть функциональные, с которых этот WL содран (Lisp, Haskell, ML). Так вот, чтобы раскрыть этим людям глаза, я и написал свой пост. И чтобы быть максимально убедительным, я использовал кричащий заголовок («WL — игрушка»). Я, конечно, понимаю, что WL всё-таки имеет свою область применения. Он нужен для создания прототипов, для того чтобы по-быстрому найти производную и т. д., для того, чтобы провести некие расчёты там, где ошибки не критичны (скажем, при выполнении домашних заданий в вузе и написании курсовых), для того, чтобы провести некие расчёты, которые будут потом проверены другим, более надёжным способом. Мой коммент на эту тему: habrahabr.ru/post/263015/#comment_8506387.

Мой коммент про численные и аналитические задачи: habrahabr.ru/post/263015/#comment_8507849.

Про кучу подробностей из моей жизни и Windows vs GNU/Linux. Я написал про GNU/Linux и т. д. не потому, что я хотел сказать, что GNU/Linux лучше Windows, а гуй лучше текстового интерфейса. И про Богачёва я написал не для того, чтобы его пропиарить. Просто я хотел немного рассказать о своей жизни, чтобы сделать мой рассказ более убедительным, чтобы было понятно, как менялись мои представления. И я не считаю, что GNU/Linux сильно превосходит Windows в техническом плане. И я понимаю, что GUI и CLI — это просто два разных интерфейса со своими применениями.

Про свободное ПО. Конкретно в случае WL его несвободность является существенным минусом, т. к. понижает доверие к полученным результатам.

UPD от 26 июля 2015 г. Пример с Simplify и другие примеры. Я немного неудачно рассказал тот пример с Simplify. Я имел в виду следующее: Simplify[(x^2 + x) / x] — это x + 1, и это неправильно, т. к. не учитывается случай, когда x равен нулю. Далее, x/x схлопывается просто в 1, хотя, опять-таки не учитывается, что x может быть равен нулю. Далее, очень показательный, на мой взгляд, пример прямо из документации WL ( reference.wolfram.com/language/ref/Simplify.html ):
In[5]:= hiddenzero = x^2 + 2 x + 1 - (x + 1)^2; anotherhiddenzero = Sin[x]^2 + Cos[x]^2 - 1; betterhiddenzero = Gamma[x + 1] - x Gamma[x];
In[6]:= {hiddenzero/anotherhiddenzero, anotherhiddenzero/hiddenzero,
        hiddenzero/betterhiddenzero, betterhiddenzero/hiddenzero}
Syntax::sntxf: "hiddenzero/anotherhiddenzero" cannot be followed by ", anotherhiddenzero/hiddenzero, ".
Syntax::sntxf: "" cannot be followed by "hiddenzero/anotherhiddenzero, anotherhiddenzero/hiddenzero, ".
In[8]:= Map[Simplify, {hiddenzero/anotherhiddenzero, anotherhiddenzero/hiddenzero, hiddenzero/betterhiddenzero, betterhiddenzero/hiddenzero}]
                                      2         2
                           -1 + Cos[x]  + Sin[x]
Simplify::infd: Expression ----------------------- simplified to Indeterminate.
                                      2          2
                           1 + 2 x + x  - (1 + x)
                           -(x Gamma[x]) + Gamma[1 + x]
Simplify::infd: Expression ---------------------------- simplified to ComplexInfinity.
                                        2          2
                             1 + 2 x + x  - (1 + x)
Out[8]= {0, Indeterminate, 0, ComplexInfinity}
In[9]:= Map[FullSimplify, {hiddenzero/anotherhiddenzero, anotherhiddenzero/hiddenzero, hiddenzero/betterhiddenzero, betterhiddenzero/hiddenzero}]
                                          2         2
                               -1 + Cos[x]  + Sin[x]
FullSimplify::infd: Expression ----------------------- simplified to Indeterminate.
                                          2          2
                               1 + 2 x + x  - (1 + x)
                               -(x Gamma[x]) + Gamma[1 + x]
FullSimplify::infd: Expression ---------------------------- simplified to ComplexInfinity.
                                            2          2
                                 1 + 2 x + x  - (1 + x)
Out[9]= {0, Indeterminate, 0, ComplexInfinity}

Пример был приведён в разделе Possible Issues, вообще, я вам скажу, это отличное место, где можно искать всякие нелогичности WL. Далее, берём пример из статьи выше (про формальную математику) и переносим его из Maple в WL, немного изменив:
In[11]:= N[Integrate[E^(-(x-1)^2)/Sqrt[x], {x, 0, Infinity}]]
Out[11]= 0. + 0.411862 I
In[12]:= NIntegrate[E^(-(x-1)^2)/Sqrt[x], {x, 0, Infinity}]
Out[12]= 1.97373

У меня сильное подозрение, что ответ, полученный NIntegrate[...], правильный, а N[Integrate[...]] — нет. Т. к. NIntegrate выполнил внутри себя простой тупой алгоритм численного дифференцирования. В отличие от Integrate, который представляет собой неведомого монстра алгебраических манипуляций без формальной строгости, подверженного ошибкам. Окончательно я поверю, что один из этих результатов правильный, только если самостоятельно напишу программу на C/C++, которая будет численно интегрировать. Либо если найду (или, как минимум, проверю) этот интеграл на бумажке. (А ещё этот интеграл, очевидно, должен быть действительным.)

И, наконец, я засомневался в своей позиции, вы на меня повлияли, господа комментаторы. Возможно (возможно!), WL действительно качественный продукт, пригодный для серьёзных научных и прочих применений. При этом я не меняю своё мнение на противоположное, окончательно решить для себя, хороший WL или нет, я смогу только хорошенько его поиспользовав, но этого я делать сейчас не хочу.

И всё же добавлю: если вы хотите получать достоверные результаты на WL, вам нужно уметь его использовать (впрочем, то же самое относится к любой другой технологии). Например, понимать, как на WL происходит работа со всякими частными случаями вроде нулевого знаменателя (см. примеры в этом посте выше). Далее, важно понимать, что WL — это высокоуровневый язык, что работать с математикой на компьютере можно и с помощью низкоуровневых языков (вроде C++) тоже. И наконец, важно знать, что WL — это не единственный язык, позволяющий писать относительно сжатый код, что существуют скриптовые языки (Perl, Python, Bash). И что WL — не единственный язык, поддерживающий функциональное программирование, что существуют Lisp, ML и Haskell.

Я люблю Хабр, Хабр покажет тебе, насколько ты не прав! :)

Приведённые примеры были на Mathematica 10.0.2.

UPD от 26 июля 2015 г. Как правильно заметили тут, «почти вся ценность этого поста в комментариях». :)

UPD от 26 июля 2015 г. Баг с Integrate исправлен.
Теги:
Хабы:
Всего голосов 77: ↑44 и ↓33 +11
Просмотры 56K
Комментарии Комментарии 110