Предисловие

Привет, читатель!

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

И словно намеренно в этот момент мне постучали с телеграммой: «Данные карточки для оплаты», — гласил текст. Я удивился: неужели снова за работу, тогда моя статья так и останется лишь прекрасной фантазией? Это было разочарование — я уже принял конец, соглашаясь с тем, что он должен был случиться.

Ну, пожалуй, ладно, — и я отвлёкся на то, чтобы попробовать воспользоваться только что полученным предложением, хотя и был крайне скептически настроен. Мой скепсис подтверждался тем, что совсем не совпадали ни регионы моего местоположения, ни языковые настройки, ни данные плательщика, ни имена аватаров, словом — вообще ничего.

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

О чём буду писать дальше? Совершенно точно не про успех и тем более не про себя. Я едва ли могу вас учить о том, как надо, как правильно. Это скорее попытка передать ощущения от первого лица, о том, как, высмеивая громкие лозунги, я понял, что оказался не прав, всего лишь один раз решив задачу, с которой едва ли справился бы самостоятельно.

Тогда, осознав произошедшее, я моментально пересмотрел свои убеждения и подумал: — Хорошо, но если этот самый модный Инструмент может настолько мне помочь, так поставим планку на такой уровень, который, мне кажется, практически нереальным.

Поехали.

Дирижёр

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

Что же стало? Бесконечное производство безыдейного контента для бессмысленного потребления. Не могу сказать, что бесцельного. Цель со стороны автора понятна — извлечение прибыли, но со стороны потребителя остаётся бессмысленной. Я, как, скорее всего, и вы, не хочу это всё видеть. И я не хочу это производить… СТОП. Нет, это не синтезированный контент. А вот то, о чём дальше пойдёт повествование, — синтезированный продукт. Такое выходит противоречие.

Но допустим, что не всё произведённое с помощью Инструмента, — это обязательно мусор. Даже если ему безоговорочно делегируется весь процесс производства продукта. На вопрос «зачем?» — ответ такой: экономическая целесообразность. Используя Инструмент, мы получаем удешевление производства. И вот там, где раньше нужен был полный офис штатных специалистов, взаимодействие со сторонними организациями, специализированные коллекции литературы, оборудование и, в конце концов, долгая работа, сегодня справляется Инструмент.

Конечно, я преувеличиваю, но совсем немного. Инструментом надо умело дирижировать. А Инструмент то и дело норовит обмануть дирижёра. Где-то лукавит, где-то недоговаривает, нагло врёт и ленится или совсем отказывается работать. Не осознавая вовсе его устройства, дирижёр при помощи выработанных вербальных техник возвращает капризный Инструмент в рабочий режим, добивается от него правильных действий. По крайней мере, тех действий, которые дирижёру кажутся правильными.

Но всё ли знает дирижёр? Нет, точно нет. И в этом случае приходится доверять экспертности Инструмента. В процессе производства Инструмент будет убеждать в тех или иных решениях, и какие-то придётся принять на веру, потому что глубокое изучение темы может быть практически невозможным или нецелесообразным. Тем не менее сегодня дирижёр должен знать довольно много, а завтра — уже меньше.

Мы движемся в сторону цифрового мира, где компьютерная программа станет воплощением фантазии любого. Любой будет дирижёром. Он просто расскажет о своей проблеме, а Инструмент воплотит решение. Или даже не расскажет?

А что, если кто-нибудь возьмёт лабораторную мышь, подключит к ней датчики и свяжет их с Инструментом? Хаотичные сигналы станут хаотичным текстом, а хаотичный текст — приложением для смартфона. Новость облетит социальные сети, и мы увидим первое «животное-программиста». Если это уже не случилось. Оставлю открытый вопрос — может оказаться так, что мышь найдёт закономерности взаимодействия с Инструментом и начнёт его использовать в своих интересах?

Мотивация

Будучи претендентом на наличие интеллекта, не уступающего мышиному, и заполучив Инструмент в двадцатикратной максимальной комплектации, я стал реализовывать свою затею и… отвлечёмся на то, чтобы въехать в контекст.

Сперва поговорим про «матричную лабораторию». Это известный в инженерных кругах язык программирования и среда для написания и отладки кода. К этой среде прилагается множество расширений, содержащих типовые решения задач из разных областей, что на практике позволяет быстро опробовать на своих данных тот или иной известный алгоритм. Разумеется, расширения, как и сама среда, — платные.

Продукт, на мой взгляд, концептуально замечательный. Но на практике — и редактор кода не устраивал, и графики тормозили на больших данных, и тёмной темы оформления долго не было. Сам язык сугубо ограниченный, что особенно сказывается, когда нужно взаимодействие со сторонними файлами и программами. Да и встраивать такое чудовище в свою инфраструктуру (не говоря уже об отдельном приложении) не выглядело хорошей затеей.

Профессионально я занимался довольно продолжительное время обработкой измерений, прямо с вузовской скамьи. На курсе, посвящённом «матричной лаборатории», я отверг этот продукт. Будучи радикально настроенным молодым человеком, не понял, зачем он мне нужен. В то время у меня в рукаве был настоящий 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

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

Окно просмотра матрицы
Окно просмотра матрицы

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

Интерактивное окно графиков
Интерактивное окно графиков

Короче говоря — получился рабочий джентльменский набор.

Заключение

Подводя ранний промежуточный итог проделанной работы, я стал ещё более убеждён в том, что программное обеспечение новой эры индивидуально. Здесь я повторюсь: вы просто расскажете Инструменту, что вам нужно, а Инструмент это сделает.

Пока наблюдается скорее некоторый переходный процесс — всё-таки дирижёр должен обладать довольно сильным набором прикладных знаний в области разработки программного обеспечения. Но этот переходный процесс едва ли затянется надолго.

Что касается проекта Numkit, публикация исходных кодов — его интерпретатора, транслятора, математической библиотеки и самой графической среды — является вопросом времени. Точно не сегодня.

Но точно сегодня я предлагаю перейти по ссылке, запустить сырой и без линейной алгебры Numkit в браузере и попробовать множество примеров, которые сделал Инструмент.

https://czssgkavo.github.io/numkit/

На этом, пожалуй, всё. Спасибо!