Про то, как я замахнулся сделать аналог «матричной лаборатории», вооружившись самым модным инструментом
Предисловие
Привет, читатель!
В календаре выходной, за окном — дождь, подружка уехала в отпуск, а кабинет и он — окно в новейшую технологическую эру — более непригоден к использованию. Так, оказывается, что если отвлечься от насущных задач, то остаёшься наедине с мыслями, которыми хочется поделиться.
И словно намеренно в этот момент мне постучали с телеграммой: «Данные карточки для оплаты», — гласил текст. Я удивился: неужели снова за работу, тогда моя статья так и останется лишь прекрасной фантазией? Это было разочарование — я уже принял конец, соглашаясь с тем, что он должен был случиться.
Ну, пожалуй, ладно, — и я отвлёкся на то, чтобы попробовать воспользоваться только что полученным предложением, хотя и был крайне скептически настроен. Мой скепсис подтверждался тем, что совсем не совпадали ни регионы моего местоположения, ни языковые настройки, ни данные плательщика, ни имена аватаров, словом — вообще ничего.
Управляющая кабинетами компания даже запросила фотографию паспорта и водительского удостоверения, и я уже посмеивался над своей наивностью, на секунду поверившей в возможность и допустившей, что будет продолжение. А продолжение, похоже, случилось. И вот я зарядил Инструмент посмотреть исходный код, а сам, развернув текстовый редактор, продолжил писать статью.
О чём буду писать дальше? Совершенно точно не про успех и тем более не про себя. Я едва ли могу вас учить о том, как надо, как правильно. Это скорее попытка передать ощущения от первого лица, о том, как, высмеивая громкие лозунги, я понял, что оказался не прав, всего лишь один раз решив задачу, с которой едва ли справился бы самостоятельно.
Тогда, осознав произошедшее, я моментально пересмотрел свои убеждения и подумал: — Хорошо, но если этот самый модный Инструмент может настолько мне помочь, так поставим планку на такой уровень, который, мне кажется, практически нереальным.
Поехали.
Дирижёр
Интернет стал отвратительным. Нет, безусловно, он и раньше был отвратительным. Причём в каждое время отвратительным по-своему. Но всё же раньше было, как это известно, лучше. Люди больше писали, люди больше читали. И среди тонны помоев, вылитых на голову ради продаж, находились действительно крупицы чего-то интересного.
Что же стало? Бесконечное производство безыдейного контента для бессмысленного потребления. Не могу сказать, что бесцельного. Цель со стороны автора понятна — извлечение прибыли, но со стороны потребителя остаётся бессмысленной. Я, как, скорее всего, и вы, не хочу это всё видеть. И я не хочу это производить… СТОП. Нет, это не синтезированный контент. А вот то, о чём дальше пойдёт повествование, — синтезированный продукт. Такое выходит противоречие.
Но допустим, что не всё произведённое с помощью Инструмента, — это обязательно мусор. Даже если ему безоговорочно делегируется весь процесс производства продукта. На вопрос «зачем?» — ответ такой: экономическая целесообразность. Используя Инструмент, мы получаем удешевление производства. И вот там, где раньше нужен был полный офис штатных специалистов, взаимодействие со сторонними организациями, специализированные коллекции литературы, оборудование и, в конце концов, долгая работа, сегодня справляется Инструмент.
Конечно, я преувеличиваю, но совсем немного. Инструментом надо умело дирижировать. А Инструмент то и дело норовит обмануть дирижёра. Где-то лукавит, где-то недоговаривает, нагло врёт и ленится или совсем отказывается работать. Не осознавая вовсе его устройства, дирижёр при помощи выработанных вербальных техник возвращает капризный Инструмент в рабочий режим, добивается от него правильных действий. По крайней мере, тех действий, которые дирижёру кажутся правильными.
Но всё ли знает дирижёр? Нет, точно нет. И в этом случае приходится доверять экспертности Инструмента. В процессе производства Инструмент будет убеждать в тех или иных решениях, и какие-то придётся принять на веру, потому что глубокое изучение темы может быть практически невозможным или нецелесообразным. Тем не менее сегодня дирижёр должен знать довольно много, а завтра — уже меньше.
Мы движемся в сторону цифрового мира, где компьютерная программа станет воплощением фантазии любого. Любой будет дирижёром. Он просто расскажет о своей проблеме, а Инструмент воплотит решение. Или даже не расскажет?
А что, если кто-нибудь возьмёт лабораторную мышь, подключит к ней датчики и свяжет их с Инструментом? Хаотичные сигналы станут хаотичным текстом, а хаотичный текст — приложением для смартфона. Новость облетит социальные сети, и мы увидим первое «животное-программиста». Если это уже не случилось. Оставлю открытый вопрос — может оказаться так, что мышь найдёт закономерности взаимодействия с Инструментом и начнёт его использовать в своих интересах?
Мотивация
Будучи претендентом на наличие интеллекта, не уступающего мышиному, и заполучив Инструмент в двадцатикратной максимальной комплектации, я стал реализовывать свою затею и… отвлечёмся на то, чтобы въехать в контекст.
Сперва поговорим про «матричную лабораторию». Это известный в инженерных кругах язык программирования и среда для написания и отладки кода. К этой среде прилагается множество расширений, содержащих типовые решения задач из разных областей, что на практике позволяет быстро опробовать на своих данных тот или иной известный алгоритм. Разумеется, расширения, как и сама среда, — платные.
Продукт, на мой взгляд, концептуально замечательный. Но на практике — и редактор кода не устраивал, и графики тормозили на больших данных, и тёмной темы оформления долго не было. Сам язык сугубо ограниченный, что особенно сказывается, когда нужно взаимодействие со сторонними файлами и программами. Да и встраивать такое чудовище в свою инфраструктуру (не говоря уже об отдельном приложении) не выглядело хорошей затеей.
Профессионально я занимался довольно продолжительное время обработкой измерений, прямо с вузовской скамьи. На курсе, посвящённом «матричной лаборатории», я отверг этот продукт. Будучи радикально настроенным молодым человеком, не понял, зачем он мне нужен. В то время у меня в рукаве был настоящий C++, хотя появившийся одиннадцатый стандарт казался чем-то избыточно сложным.
Весь радикализм улетучился с первыми практическими задачами. Оказалось, что, во-первых, мне нравится концепция матричного языка: не писать циклы для поэлементных операций, множество параметров раскидать по своим размерностям и оперировать многомерными объектами. Во-вторых, мне нравится отладчик и REPL, что позволяет остановить программу и исполнять код прямо в консоли. В-третьих, мощная визуализация — интерактивные графики всевозможных видов. Ну и, наконец, обширная математическая библиотека для обработки сигналов. Это, пожалуй, ключевые причины, по которым «матричная лаборатория» стала моим сподручным средством на долгое время. С пометкой, что я писал кросс-платформу на C++.
Рассказывая про свой опыт нынешним коллегам, в том числе руководителям, к сожалению, я чаще сталкиваюсь с непониманием пользы «матричной лаборатории». А здесь мой опыт, по существу, выливается в одну ключевую идею: когда разрабатываешь программное обеспечение для обработки измерений, начни с проектирования алгоритма, а не кидайся в реализацию. Это особенно актуально, если речь идёт о видеокартах, встраиваемых процессорах и микроконтроллерах.
Что же такое проектирование алгоритма? Это поиск решения, которое на тестовых натурных или синтетических измерениях даёт приемлемый результат. И только после того, как решение найдено и подтверждено апробацией (проведено эмпирическое исследование работы алгоритма), можно приступать к реализации или сформулировать техническое задание. Такой подход экономит время, избавляя от переписывания аппаратно-специфичного кода.
Лучшим средством проектирования алгоритмов для меня была и остаётся «матричная лаборатория». Я пробовал содержать змею, начать отношения с Юлей и даже взять октаву. Но по разным причинам, выливающимся в личный дискомфорт, от всех них отказался. Меня не покидала мысль, что от лучшего (благодаря продуманной среде с отладчиком и графиками) до идеального совсем немного, а именно:
компактный интерпретатор, который можно было бы встроить и таким образом избежать переписывания кода;
симметричная C++ библиотека на случай, если мы не захотим встраивать интерпретатор и использовать все те же самые функции;
открытый и не замусоренный зависимостями исходный код, а также дружелюбие к разному окружению.
В течение нескольких лет я неоднократно пробовал писать интерпретатор подобного языка программирования, но эти попытки меня не привели к чему-то законченному, что можно было бы использовать. А идея жила, и в моих руках, наконец, появился Инструмент. Я стал дирижёром.
Проект Numkit
После возвращения работа продлилась недолго — каких-то полдня. Дверь в кабинет снова заперта. Поэтому пришло время рассказать, что получилось сделать, и признать наличие множества недочётов. К сожалению, эти недочёты отвлекали меня от реализации нового интересного функционала, которого нет в оригинальной «матричной лаборатории». Вечная дилемма в работе — причёсывать или наращивать.
Проект получил название Numkit. В основе — C++ код. На нём написан интерпретатор, виртуальная машина, математическая библиотека. Главное правило — минимум зависимостей, разве что потянули к себе Google Highway и Test. Графическая среда как бы идёт в придачу к этой основе и написана на JS. Такая связка позволяет запускать Numkit в браузере, формально — где угодно, правда, собранная родная версия должна работать быстрее.
По скорости, вопреки распространённому мнению, оригинальная «матричная лаборатория» — очень быстрая и оптимизированная, но планы приблизиться к ней и проиграть не более чем в два раза — вполне осуществимы. Почему быстрая — ответ известен: на векторизованных операциях включаются такие монстры, как Intel MKL, FFTW, а циклы умело оптимизируются JIT-компилятором. Мой путь был — не тащить какой-нибудь OpenBLAS, а заставить инструмент писать свои ядра, используя лишь обёртку на SIMD-инструкции, а вместо JIT — транслировать код и вызывать настоящий C++ компилятор. И шаг в эту сторону был сделан, и даже получены результаты.
Например, такой блок кода
function y = biquad(x, b0, b1, b2, a1, a2)
n = numel(x);
y = zeros(1, n);
x1 = 0; x2 = 0; y1 = 0; y2 = 0;
for k = 1:n
xn = x(k);
yn = b0*xn + b1*x1 + b2*x2 - a1*y1 - a2*y2;
y(k) = yn;
x2 = x1; x1 = xn;
y2 = y1; y1 = yn;
end
endостается вполне узнаваемым после трансляции
void biquad_1dr_1d_1d_1d_1d_1d(const double* x, std::size_t _nk_x_len, double b0, double b1, double b2, double a1, double a2, double* __restrict y, std::size_t _nk_y_len) {
double n = 0.0;
double x1 = 0.0;
double x2 = 0.0;
double xn = 0.0;
double y1 = 0.0;
double y2 = 0.0;
double yn = 0.0;
{
nk_val _nk_args[] = { nk_box_array(x, _nk_x_len) };
n = nk_rt::bridge_scalar_arr("numel", _nk_args, 1);
}
for (std::size_t _nk_i = 0; _nk_i < _nk_y_len; ++_nk_i) {
y[_nk_i] = 0.0;
}
x1 = 0.0;
x2 = 0.0;
y1 = 0.0;
y2 = 0.0;
for (std::size_t k = 0; k < _nk_x_len; ++k) {
xn = x[k];
yn = (((((b0 * xn) + (b1 * x1)) + (b2 * x2)) - (a1 * y1)) - (a2 * y2));
y[k] = yn;
x2 = x1;
x1 = xn;
y2 = y1;
y1 = yn;
}
}
и совсем не проигрывает в скорости.
Математическую библиотеку оказалось делать несложно. В большей степени работа велась Инструментом автономно, по моим указаниям, которые упрощённо, без потери смысла, выглядели так:
читай документацию;
пиши реализации функций;
пиши тесты;
запускай Numkit и «матричную лабораторию»;
сравнивай результат по точности и по скорости, заводи задачу при необходимости.
Иначе говоря — возьми и перепиши своим почерком в мою тетрадь.
В то же время много внимания ушло на разработку графической среды. Требовалось много ручного тестирования. Структурно среда вполне узнаваема: консоль, воркспейс с переменными, панель для графиков, навигатор по файлам.

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

Графики получили два представления: предварительный просмотр на панели слева и интерактивное окно, в котором можно их прокручивать, настроить отображение и экспортировать в файл.

Короче говоря — получился рабочий джентльменский набор.
Заключение
Подводя ранний промежуточный итог проделанной работы, я стал ещё более убеждён в том, что программное обеспечение новой эры индивидуально. Здесь я повторюсь: вы просто расскажете Инструменту, что вам нужно, а Инструмент это сделает.
Пока наблюдается скорее некоторый переходный процесс — всё-таки дирижёр должен обладать довольно сильным набором прикладных знаний в области разработки программного обеспечения. Но этот переходный процесс едва ли затянется надолго.
Что касается проекта Numkit, публикация исходных кодов — его интерпретатора, транслятора, математической библиотеки и самой графической среды — является вопросом времени. Точно не сегодня.
Но точно сегодня я предлагаю перейти по ссылке, запустить сырой и без линейной алгебры Numkit в браузере и попробовать множество примеров, которые сделал Инструмент.
https://czssgkavo.github.io/numkit/
На этом, пожалуй, всё. Спасибо!