КДПВ
КДПВ

Wolfram Language JavaScript Frontend - это проект, цель которого в создании бесплатной альтернативы для Mathematica с открытым исходным кодом, но со своими особенностями и преимуществами, а если точнее то в реализации пользовательского интерфейса для ядра Wolfram Language (WL). Ядро входит в состав Математики либо распространяется в виде бесплатной утилиты командной строки - Wolfram Engine. То есть данное приложение это именно пользовательский интерфейс для WL, а не попытка полностью переписать язык. Ниже будет демонстрация возможностей, а так же отличия от Mathematica и других приложений. Вам это точно будет интересно, если вам нравится подход к программированию, который используют такие платформы как Mathematica, Jupyter, NTeract, JupyterLab, DeepNote, ObservableHQ, Google Collab и некоторые другие.

Внимание! В статье много изображений!

Установка

Главным системным требованием является наличие Wolfram Engine или Mathematica. Если ни одного из перечисленных приложений все еще не установлено на ваш компьютер по каким-то необъяснимым причинам, то вы всегда можете получить бесплатную версию Wolfram Engine следуя инструкциям на странице: https://www.wolfram.com/engine/. А еще можно установить ядро используя пакетный менеджер или скачав docker-образ вот так:

brew cask install wolfram-engine # macOS
winget install WolframEngine # Windows
docker pull wolframresearch/wolframengine # docker

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

wolframscript

После успешной активации переходим на страницу с релизами WLJS и загружаем установочный файл. Запускаем установщик - сначала приложение распакуется в директорию пользователя, а затем запустится. Примерно так же, как это происходит с другими приложениями на electron. Далее нужно немного подождать пока загрузятся все зависимости и откроется вот такое окно:

Стартовое окно Wolfram Language JavaScript Frontend (WLJS)
Стартовое окно Wolfram Language JavaScript Frontend (WLJS)

Главное меню

Оно интуитивно понятно и работает примерно так, как этого ожидает пользователь от большинства приложений рабочего стола.

  • File - позволяет создать, открыть, сохранить, экспортировать блокнот...

  • Edit - вырезать, вставить, удалить, выбрать...

  • Window - перезагружает окно и управляет размерами...

  • Evaluation - выполняет код ячеек, останавливает вычисление и управляет ядром...

  • Misc - настройки и информация...

Особенно стоит отметить пункт File > Share, который позволяет экспортировать блокнот в HTML-файл, где будет сохранена вся разметка и интерактивные элементы. Конечно же только те, которые не требуют подключения к ядру.

Чтобы создать блокнот с демонстрацией возможностей перейдем в меню File > New или нажмем сочетание клавиш CTRL + N. После чего слева - в области навигации появится новый файл со случайным именем и расширением .wln - Wolfram Language Notebook.

Навигация

Новый файл в навигаторе и контекстное меню
Новый файл в навигаторе и контекстное меню

В навигации по файлам и директориям тоже все очень просто и интуитивно понятно. Директории можно открывать. Файлы после нажатия левой кнопкой мыши открываются на главной панели, а после нажатия правой кнопкой мыши - появляется контекстное меню, где файл можно открыть в отдельном окне, переименовать, копировать, удалить, показать в файловом менеджере. Боковую панель навигатора сворачивается при помощи кнопки "<<". После перехода в любую директорию вернуться на уровень вверх можно нажав на верхнюю строчку в списке навигатора с именем "../". На скриншоте наш новый файл уже открыт на главной панели окна. В нем пока ничего нет, кроме одной пустой ячейке с небольшой подсказкой - как в редакторе статей Хабра.

Ячейки

Пустая ячейка и всплывающие кнопки управления
Пустая ячейка и всплывающие кнопки управления

Все блокноты состоят из списка ячеек и внутренних метаданных. Больше в них ничего нет. Ячейки бывают разных типов. В первую очередь они делятся на ячейки ввода (input) и ячейки вывода (output). Пользователь при помощи клавиатуры и мыши по умолчанию может создавать только ячейки ввода. Делается это либо при помощи клика мышью в область между ячейками документа, либо двойным нажатием клавиши в последней ячейке. Еще один способ создания новой ячейки - нажатие на всплывающую кнопочку + при наведении на область слева от существующей ячейки. Для удаления сначала нужно удалить весь текст, а затем нажать клавишу BACKSPACE.

