Wolfram Language JavaScript Frontend

КДПВ

КДПВ

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

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

Установка

Главным системным требованием является наличие 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

кнопка и выпадающий список как результат выполнения

кнопка и выпадающий список как результат выполнения

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

.html

Теперь углы пунктирной рамки закруглены для всего документа

Теперь углы пунктирной рамки закруглены для всего документа

WolframScript Pages

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

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

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

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

randomFigure[] := 
Graphics[{{RandomColor[], RandomChoice[{Disk, Circle, Rectangle}][]}}, 
  ImageSize -> 60
]
.html

случайные фигуры в HTML

случайные фигуры в HTML

Wolfram Language XML Extension

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

.wlx
Heading[Text_] := 

; Graphics1 = Plot[Sin[x], {x, -4, 4}, ImageSize -> 350]; Hello World!

801660b4991fa2d72133332e247b4f19.png

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

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

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

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

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

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

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

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

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



---

# Slide 2

3D graphics

после выполнения слайд напечатается в 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 — Кирилл Васин и Кирилл Белов!

© Habrahabr.ru