|
Professor Seleznov
|
Возможно, на мой предвзятый взгляд, нынче автоматным программированием (АП) называют любое программирование, в которое вводят состояния (а параллельным – где используют потоки). Но не все, что с колесами – машина, а с крыльями – самолет. И далеко не всегда то, что «выглядит» как автомат, «плавает» как автомат и «крякает» как автомат им является. Это ясно, если руководствоваться математическим определением конечного автомата (КА). Только соответствие этому позволяет считать программирование автоматным.Подробнее же об АП рассказано в [1]. Среди существующих программных подходов некоторые на взгляд программистов относятся к категории АП. Это, например, варианты диаграмм Харела (Statecharts) и языков на них основанных. Например, UML (Unified Modeling Language). Именно этой теме посвящена статья на Хабре, которая описывает проектирование на базе КА в среде Engee[2]. В последней есть библиотека «Конечные автоматы» – «лучший инструмент для визуального проектирования сложной управляющей логики» [3]. Разберем данную статью, создав аналог рассмотренного в ней решения, но только на языке С++ и в среде ВКПа – классическом варианте технологии автоматного программирования. Это позволит объективно сравнить подходы, а вам, «хабравчане», останется только составить уже свое мнение о разных вариантах АП. Human-симулятор Общая структурная модель решения, заимствованная из [2], приведена на рис. 1. Здесь блок human_simulator представляет модель человека, а fitness_tracker реализует логику фитнесс-браслета. Предположительно реализовать их будет не так уж сложно, поскольку в основе решений аналогичные по своей сути алгоритмические модели – конечные автоматы. Но, как говорится, легко было на бумаге… Начнем, как и в исходной статье, с создания модели человек. Моделирование (симуляция) его поведения поможет проектированию и пригодится при тестировании. В рамках поставленной задачи необходимо смоделировать частоту пульса, число шагов и текущую активность пользователя. В последнем случае будем различать следующие его состояния - Сон (Sleep), Покой(Rest), Ходьба(Walk) и Бег(Run). Модель поведения human_simulator в форме классического КА показана на рис. 1. Здесь состояние s1 является промежуточным, через которое проходят пути во все другие состояния. При этом предикат x1 принимает истинное значение, если изменится любой из входов модели. К ним относятся: parameter_activity - вид активности человека и parameter_intensity - интенсивность его поведения. Остальные предикаты различают состояния модели, а действия моделируют изменение выходных параметров модели.

Рис. 1. Структурная модель проекта

Рис.2. КА модель симулятора человека Автомат, начав работу из начального состояния st, переходит в s1 устанавливает начальные значения каденса (шагов в сек.), частоту пульса и запускает отсчет времени моделирования (y3). Попутно предикат x1 фиксирует входные параметры модели. Заметим, что это не совсем верно, т.к. предикаты в идеале не должны выполнять каких-либо действий. Просто в данном случае так показалось удобнее. Когда x1 принимает истинное значение, то в зависимости от значения x2, x3, x4 модель переходит в то или иное состояние и устанавливает целевые значения пульса и каденса (y2). И пока текущее состояние стабильно (x1 – false) действие y1 изменяет параметры в сторону достижения целевых значений. При изменении любого из входов блока (x1 – true) автомат возвращается в промежуточное состояние, а затем, если это необходимо, переходит в новое состояние. Модель автомата в [2] содержит «параллельные состояние» (так звучит в терминах UML) типа Result_Processing для моделирования изменения пульса и подсчета числа шагов. Это спорное решение, т.к. фактически объединяет параллельные не вязанные между собой процессы. В рамках АП подобные задачи решаются параллельными автоматами. В данном случае, а речь уже об ВКПа, их будет два: один моделирует случайный процесс изменения пульса, второй – подсчитывает шаги. Итак, нам достаточно просто удалось создать аналог модели человека в терминах классической модели КА. При этом, помимо упомянутых двух параллельных автоматов, темпоральный оператор типа after() реализован также как параллельный автомат. Все это в сумме формирует более строгую, компактную, наглядную и потому подверженную меньшим ошибкам модель. Фитнес-браслет Переходим к реализации аналога блока fitness_tracker, который собственно и отвечает за логику работы браслета. Он должен: 1. Имитировать подсчет шагов. 2. Устанавливать флаг отдыха, если превышено время тренировки. 3. Устанавливать флаг перехода к тренировке, если превышено время отдыха. 4. Контролировать превышение частоты пульса. В статье [2] реализация его весьма специфична. И это наследие свойств исходной модели, которые сложно конвертируются в классическую модель автомата. Но поскольку функции браслета достаточно просты, а смысл входных и выходных каналов не вызывает противоречивых толкований, то попробуем создать собственную реализацию блока fitness_tracker. В рамках нового решения мы не отказались и от исходного решения. В первую очередь там, где оно легко преобразуется в эквивалентную модель КА. И здесь есть кандидат - «первое состояние» Check_Heart_Rate. Его исходная модель показана на рис. 3, а граф соответствующего КА приведен на рис. 4.