В ячейках с выводом появляется результат выполнения вашего кода. Что там будет - зависит от того, что пользователь ввел. Это может быть график, текст, разметка и многое другое. Чтобы создать такую ячейку - достаточно нажать сочетание клавиш SHIFT + ENTER в любой ячейке ввода (если там есть код конечно). После чего приложение прочитает код ячейки, отправит его интерпретатору, дождется ответа и ниже напечатает результат. Вот например какой результат будет при выполнении вот такого кода:

Graphics3D[Table[{RandomColor[], 
  Sphere[RandomReal[1, 3], 0.05 + RandomReal[]/10]}, {25}]]
Случайные сферы
Случайные сферы

Обратите внимание на другие всплывающие кнопки. В левом нижнем углу есть стрелочка вниз, которая позволяет скрыть input, а в правом верхнем углу есть еще 4 кнопки по порядку: удалить output, сделать ячейку инициализирующей, открепить результат от окна и выполнить код (альтернатива SHIFT + ENTER). Если выполнить код повторно - то результат будет заменен на новый. В общем-то это и есть основная функциональность приложения - интерактивные ячейки с кодом, которые сразу же показывают пользователю результат. На этом мы и остановимся более подробно.

Wolfram Language

Это основной язык программирования, который здесь поддерживается. Ведь на нем написан весь бэкенд, а также изначально цель была именно в поиске бесплатного аналога Mathematica. Чтобы писать на этом языке нечего дополнительно делать не надо - просто выполнить код в ячейке. Например ниже демонстрация того, как можно решить уравнение:

Solve[x^2 + 9 * x - 1 == 0, x]
Решение квадратного уравнения
Решение квадратного уравнения

На анимации выше видно, что текстовый вывод печатается в форматированном виде. Корни уравнения содержат знак радикала, а рациональные числа отображаются в виде дробей. Здесь стоит отметить, что все это возможно благодаря использованию JavaScript библиотек CodeMirror и wljs-interpreter. Именно она позволяет отображать форматированный вывод так, что под этим выводом прячется совсем другой код без форматирования - т.е. позволяют создавать синтаксический сахар. Причем математические формулы - это лишь малая и самая очевидная часть этого синтаксического сахара.

Стоит отметить, что концепция отображения математических формул здесь наиболее похоже на то, как это же происходит в Mathematica, но отличается от других инструментов с "ноутбучным" интерфейсом таких как Jupyter, DeepNote, Observablehq, nteract и т.д. Все формулы представляют собой не просто красивую разметку, а являются редактируемыми выражениями на WL, которые можно изменять прямо в ячейках вывода.

Редактирование формулы как выражения WL
Редактирование формулы как выражения WL

С помощью такого же синтаксического сахара реализованы не только формулы, но и любые другие объекты и они тоже поддерживаются редактором:

Замена сферы на куб в output-ячейке
Замена сферы на куб в output-ячейке

Markdown

Кроме поддержки Wolfram Language те же самые ячейки ввода работают и с другими языками программирования и языками разметки. Для того, чтобы указать приложению, что в ячейке находится что-то, что нужно интерпретировать другим образом - в начале ячейке нужно ввести точку, затем имя языка и на следующей строке вводить уже сам код или разметку. Например, для markdown это будет выглядеть вот так:

.md
# Demo notebook for Habr
## Markdown cells
_you_ *can* __hide__ **the** input cell using the ~pop-up~ `buttons` 
on the [left side]()
## Supported languages
* Wolfram
* ect..
## Wolfram code example
```wolfram
Plot[Sin[x], {x, 1, 2}]
```

Далее нужно просто выполнить эту ячейку и в output появится форматированный текст:

Если в первой строке .md - подсветка синтаксиса меняется
Если в первой строке .md - подсветка синтаксиса меняется

Такой способ ввода можно представить так, будто бы блокнот - это редактор файлов и указывая в начале "расширение" мы создаем анонимный файл, текст которого начинается со следующей строки. Ниже мы еще раз вернемся к этому сравнению, а пока перейдем к другим поддерживаемым языкам.

JavaScript

