25 сентября 2011

Common Lisp. Restas. Maxima. #2

Маленькая завлекушная картинка

В предыдущей заметке мы построили простое web приложение перенаправляющее ввод/вывод консольной программы MAXIMA. С тех пор прошло недели три, и сегодня я рад представить вам графическую web оболочку, с функцией редактирования TeX документов и встраивания в них исполняемых команд MAXIMA. А также система emacs-style клавиатурных сочетаний сделает вашу повседневную математическую работу гораздо приятнее и продуктивнее.



В программе MAXIMA ввод может быть двух видов:
  • слегка расширенный математический язык. Присутствуют присваивание (определение символа), условная конструкция, конструкция цикла.
  • или же s-выражения или по-другому программы на лиспе, использующие api maxima, для задания математических выражений.

Вывод представлен несколькими видами и может быть запрограммирован по своему.
  • по-умолчанию 2d - это такая печать символов, как если бы программа писала математические выражения на бумаге.
    • Пример:
    (%i1) x:12+i^2;
                                         2
    (%o1)                               i  + 12
    (%i2) 
    
  • в строку 1d - это печать в компьютерном формате (совпадает с тем как вы вводите выражения)
    • Пример:
    (%i4) display2d:false;
    
    (%o4) false
    (%i5) x:12+i^2;
    
    (%o5) i^2+12
    (%i6) 
    
  • в TeX/LaTeX - это вывод в TeX/LaTeX формате. Используется большинством современных оболочек.
    • Файлы реализующие:
      • /usr/share/maxima/5.x.x/emacs/emaxima.lisp
      • /usr/share/maxima/5.x.x/emacs/imaxima.lisp
    • Пример:
      (%i6) tex(x:i^2+12);
      $$i^2+12$$
      (%o6) false
      (%i7) 
  • в MathML - это вывод в специфицированной xml форме. Форм вобще две: одна для отображеня, а вторая для передачи смысла. wxMaxima использует свой "диалект" MathML. 
    • Файлы реализующие:
      • /usr/share/maxima/5.x.x/share/contrib/lurkmathml/mathml.lisp
      • /usr/share/maxima/5.x.x/share/contrib/maximaMathML/maximaMathML.lisp
    • Пример: 
      (%i1) load("/usr/share/maxima/5.24.0/share/contrib/lurkmathml/mathml.lisp");
      (%o1)    /usr/share/maxima/5.24.0/share/contrib/lurkmathml/mathml.lisp
      (%i2) mathml(x:i^2+12);   
      <math xmlns="http://www.w3.org/1998/Math/MathML"> <msup><mrow>
       <mi>i</mi> </mrow> <mn>2</mn> </msup> <mo>+</mo> <mn>12</mn> </math>(%o2)                                false
      (%i3)
      
Первым выбором стал формат MathML, как формат, который будет поддерживаться всеми браузерами "из коробки". Однако maximaMathML оказалось предоставляет два формата одновременно представления и содержания, и разделять их руками очень не хотелось. lurkmathml требует вызова дополнительной функции для вывода. Для рендеринга в браузере приходилось извращаться, хотя MathJax впоследствии решил проблему. Я решил себя не ограничивать и попробовать MathJax в связке с LaTeX выводом.

LaTeX вывод лучше всего представлен у imaxima. Данный пакет полностью перекрывает стандартный вывод, заменяя его на LaTeX. Кроме того вокруг вспомогательных меток (%i*, %o*) выставляются специальные символы, на которые можно ориентироваться при визуализации repl-a.

Я остановился на выводе предоставляемом imaxima.lisp.

Далее я подумал, что если красивый вывод сделать возможно, то недалеко и до редактирования документов с интерактивными вычислениями "вычисляемых" частей.

Некоторое время я провел в просмотрах существующих javascript html редакторов, но использовать их не хотелось, все требовали некоторой модификации под мои нужды. Кроме того многие из них по умолчанию копировали интерфейс MS офиса, что навевало тоску. Позже редактор я-таки нашел, и его автором оказался небезызвестный Марижн Хавербеке. Что за редактор и чем знаменит автор? Ответ на этот вопрос вы узнаете в конце статьи.