Рис.3. Состояние Check_Heart_Rate на UML

Рис.4. Модель Check_Heart_Rate в форме конечного автомата Модель в Engee содержит темпоральный оператор duration(), параметром которого является логическое выражение. И хотя подобного оператора пока в ВКПа нет, он легко реализуется аналогично оператору аfter() в форме параллельного автоматного процесса, в котором один из его предикатов в соответствии с концепцией ООП перегружен логическим выражением. Изначально процесс, моделирующий оператор duration(), находится в состоянии «0» и переходит в состояние «1», если логическое выражения true в течение заданного времени. Процесс вернется в состояние «0», как только выражение примет значение false. Предикат x1 автомата на рис. 4 анализирует текущее состояние некоторого процесса (указатель на него – pFDura10sec) и если значение пульса превысит максимум более 10 сек, автомат перейдет в состояние Notify, установив значение флага notification_dangerous_heart_rate (y2). Действие y3 сбросит флаг, когда пульс вернется в норму. Так мы реализовали п. 4 из приведенного выше списка. Для реализации п.п. 2, 3 необходимо различать состояния активности и бездействия человека. Для этого создадим автомат FHumanStates, который будет распознавать состояния модели по величине пульса. Он приведен на рис. 5.

Рис.5. Модель классификации состояния человека Другой автомат - FActiveAction (см. рис. 6) будет анализировать состояния автомата на рис. 5 и переходить в состояние Action или Inaction, отражающие активность человека. Но прежде чем перейти в эти состояния модель в промежуточных состояниях act и inac в течение определенного времени выполняется анализ текущего состояния. И только если оно стабильно происходит переход в новое состояние. В процессе переходов запускается отсчет времени, который фиксируются при переходе в противоположное состояние активности. Так определяются времена нахождения в том или ином состоянии активности.

Рис.6. Модель классификации состояния человека Еще один параллельный автомат – FSendNotification анализирует данные времена и устанавливает флаги активности или отдыха. Конечно, это можно было бы вполне сделать в автомате FActiveAction, но в данном случае принято решение разнести эти действия по отдельным процессам. В результате мы создали аналог блока fitness_tracker в форме множества параллельных автоматов, реализующих функции, сформулированные п.п. 1-4. Мы не стали создавать модель подсчета шагов, т.к. она фактически реализована в рамках модели человека. Сервисные процессы Мы не рассматриваем подробно модели процессов, окружающих модель браслета. Они созданы на базе типовых процессов и реализуют отображение текущего состояния браслета и выдают соответствующие текстовые сообщения. Дополнительно был создан диалог управления моделью. На нем размещены элементы управления и кнопка запуска теста, аналогичного тесту в [2]. Кстати, это тоже еще один параллельный автомат, который в заданные моменты времени изменяет входные параметры модели человека.

Рис.7. Результаты тестирование модели в ВКПа Средствами среды ВКПа реализован вывод диаграмм сигналов. Все это, в том числе и результаты тестирования, демонстрирует рис. 7. Можно видеть, что диаграммы графиков сигналов на этом рисунке совпадают с аналогичными диаграммами в [2]. Браслет для Виктории Бони Чем дольше проектируешь модель, тем лучше ее понимаешь. Например, становится ясно, что исходная модель может перейти из любого состояния в любое другое. Например, от состояния сна к состоянию бега. Такое еще можно допустить (в экстремальной ситуации), но вот заснуть на бегу, скорее всего, будет проблематично. Подобные рассуждения привели к уточнению модели. Она показана на рис. 8. В свете текущих событий назовем ее моделью поведения условной Виктории Бони. И, возможно, это не так уж далеко от действительности. Особенно в свете поведения персонажей Дом-2.