Этот язык поддерживается по очевидным причинам - ведь приложение на самом деле является веб-страницей упакованной в electron. Как и в предыдущем случае достаточно ввести "расширение" в первой строке, а далее можно писать код на JS. Ниже пример рисования окружностей по клику мыши:

.js
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 400;
let x, y
const handleDrawCircle = (event) => {
  x = event.pageX;
  y = event.pageY;
  drawCircle(x, y);
};
const drawCircle = (x, y) => {
  context.beginPath();
  context.arc(x, y, 50, 0, 2 * Math.PI);
  context.strokeStyle = 'red';
  context.stroke();
};
canvas.addEventListener('click', handleDrawCircle);
return canvas; 

Вот как это выглядит в самом блокноте:

Код слегка "обфусцирован" чтобы можно было рассмотреть результат
Код слегка "обфусцирован" чтобы можно было рассмотреть результат

Важные особенности выполнения JavaScript внутри блокнота:

  • В конце ячейки нужно писать return чтобы указать, что печатать в output

  • Весь код по сути оборачивается в function и имеет локальную область видимости только внутри ячейки. Т.е. любые объявленные функций и переменных видны только в одной ячейке

  • Чтобы создать глобальные функции и переменные используйте объект window.

JS дает полный доступ ко всему документу. С помощью скриптов в ячейках можно изменить весь интерфейс до неузнаваемости. Но можно и полностью сломать первым же скриптом.

HTML

Если markdown разметка не позволяет сделать то, что вы хотите - в ячейках можно использовать HTML. Все работает точно так же при помощи указания в первой строке .html. Вся разметка из ячейки ввода вставляет в ячейку вывода как фрагмент страницы:

.html
<button>click me!</button>
кнопка и выпадающий список как результат выполнения
кнопка и выпадающий список как результат выполнения

У HTML ячеек есть одно очень важное преимущество. Код, который встраивается в разметку выполняется к глобальной области видимости. Это может быть полезно для создания JavaScript функций доступных во всем документе. Но еще полезнее то, что из HTML разметки можно импортировать сторонние скрипты и стили, а так же изменять стили текущего документа. Вот так например я могу добавить закругленную рамку для всех ячеек с кодом:

.html
<style>
  .cm-editor {
    border-radius: 5px;
  }
</style>
Теперь углы пунктирной рамки закруглены для всего документа
Теперь углы пунктирной рамки закруглены для всего документа

WolframScript Pages

И самая важная особенность HTML-ячеек. Они по умолчанию поддерживают синтаксис WolramScript Pages (WSP). Более подробно про саму технологию WSP можно почитать на странице проекта, но если коротко - то это расширение синтаксиса XML специальным тегом <?wsp code[] ?>, который вставляет в разметку выражение на WL - т.е. примерно так же, как это работает в PHP.

красный круг в HTML со светло-голубым фоном
красный круг в HTML со светло-голубым фоном

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

randomFigure[] := 
Graphics[{{RandomColor[], RandomChoice[{Disk, Circle, Rectangle}][]}}, 
  ImageSize -> 60
]
.html
<ul><?wsp Table[ ?><li><?wsp randomFigure[] ?></li><?wsp , {i, 1, 4}] ?></ul>
случайные фигуры в HTML
случайные фигуры в HTML

Wolfram Language XML Extension

Еще одна технология, которая смешивает код на WL с разметкой страницы. Только теперь это похоже на на PHP, а на JSX. Т.е. все это работает наоборот - мы пишем WL-код и можем добавлять в него разметку. Более подробно об этой технологи можно почитать на странице документации, а чтобы создать ячейку в первой строке пишем .wlx. Ниже пример графика с заголовком и все это в одной ячейке:

.wlx
Heading[Text_] := <h2 class="tracking-tight"><Text/></h2>;
Graphics1 = Plot[Sin[x], {x, -4, 4}, ImageSize -> 350]; 

<body>
  <Heading>
    Hello World!
  </Heading>
  <Graphics1 />
</body>

Обратите внимание на важные особенности:

  • Объявленные в документе функции на WL доступны внутри разметки WLX

  • Возвращать нужно результат заключенный в один общий тег

  • Все теги разметки HTML всегда начинаются со строчной буквы

  • Все теги, которые преобразуются в результат выполнения WL - с большой

  • Для вставки переменной используется <Name />

  • Для вставки функции:<Func>arg1 arg2</Func>

  • Вы можете легко импортировать скрипты и стили