После продолжительного обдумывания, поисков и вновь обдумывания, я натолкнулся на косвенное мнение специалистов. В.А. Ильина, П.К. Силаев, "Система аналитический вычислений MAXIMA для физиков-теоретиков", цитаты:
"История взаимоотношений MAXIM'ы и Mathematic'и напоминают историю взаимоотношений UNIX и WinXXX."
"Так что конструировалась система [Mathematica], которая "умеет все", но делает это "все" не слишком хорошо ("чтобы хоть как-нибудь работало")."
"Опять-таки, при усовершенствовании системы [Mathematica] основное внимание уделялось оформлению, а не оптимизации работы."
"Под WinXXX (старайтесь не пользоваться WinXXX!) все совершенно аналогично."
"Любой человек набиравший настоящие формулы в TeX и в WinWord, знает насколько просто и быстро набирать команды TeX в любом текстовом редакторе и насколько мучительное занятие пользоватся "сервисом" с кнопочками в WinWord."
"При этом текст будет снабжен "боевой раскраской" - функции MAXIM'ы будут рисоваться одним цветом, переменные другим, комментарии - третьим.(6)...
(6) На взгляд авторов, это скорее недостаток, чем достоинство."
В emacs'e им даже не понравилась цветовая раскраска кода. Очень, кстати интересный вопрос: ориентируется ли программист на цвет текста при поиске необходимого кода?

Так основной особенностью пользовательского интерфейса должна быть функциональность.

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

Установка и запуск

Установите maxima, pdflatex:
$ sudo pacman -S texlive-bin texlive-core texlive-langcyrillic texlive-latexextra maxima sbcl
Скопируйте себе репозитарий. Загрузите quicklisp. Запустите common lisp. В данном случае sbcl. Установите некоторые зависимости.
$ git clone https://filonenko-mikhail@github.com/filonenko-mikhail/restmax.git /path/to/projects/restmax
$ cd /path/to/projects/restmax
$ curl -O http://beta.quicklisp.org/quicklisp.lisp
$ sbcl --load quicklisp.lisp
* (quicklisp-quickstart:install)
* (ql:add-to-init-file)
* (quit)
$ sbcl
* (push #p"/path/to/projects/restmax/" asdf:*central-registry*)
* (ql:quickload :restmax)
* (restas:start :restmax :port 8080)

Теперь откройте в браузере следующий адрес:
http://127.0.0.1:8080/index.html

Если не возникло проблем перед вам должна оказаться страница с кнопками переключения закладок TeX и MAXIMA.

Взаимодействие

На странице находится две закладки TeX и MAXIMA для отображения редактора TeX и MAXIMA repl'а соответственно.

На странице существует небольшая система клавиатурных сочетаний для некоторых функций. Система работает в стиле emacs/stumpwm и имеет префиксную клавишу, по-умолчанию Ctrl + c, и клавишу отмены текущей последовательности сочетаний, по-умолчанию Ctrl + g. Некоторые сочетания используются без префикса.

Для того, чтобы переключиться на вкладку MAXIMA, нажмите Ctrl+C, а затем Ctrl + Shift + m.
Для того, чтобы переключиться на вкладку TeX, нажмите Ctrl+C, а затем Ctrl + Shift + t.
Для просмотра справочника текущих клавиатурных сочетаний нажмите (без префикса) Ctrl + Shift + h.

Текущее клавиатурное сочетание отображается в левом нижнем углу.

TeX

На вкладке TeX на данный момент доступно несколько функций.
  • Открыть TeX документ [Ctrl+c Ctrl+f].
  • Сохранить TeX документ [Ctrl+c Ctrl+s].
  • Сгенерировать файл формате PDF из текущего TeX документа [Ctrl+c Ctrl+c].

Открытие документа TeX осуществляется выбором файле в крайнем левом поле и последующем нажатием кнопки Open.

Сохранение текущего документа осуществляется кнопкой Save.
Генерация PDF - кнопкой Render PDF.
Интуитивно понятно я думаю :)