Рис. 8. Модель поведения Виктории Бони. Модель сразу после инициализации попадает в состояние Сон (Sleep). Попасть в другое состояние, не поспав при рождении, просто невозможно. А уже из этого состояния может перейти, например, в состояние Бег (Run), но только через состояние Покой (Rest). А вот уже из него, минуя состояние Хотьба (Walk), можно перейти и к бегу. Но вот вернуться обратно в состояние Покой столь же коротким путем не удастся. Сделать это можно, следуя логике поведения модели, только перейдя на шаг. Если мы заменим ранее созданную модель на модель Бони, то результаты теста не изменятся. Но вот выбор следующего состояния в рамках прямого диалога управления моделью уже будет зависеть от текущего состояния модели. Например, из любого активного состояния в состояние Сон (Sleep) можно будет попасть только через состояние Покой (Rest). Другие попытки нарушить последовательность смены состояний будут проигнорированы. Можно считать, что модель в каком-то смысле «поумнела». Код модели Бони А теперь перейдем, пожалуй, если не к самому интересному, то самому показательному в нашем проекте моменту – коду модели Виктории Бони. Он показан на листинге 1. Благодаря объектным возможностям С++, создать его получилось легко и, можно даже сказать, красиво.
#include "FHumanSimulator.h" LArc TBL_Bonya[] = { LArc("st", "Sleep", "--", "y3"), LArc("Sleep", "Sleep", "x2", "y1"), LArc("Sleep", "Rest", "x3", "y2"), LArc("Rest", "Rest", "x3", "y1"), LArc("Rest", "Sleep", "x2", "y2"), LArc("Rest", "Walk", "x4", "y2"), LArc("Rest", "Run", "^x2^x3^x4", "y2"), LArc("Walk", "Walk", "x4", "y1"), LArc("Walk", "Rest", "x3", "y2"), LArc("Walk", "Run", "^x2^x3^x4", "y2"), LArc("Run", "Run", "^x2^x3^x4", "y1"), LArc("Run", "Walk", "x4", "y2"), LArc() }; class FBonya : public FHumanSimulator { public: LFsaAppl* Create(CVarFSA *pCVF) {Q_UNUSED(pCVF)return new FBonya(nameFsa, pCVarFsaLibrary);} FBonya(string strNam, CVarFsaLibrary *pCVFL):FHumanSimulator(strNam, pCVFL, TBL_Bonya) {} protected: void y2() { setting_intensity = pVarIntensity->GetDataSrc(); setting_activity = pVarActivity->GetDataSrc(); FHumanSimulator::y2(); } };
Листинг 1. Код модели Бони Листинг 1 представляет полный код, в котором нет ни чего лишнего. Он содержит лишь алгоритм поведения модели, имя класса, свойства которого наследуются, сам конструктор класса, метод Create() для создания библиотечных объектов и немного подправленное действие y2 базового класса. Подчеркнем, что подобный «фокус» возможен в немалой степени потому, что поведение автоматного класса отделено от методов автомата. В обычной ситуации все это перемешано, т.к. программа на любом языке программирования представляет собой в большинстве случаев смесь операторов управления, арифметических, логических и других программных операторов.

Рис. 9. Тестирование модели Бони Отметим, что при таком подходе управление и методы класса можно, во-первых, использовать и корректировать независимо друг от друга. Во-вторых, уменьшается размер кода, т.к. можно вызывать методы в разных частях алгоритма. В-третьих, классы могут наследовать и/или изменять поведение класса, отдельные методы и т.д. и т.п. Можно ли что-то подобное делать в рамках Engee сказать сложно. Хотя что-то, наверное, можно. Так, например, выделить управление, но вот оценить объектные возможности Engee, руководствуясь исходной статьей, уже сложно. Заключение Самое сложное – писать заключение. Нужно подбирать слова, чтобы описать то, что очевидно для автора. Возникают и вопросы. Например, как так получилось, что, взяв за основу конечный автомат, сделали диаграмму Харелла, которая программисту может показаться удобной и технологичной, но от классического автомата и его теории явно отстоит далеко? А потому закономерен вопрос: можно ли Engee откатить, чтобы вернуться к истокам КА? И как это будет выглядеть в результате? Самому «копать», чтобы получить ответ на заданный выше вопрос, если честно, попросту лень. Но времена такие, что можно привлечь такой «интеллект, как DeepSeek, который быстро и с удовольствием «копнет» за вас. Нужно только с ним эту тему «перетереть». Вот мы и поболтали… Беседа получилась не совсем уж краткая, но в процессе даже появился интерес к результату. Цель все же была достигнута, и стало понятно, как можно вернуть Engee к классическим истокам, используя ее визуальный язык, чтобы повторить автоматную технологию ВКПа. Но нужно ли это? И возможно ли в полном объеме реализовать модель АП? Хотя это, возможно, темы уже другого разговора… Литература 1. Автоматная модель управления программ. https://habr.com/ru/post/484588/ 2. Визуальное проектирование управляющей логики фитнес-браслета. https://habr.com/ru/companies/etmc_exponenta/articles/910114/ 3. Библиотека «Конечные автоматы». https://start.engee.com/state_machines-Источник
|