Mermaid

Здесь все просто. Поддержка диаграмм на языке Mermaid работает на основе JavaScript библиотеки. Вот например схема, которая описывает backend приложения:

.mermaid
flowchart TD    
    A[Frontend]-- HTTP+WS ---B(marster kernel)
    B---|WSTP+JTP|C[[sub kernel]]
    C-->|WS|A 
упрощенная схема работы приложения
упрощенная схема работы приложения

Slides

Еще один "язык" разметки, который поддерживается при помощи библиотеки RevalJS. В первой строке указываем тип ячейки .slide или .slides, а дальше можно использовать правила написания презентаций RevalJS. Самые простые презентации создаются при помощи .md разметки и использования HTML. Вот пример:

Graphics1 = Plot[Sin[x], {x, -2, 2}]; 

Graphics2 = Plot3D[Sin[x] + Cos[y], {x, -2, 2}, 
{y, -2, 2}]; 
.slide

# Slide 1

2D graphics

<Graphics1 />

---

# Slide 2

3D graphics

<Graphics2 />
после выполнения слайд напечатается в output ячейке
после выполнения слайд напечатается в output ячейке

Обратите внимание, что HTML в разметке слайдов по умолчанию поддерживает WLX, а это значит, что в процессе написания презентации можно создавать различные объекты: графики, картинки и диаграммы на языке Wolfram и вставлять их прямо в презентацию. После того как ячейка с результатом напечатается - ее нужно "открепить" чтобы перейти в режим показа слайдов:

слайды в открепленной ячейке
слайды в открепленной ячейке

ChatGPT

Мы не смогли совладать с соблазном и не присоединиться к общей волне хайпа - поэтому добавили возможность общения с моделью GPT3.5 прямо из ячеек блокнота. Для этого моно просто ввести в первой строке .llm а на следующей строке любой текст:

.llm
how to sort array in Mathematica?
текст форматированный как код в MD автоматически превращается в input
текст форматированный как код в MD автоматически превращается в input

В ячейках-диалогах с нейросетью есть пара интересных особенностей:

  • Ответ нейросети печатается в виде набора пар ячеек: input + output

  • Если где-то текст плохой - вы легко можете отредактировать input и перевыполнить

  • Если нейросеть отвечает кодом в разметке .md - он превращается в input без output

  • Весь вывод печатается выше ячейки ввода, тем самым симулирую работу ассистента, который заполняет вместе с вами сверху вниз input-ячеки и выполняет в них код.

  • Когда первая ячейка ввода смещается в самый низ - это становится похоже на обычный диалог или интерфейс ChatGPT.

Files

В самом начале обзора было сравнение с анонимными файлами внутри ячейки. Так вот ячейки могут не только создавать "анонимные файлы в блокноте", но и читать существующие файлы! Для этого в первой строке необходимо ввести имя файла и выполнить ячейку. Например, ниже мы экспортируем картинку, а затем напечатаем ее в следующе ячейке:

Export["bubbleChart.png",BubbleChart[RandomReal[1, {5, 7, 3}]]]
bubbleChart.png
просмотр картинки как вызов из ячейки
просмотр картинки как вызов из ячейки

А еще можно записывать текстовые файлы вот так:

file.txt
col1, col2, col3
1, 2, 3
4, 5, 6

Затем читать их

file.txt

И после этого они будут доступны для импорта функциями Mathematica:

Import["file.txt", "CSV", HeaderLines -> 1]
создание и чтение текстового файла
создание и чтение текстового файла

Заключение и КДПВ

На этом мы закончим обзор возможностей бесплатного интерфейса для Wolfram Language. В статье удалось рассмотреть далеко не все возможности приложения, а только самые основные (даже не все поддерживаемые типы ячеек). Кроме создания самого интерфейса мы (разработчики) так же добавляем свои полезные функции и плагины. Результат такой функции уважаемые читатели могли видеть на КДПВ. На рисунке кроме логотипа и текста есть реальный скриншот блокнота с 3D изображением Спайки - многогранника-символа языка Wolfram. Его различные вариации уже более 35 лет являются символом Wolfram Mathematica и компании Wolfam Research. Так что же такого особенного в этом многограннике? Дело в том, что на скриншоте построен этот многогранник при помощи Graphics3D, но при этом с использованием трассировки лучей и собственного освещения (чего никогда до сих пор не было в WL без использования OpenCL или CUDA). Вот код, который позволяет построить 3D график где будет Спайки и трассировка лучшей:

Graphics3D[{{Red, N@PolyhedronData["Spikey", "Polygons"]}}, 
  Boxed->False,"RTX"->True,"Lighting"->None,
  ImageSize->{500, 400},"ViewProjection"->"Perspective", 
  "Lightmap"->"https://raw.githubusercontent.com/JerryI/Mathematica-ThreeJS-graphics-engine/master/assets/PureSky.hdr"
]
Спайки с трассировкой лучей
Спайки с трассировкой лучей

На этом точно все! Всем спасибо за внимание и увидимся в следующих статьях и обзорах! Наш проект находится в стадии активной разработки и постоянно обновляется. Вы можете следить за ним на GitHub и на странице документации. С вами были разработчики Wolfram Language JavaScript Frontend - Кирилл Васин (https://github.com/jerryi) и Кирилл Белов (https://github.com/kirilbellovtest)!

Комментарии (8)


  1. Jury_78
    13.10.2023 14:47
    +1

    цель была именно в поиске бесплатного аналога Mathematic

    Возможно не знаете, но есть Maxima - это система компьютерной алгебры.


    1. KirillBelovTest Автор
      13.10.2023 14:47
      +1

      Wolfram Language - это уже не система компьютерной алгебры. В плане набора функций Maxima находится слишком далеко от Wolfram Language. Пользовательский интерфейс Максимы тоже не обладает той функциональностью Mathematica, о которой я писал в статье и концепцию которой мы сумели воспроизвести. Я пользовался максимой примерно 8 лет назад и может быть с тех пор многое изменилось, но в не кажется нельзя было редактировать output и пользоваться хотя бы отдалено похожим «синтаксическим сахаром» как в WL. Но я могу ошибаться. Я обязательно поставлю текущую версию и посмотрю что там изменилось. Спасибо вам за комментарий и напоминание


      1. Jury_78
        13.10.2023 14:47
        +1

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


        1. KirillBelovTest Автор
          13.10.2023 14:47

          Еще раз спасибо, что напомнили. Только что установил текущую версию. Действительно с тех пор, как я последний раз запускал Максиму - там довольно много изменений произошло. Посмотрел документацию и приятно удивился сколько всего там есть. Интерфейс тоже порадовал своей аутентичностью. А еще я вспомнил, что мне там действительно очень понравилось - это то, что графики строятся в gnuplot


    1. JerryI
      13.10.2023 14:47
      +1

      Ребята на самом деле далеко продвинулись с Максимой. Это реально круто, но чертовски сложновыполнимо. Здесь же немного про другой путь: бесплатное ядро Wolfram Engine где уже есть все решатели и прочее + написанный с нуля интерфейс нему.


      1. JerryI
        13.10.2023 14:47
        +1

        del. перепутал с Mathics


  1. ekimenkoav
    13.10.2023 14:47
    +2

    Не использовал Wolfram Engine, поскольку не было интерфейса (но есть возможность использовать собственно Mathematica). Испробую ваш интерфейс!

    Поддержка Markdown это очень круто!

    В Mathematica есть возможность делать слайды для показа. Но когда я использую этот функционал, то всегда возникают сложности, например, с масштабом отображения текста и объектов . Есть ли пример презентации сделанной в WLJS?


    1. JerryI
      13.10.2023 14:47
      +1

      Спасибо за теплые слова)

      Про презентации, пока хороших доков нет, но если нажать File -> Open Examples, там будет набор примеров Presentation.

      Либо на странице компонента для презентаций есть также видео демка https://github.com/JerryI/wljs-revealjs (ставить не надо, он уже поставляется вместе с системными компонентами)

      Так как там используется Markdown с поддержкой HTML и CSS то масштабирование можно наладить.

      Юникод пока не завезли, он что то теряется при передаче на сторону JS :(