Кроме того в TeX документе вы можете использовать команды Maxima окружив их тегом \maxima. Внимание: maxima не вставляет символы окружения $$, вы должны это сделать вручную.
Пример:
\maxima{eq:x+y}
После того как вы вставили тег \maxima, вы можете выделить содержимое тега и нажать сочетание Ctrl+c Ctrl+m. Даннная команда отправит выделенный текст в MAXIMA repl и выполнит его.

MAXIMA

Здесь все просто. Вводите команды maxima, нажимайте submit. Submit можно также выполнить из поля ввода команды сочетанием Ctrl+enter (без префикса).

MAXIMA repl использует imaxima.lisp для вывода и MathJax для визуализации выражений. Для того, чтобы просмотреть исходный код TeX выражения нажмите на него правой клавишей мыши и выберите пункт меню Show source. Об остальных функциях MathJax вы можете узнать здесь: http://www.mathjax.org/help/menu/

Пример

В папке /path/to/projects/restmax/example/ есть TeX документ со встроенными командами MAXIMA. Давайте его рассмотрим.
\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T2A]{fontenc}
\usepackage[russian]{babel}

\title{Тест-минимум}

\begin{document}
Решение квадратного уравнения.

Пусть имеется выражение:

$$ \maxima{exp:'(a*x^2+b*x+c)$exp = 0} $$

Необходимо вычислить дискриминант по формуле:

$$ \maxima{discriminant:b^2 - 4*a*c$D = discriminant} $$

\emph{Если дискриминант меньше нуля, решений нет}

\emph{Если дискриминант равен нулю, уравнение имеет один корень, вычисляемый по формуле:}

$$ \maxima{x[1,2] = -b/(2*a)} $$

\emph{Если дискриминант больше нуля, корни уравнения $ \maxima{'x[1]}, \, \maxima{'x[2]}$}:

$$ \maxima{x[1]:(-b+sqrt(D))/(2*a)$ 'x[1]=x[1]} $$
$$ \maxima{x[2]:(-b-sqrt(D))/(2*a)$ 'x[2]=x[2]} $$

Пример решения уравнения:

$$ \maxima{egvars:[a=1, b=3,c=-4]$example1:subst(egvars, exp)$example1=0} $$

Найдем дискриминант:

$$ \maxima{egdiscr:subst(egvars, discriminant)$D = egdiscr} $$

Так как дискриминант больше нуля, находим корни уравнения:

$$ \maxima{'x[1] = subst(append(egvars,[D = egdiscr]), x[1])} $$
$$ \maxima{'x[2] = subst(append(egvars,[D = egdiscr]), x[2])} $$

\end{document}
О структуре и командах TeX документа можно прочесть в книге "Не очень краткое введение в LaTeX 2ε", а мы рассмотрим только код MAXIMA.
\maxima{exp:'(a*x^2+b*x+c)$exp = 0}
Тег MAXIMA не является тегом TeX. Конструкция \maxima{} ограничивает команды, которые будут выполнены в MAXIMA. Вывод последней команды заменит данную конструкцию.

В дальнейшем мы будем рассматривать только команды. Итак первой строкой мы связываем выражение '(a*x^2+b*x+c) с символом exp. Для этого предназначен оператор связывания ":".  Одиночная кавычка используется, как и в лиспе, для запрещения вычисления подвыражения. Мы используем ее, так как в будущем символы a, b, c, x могут быть связаны со значениями и, если они будут вычислятся, мы не получим символьного выражения. Далее мы заглушаем вывод операции связывания символом "$". После чего просто создаем уравнение, левая часть которого представлена выражением exp, а правая нулем. И вывод данной команды будет вставлен в TeX документ. Вы можете это проверить выделив exp:'(a*x^2+b*x+c)$exp = 0 и нажав Ctrl+c Ctrl+m.
Оператор "=" создает уравнение, которое впоследствии может быть разрешено функциями solve, algsys или проверено на истинность функцией is.
discriminant:b^2 - 4*a*c$D = discriminant
Строка аналогичная предыдущей.
x[1,2] = -b/(2*a) 
Мы также можем создавать символы с индексами и использовать их в обычных выражениях.
x[1]:(-b+sqrt(D))/(2*a)$ 'x[1]=x[1]
x[2]:(-b-sqrt(D))/(2*a)$ 'x[2]=x[2] 
В данном случае мы связываем символ x[1] с выражением (-b+sqrt(D))/(2*a). Заглушаем вывод. А затем выводим символ и его выражение.
egvars:[a=1, b=3,c=-4]$example1:subst(egvars, exp)$example1=0
Связываем символ egvars с массивом уравнений. Затем связываем символ example1 с результатом функции subst. Функция subst (substitute) осуществляет подстановку по принципу, все левые части уравнений перечисленных в списке в первом параметре будут заменены в выражении переданном во втором параметре на правые части этих уравнений. Например:
(%i1) subst (a, x+y, x + (x+y)^2 + y);
                                    2
(%o1)                      y + x + a
(%i2) subst (-%i, %i, a + b*%i);
(%o2)                       a - %i b
egdiscr:subst(egvars, discriminant)$D = egdiscr
Так мы нашли дискриминант. Мы использовали символ egvars из предыдущей конструкции. Так можно и нужно делать, так как все конструкции выполняются в рамках одного процесса MAXIMA. Другое поведение обработчика тега maxima было бы нелогично и расточительно. Последние выражения, как вы уже заметили, служат для красивого вывода в результирующий TeX документ.
'x[1] = subst(append(egvars,[D = egdiscr]), x[1])
'x[2] = subst(append(egvars,[D = egdiscr]), x[2]) 
Здесь мы производим вычисления подобные вычислениям выше, кроме того, что список уравнений для подстановки формируется функцией append. Функция append принимает любое количество список и соединяет их в один.

В ближайщем будущем...

Исправить недочеты.

Реализовать:
  • поддержку графики
    • MAXIMA это вывод графиков
    • TeX вставка изображений из файлов
    • интеграция графиков и TeX документов
  • поддержка latex2html, возможно просмотр в окне браузера
    • ссылки на ресурсы содержащие документацию
      Стоит подумать над:
      • снимки вычислений для последующего использования, эдакий pastebin.
      • использование MAXIMA как внутренний, а не внешний процесс
      • справочная система по командам TeX, MAXIMA.
      • хранение файлов на сервере

      Зависимости проекта

      • core
        • maxima
        • pdflatex
      • web
        • jquery [embedded]
        • jquery.form [embedded]
        • MathJax [CDN]
        • CodeMirror [embedded]
      • common lisp
        • restas
        • restas-directory-publisher
        • bordeaux-threads
        • cl-ppcre

      Ответ на вопрос посередине: Марижн Хавербеке является автором библиотеки Postmodern для работы с Postgresql из Common Lisp и редактора кода CodeMirror, написанного на javascript. CodeMirror я использовал в странице для редактирования TeX документа.

      Напоследок несколько вопросов к публике:
      Может у кого-то есть желание предоставить sbcl хостинг для тестирования данного проекта?
      У кого есть время, в папке /path/to/projects/restmax/src/static/script/jquery.emacskeys.js лежит плагин для jQuery для emacs-style клавиатурных сочетаний, его нужно поиспользовать в своих проектах, чтобы отшлифовать.

      Как всегда очень рад услышать отзывы, критику.

      2 комментария:

      1. Не в сильно отдалённом будущем планирую подробно изучить (с экспериментами и прочим) эту и предыдущую статью. Насчёт хостинга: будет! Но к сожалению сильно позже:(

        ОтветитьУдалить
      2. Ну код из статей можно не читать, так как он меняется с добавлением возможностей. Но основные принципы да, кроме того иногда я чего-то могу недопонимать.

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