Автоматное программирование как новый способ создания автоматических торговых систем

MT5 | 14 августа, 2012

ἓν οἶδα ὅτι οὐδὲν οἶδα ( ο φιλόσοφος Σωκράτης )

я знаю, что ничего не знаю ( философ Сократ)

Введение

Начну с того, что эта тема совершенно не известна никому из трейдеров, разрабатывающих советники на MetaQuotes Language 4/5 (MQL4/5). Я убедился, попробовав найти эту тематику поиском на сайте MetaQuotes. Ничего нет.

Каждый трейдер создает свой советник, но для этого надо очень серьезно решить все проблемы с программированием и сложнейшей логикой работы программы. Ведь программа обязана САМА работать во всех стандартных и форс-мажорных ситуациях как часы.

Но как учесть все? Это очень и очень сложно, поэтому для автоматической системы управления требуется правильное программирование всех систем управления, а для этого подойдет только единственный правильный способ программирования "Автоматное программирование". В последние годы большое внимание уделяется разработке технологий программирования для встроенных систем и систем реального времени, к которым предъявляются высокие требования по качеству программного обеспечения.

В России автором Шалыто А.А. (преподаватель, профессор, доктор технических наук, заведующий кафедрой "Технологии программирования" СПбГУ ИТМО, ) в 1991 году разработан способ программирования, названный им "автоматное программирование". Я думаю, что читателям будет интересно потом увидеть простоту и легкость Автоматного программирования или SWITCH-технологии. Это настолько удобное программирование МТС систем в MetaQuotes Language, что лучше не придумаешь. Этот стиль очень точно вписывается в систему принятий сложнейших решений.

1. Начну издалека, с проблемы

Наверное, давней мечтой всех постановщиков задач и разработчиков программного обеспечения является полное соответствие задуманного решения задачи (алгоритма решения) и программной реализации этого алгоритма. Но что-то не склеивается у постановщиков и программистов. В алгоритмах постоянно не учитывается то, что необходимо программистам для реализации, а текст программы мало похож на алгоритм.

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

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

Если программа большая, то проверить по тексту соответствие алгоритму невозможно. Для проверки правильности реализации используется некая процедура под названием "Тестирование". При этом по существу проверяется как программист понял алгоритм (тот, который на бумаге) и как преобразовал его в алгоритм в своей голове, а далее в текст программы. В итоге программист является единственным держателем важнейшей логической информации, и становится абсолютно не важным то, что было придумано до программной реализации.

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

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

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

Время уходит, проект надо закончить к заданному сроку, а исполнитель сидит и придумывает "на коленке" как ему разрешить ту или иную логическую задачу, да еще и успеть реализовать. А уж о логических ошибках, не выявленных при тестировании, и вспоминать не будем, ибо и тестирование аналогично (хаотично)... Таково сегодняшнее положение. Есть ли выход или хотя бы улучшение? Складывается впечатление, что теряется нечто главное при переходе от алгоритма, изображенного в общепринятом стандарте, к тексту программы.

2. Логическая часть программы

Автором "автоматного программирования" предложена следующая концепция идеальной логической части программы. Вся логика программы строится на основе селектора (switch). Упрощенно, любой алгоритм управления (автомат) может быть реализован так, как показано (пока не задумывайтесь над смыслом комментариев, оцените структуру).

switch(int STATUS ) // Многозначная глобальная  переменная состояния автомата.
{
  case 0:  // старт

  // Проверка условий на дугах и петлях (условия проверяются по приоритетам),
  // выполнение перехода (изменение значения переменной STATUS)
  // и действий на дуге или петле (выполнение выходной функции);
  // протоколирование переходов и действий при выполнении условия. 

  // Вызов вложенных автоматов.
  // Выполнение выходных функций в состоянии.
  break ;
  
  case 1:
  // Проверка условий на дугах и петлях (условия проверяются по приоритетам),
  // выполнение перехода (изменение значения переменной STATUS)
  // и действий на дуге или петле (выполнение выходной функции);
  // протоколирование переходов и действий при выполнении условия. 

  // Вызов вложенных автоматов.
  // Выполнение выходных функций в состоянии.
  break ;
  
*********
*********
*********

 case N-1:
  // Проверка условий на дугах и петлях (условия проверяются по приоритетам),
  // выполнение перехода (изменение значения переменной STATUS)
  // и действий на дуге или петле (выполнение выходной функции);
  // протоколирование переходов и действий при выполнении условия. 

  // Вызов вложенных автоматов.
  // Выполнение выходных функций в состоянии.
  break ;

 case N:
  // Проверка условий на дугах и петлях (условия проверяются по приоритетам),
  // выполнение перехода (изменение значения переменной STATUS)
  // и действий на дуге или петле (выполнение выходной функции);
  // протоколирование переходов и действий при выполнении условия.

  // Вызов вложенных автоматов.
  // Выполнение выходных функций в состоянии.
  break ;
}

3. Что же такое автоматное программирование (объяснение дано автором Шалыто А.А.)

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

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

Возможно, что программист предусмотрел реакции на все комбинации значений управляющих переменных (2n комбинаций в рассматриваемом случае). Однако более вероятно, что некоторые комбинации значений управляющих переменных (вплоть до 2n-n) оказались непредусмотренными. Тогда при возникновении неожиданного сочетания входных воздействий программа может перейти в непредусмотренное состояние.

Для трейдера равнозначно бездействие советника при:

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

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

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

Для достижения строгости при разработке поведения программы необходимы три составляющие:

В качестве такой математической модели предлагается использовать конечный автомат, базирующийся на понятии "состояние". Автоматное программирование поддерживает такие этапы создания программного обеспечения, как проектирование, реализация, отладка и документирование.

Если в программировании в последнее время все шире используется понятие событие, то предлагаемый подход базируется на понятии состояние. С добавлением к нему понятия входное воздействие, которое может быть входной переменной или событием, вводится термин автомат без выхода. К последнему добавляется понятие выходное воздействие и вводится термин автомат (конечный, детерминированный). Поэтому область программирования, базирующаяся на этом понятии, названа автоматным программированием, а процесс создания таких программ - автоматным проектированием программ.

Особенность рассматриваемого подхода состоит в том, что при его использовании автоматы задаются графами переходов. Для различения их вершин вводится понятие кодирование состояний. При выборе "многозначного кодирования состояний" с помощью одной переменной можно различить состояния, число которых совпадает со значностью выбранной переменной. Это позволило ввести в программирование такой термин, как наблюдаемость программ.

В рамках предлагаемого подхода программирование выполняется "через состояния", а не "через переменные" (флаги), что помогает лучше понять и специфицировать задачу и ее составные части. При этом отладка проводится путем протоколирования в терминах автоматов.

Поскольку от графа переходов к тексту программы предлагается переходить формально и изоморфно, то при применении языков программирования высокого уровня наиболее рационально делать это с помощью конструкции switch. Поэтому технологию автоматного программирования было решено назвать "SWITCH-технология".

4. Программирование с явным выделением состояний

В дальнейшем автоматный подход был распространен на событийные системы, которые называются также "реактивными". Реактивные системы взаимодействуют с окружающей средой путем обмена сообщениями в темпе, задаваемом средой (к этому классу можно отнести советник).

Для программирования событийных систем с применением автоматов был использован процедурный подход, и поэтому такое программирование было названо программированием с явным выделением состояний. При этом выходные воздействия привязаны к дугам, петлям или вершинам графов переходов (применяются смешанные автоматы - автоматы Мура/Мили). Это позволяет в компактном виде представлять последовательности действий, которые являются реакциями на соответствующие входные воздействия.

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

Система взаимосвязанных автоматов образует системонезависимую часть программы, а системозависимая часть формируется из функций входных и выходных воздействий, обработчиков событий и т.д.

Другая важнейшая особенность описываемого подхода состоит в том, что при его применении автоматы используются триедино:

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

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

5. Основные понятия автоматного программирования

Базовым понятием автоматного программирования является СОСТОЯНИЕ. Основное свойство состояния системы в момент времени t0 заключается в "отделении" будущего (t > t0) от прошлого (t < t0) в том смысле, что текущее состояние несет в себе всю информацию о прошлом системы, необходимую для определения ее реакции на любое входное воздействие, формируемое в момент времени t0.

При использовании понятия СОСТОЯНИЕ знание предыстории не требуется. Состояние можно рассматривать как особую характеристику, которая в неявной форме объединяет все входные воздействия прошлого, влияющие на реакцию сущности в настоящий момент времени. Реакция зависит теперь только от входного воздействия и текущего состояния.

Понятие входное воздействие также является одним из базовых для автоматного программирования. Чаще всего, входное воздействие – это вектор. Его компоненты подразделяются на события и входные переменные в зависимости от смысла и механизма формирования.

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

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

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

На практике чаще применяется проектирование от объектов управления и событий:

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

  2. Строится набор управляющих состояний.

  3. Каждому запросу объектов управления ставится в соответствие входная переменная автомата, каждой команде – выходная. На основе управляющих состояний, событий, входных и выходных переменных строится автомат, обеспечивающий заданное поведение системы.

6. Особенности и достоинства программы

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

Вторая особенность вытекает из первой. Любой автомат содержит конструкцию switch (и фактически состоит из нее), внутри которой содержатся все логические операции. При вызове любого автомата управление передается к одной из меток case, а после выполнения соответствующих этой метке действий работа автомата (подпрограммы) завершается до следующего запуска. Указанные действия заключаются в проверке условий переходов и, если некоторое условие выполняется, то осуществляется вызов соответствующих выходных функций и изменение состояния автомата.

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

В последнее утверждение трудно поверить, ведь все мы привыкли без всяких особых размышлений применять множество глобальных и локальных переменных (флагов). А куда же без них?! Чаще всего это флаги, сигнализирующие программе о выполнении какого-либо условия. Флаг устанавливается (принимает значение TRUE) в нужный, по мнению программиста, момент, а потом (чаще всего, только после того как этот флаг вызывает нежелательные последствия своим вечным TRUE) начинается мучительный поиск места в программе для его сброса в значение FALSE.

Знакомо, не правда ли? Так вот теперь сообразите, глядя на текст примера: ведь здесь не применяется никаких дополнительных переменных, а просто изменяется значение номера состояния, и изменяется оно при выполнении логического условия. Чем не достойная замена флагов?!

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

Первым свойством состояния является то, что в нем ожидают ограниченный набор входных воздействий. Любой алгоритм (и программа, естественно) имеет входную и выходную информацию. Выходные воздействия можно разделить на два вида: переменные (например, операции над свойствами объектов) и функции (например, вызов функции запуска приложения, выдачи сообщения и т.п.).

Второе свойство состояния - выдача набора точно определенных значений выходных переменных. Это означает очень простое и одновременно необычайно важное обстоятельство - в любой момент времени определены значения всех выходных переменных, так как в каждый момент времени алгоритм (программа) находится в каком-то состоянии.

Число состояний ограничено и число наборов значений выходных переменных, соответственно, тоже. Функция протоколирования переходов является органически встроенной в функцию автомата и, следовательно, всегда можно определить последовательность переходов между состояниями и выдачи выходных воздействий.

Полный перечень особенностей приводится в разделе 2. Особенности предлагаемого варианта технологии, а полный перечень достоинств в разделе 3. Достоинства предлагаемого варианта технологии. В данной статье просто нельзя объять необъятное море информации по данной теме! И все вопросы по теории, после изучения всей научной литературы автора, надо задавать лично Анатолию Шалыто на ящик .

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

7. Примеры Автоматного Программирования

7.1. Пример на понимание

Состояние - это просто режим, в котором находится система. Например, вода имеет 3 состояния: пар - жидкость – лед. Переход из состояния в состояние под воздействием одной величины - температуры (при постоянном давлении).

Пусть задан график во времени Температура (t) (в нашем случае - цена котировки):

int STATUS=0; // обязательно глобальная целая всегда переменная !!! STATUS - это многозначный флаг
//----------------------------------------------------------------------------------------------//
int start() // обязательное наличие внешнего цикла
  {
   switch(STATUS)
     {
      case 0:  //--- стартовое  состояние программы
         if(T>0 && T<100) STATUS=1;
         if(T>=100)       STATUS=2;
         if(T<=0)         STATUS=3;
         break;

      case 1:  //---  жидкость
         // набор вычислений или действий в этой обстановке (повтор 1 статуса -- петля в автоматном программировании) //
         // и вызовы других вложенных автоматов A4, A5;
         if(T>=100 )      { STATUS=2; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         if(T<0)          { STATUS=3; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         // протоколирование переходов и действий при выполнении условия.
         break;

      case 2:  //--- газ
         // набор вычислений или действий в этой обстановке (повтор 2 статуса -- петля в автоматном программировании) //
         // и вызовы других вложенных автоматов A4, A5;
         if(T>0 && T<100) { STATUS=1; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         if(T<=0)         { STATUS=3; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         // протоколирование переходов и действий при выполнении условия.
         break;

      case 3:  //--- лед
         // набор вычислений или действий в этой обстановке (повтор 3 статуса -- петля в автоматном программировании) //
         // и вызовы других вложенных автоматов A4, A5;
         if(T>0 && T<100) {STATUS=1; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         if(T>=100)       {STATUS=2; /* набор действий при переходе, вызовы других вложенных автоматов A2, A3;*/}
         // протоколирование переходов и действий при выполнении условия.
         break;
     }
   return(0);
  }

Можно усложнить программу, если добавить параметр давление P и новые состояния, а также ввести сложную зависимость, показанную на графике:

Этот Автомат с 32 = 9 условий переходов - просто вообще ничего нельзя забыть или пропустить. Этим стилем также очень удобно писать даже любые инструкции и законы! Никаких лазеек и обходов закона тут допустить невозможно, охватывается все комбинации вариантов развития, описываются все случаи.

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

Если в системе N состояний (кроме 0 старта), то всех условий переходов N2.

Диаграмма переходов: N = 3 состояний, переходов и петель N2 = 9 (равно количеству стрелок).

Если в примере было бы другое количество переменных, то:

Это показывает экспоненциальное возрастание всех расчетных величин в таблице, т.е. сложность и ответственность проектирования при выборе главных системообразующих переменных.

Даже если два параметра, то очень трудно все описать! Но на практике все проще! В зависимости от логики и смысла, 50-95% переходов физически не могут быть, и состояний тоже на 60-95% меньше. Этим смысловым и логическим анализом очень сокращается трудность описания всех переходов и состояний.

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

7.2. Реле с гистерезисом

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

int   status=0;  // в начале программы глобально присвоим
//------------------------------------------------------------------//
switch(status)
  {
   case 0: //  старт  
      Y=x;
      if(x>xmax)  {status=1;}
      if(x<xmin)  {status=2;}
      break;

   case 1: //++++++++++++++++++++
      if(x>xmax)  Y=x;
      if(x<xmax)  Y=xmin;
      if(x<=xmin) {status=2; Y=xmin;}
      break;

   case 2: //--------------------
      if(x<xmin)  Y=x;
      if(x>xmin)  Y=xmax;
      if(x>=xmax) {status=1; Y=xmax;}
      break;
  }

Релейная характеристика:

7.3. Шаблон на 9 состояний и 81 вариант развития событий

Y - это текущее входное состояние автомата с 1 по 9. Формируется величина Y в советнике за пределами этой подпрограммы. MEGASTATUS - это прошлое состояние Y.

int MEGASTATUS=0; // в начале программы глобально присвоим
//---------------------------------------------------------------------//
void A0(int Y) // шаблон автомата
  {
   switch(MEGASTATUS)
     {
      case 0:  // стартовое
          MEGASTATUS=Y;
          break;

      case 1: // было прошлое
          // стало текущее, повтор
          if(Y=1) { /*набор действий в этой обстановке,вызовы других вложенных автоматов A2, A3, ... */ } // Петля//
          // стало текущее иное
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 2: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          // например, если невозможен или не существует по сути задачи переход от 2 к 6, то и не пишем совсем
          if(Y=6) { /* набор действий в этой обстановке */ }
          // тогда будет сокращен автомат, но шаблон автомата должен быть полным, чтобы ничего не забыть
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 3: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 4: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 5: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 6: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 7: // было   прошлое  
          //стало  текущее  
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 8: // было прошлое
          // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ } //Петля//
          if(Y=9) { /* набор действий в этой обстановке */ }
          // протоколирование переходов и действий при выполнении условия.
          break;

      case 9: // было прошлое
         // стало текущее
          if(Y=1) { /* набор действий в этой обстановке */ }
          if(Y=2) { /* набор действий в этой обстановке */ }
          if(Y=3) { /* набор действий в этой обстановке */ }
          if(Y=4) { /* набор действий в этой обстановке */ }
          if(Y=5) { /* набор действий в этой обстановке */ }
          if(Y=6) { /* набор действий в этой обстановке */ }
          if(Y=7) { /* набор действий в этой обстановке */ }
          if(Y=8) { /* набор действий в этой обстановке */ }
          if(Y=9) { /* набор действий в этой обстановке */ } //Петля//
          // протоколирование переходов и действий при выполнении условия.
          break;
     }
   MEGASTATUS=Y;
  }

7.4. Автомат аудиопроигрывателя

Рассмотрим Простой аудиопроигрыватель.

Данное устройство может находиться в 6 состояниях:

  1. Готов к работе (Ready);
  2. Нет треков (NO TRACK);
  3. Играет трек (Playing);
  4. Прокрутка трека вперед;
  5. Прокрутка трека назад;
  6. Пауза (Pause).

Система управления аудиопроигрывателя представляет собой автомат. Нажатия кнопок рассматриваются как события (events), воздействующие на автомат. Выходными воздействиями являются операции перехода треков, проигрывания трека, управления дисплеем и т.д.

switch(STATUS)
  {
   case 0: //--- "Готов к работе"
      if(Event == 3) { STATUS = 3; } //Нажата кнопка «>>»
      if(Event == 6) { STATUS = 1; } //Не найден музыкальный файл 
      if(Event == 1) { STATUS = 2; } //Нажата кнопка «PLAY»
   
      z1();  // Установить индикатор в начальное состояние
      break;

   case 1: //--- "Нет треков"
      z6();  // Выдать сообщение «NO TRACK»
      break;

   case 2: //--- "Играть трек"
      if(Event == 4) { STATUS = 4; } //Нажата кнопка «<<»
      if(Event == 5) { STATUS = 5; } //Нажата кнопка «PAUSE»( | | )
      if(Event == 3) { STATUS = 3; } //Нажата кнопка «>>»
      if(Event == 2) { STATUS = 0; } //Нажата кнопка «STOP»
      z2(); // Играть трек
      break;

   case 3: //--- "Прокрутка трека вперед"
      z3();  // Перейти на один трек вперед
      { STATUS=2; }
      break;

   case 4: //--- "Прокрутка трека назад"
      z4(); // Перейти на один трек назад
      { STATUS=2; }
      break;

   case 5: //--- "Пауза"
      if(Event == 5) { STATUS = 2; } //Нажата кнопка «PAUSE»
      if(Event == 1) { STATUS = 2; } //Нажата кнопка «PLAY»
      if(Event == 2) { STATUS = 0; } //Нажата кнопка «STOP»
      if(Event == 3) { STATUS = 3; } //Нажата кнопка «>>»
      if(Event == 4) { STATUS = 4; } //Нажата кнопка «<<»
      z5(); //Приостановить проигрывание
      break;
  }

Теоретически в этом автомате могло бы быть 36 вариантов переходов, но реально всего 15, и все подробности описаны у автора.

8. Рекомендации Шалыто А.А. по выполнению проектов

Как правильно составлять проект и оформлять проектную документацию, можно почитать на сайте http://project.ifmo.ru/books/3, я привожу вам краткую выдержку:

  1. В качестве прототипа можно взять книгу Шалыто А.А. "Логическое управление. Методы аппаратной и программной реализации алгоритмов. СПб.: Наука, 2000", которая выложена на этом сайте в разделе "Книги". Она оформлена правильно, так как выпущена старейшим и авторитетнейшим издательством в России.
  2. Во введении должна быть обоснована актуальность выбранной темы, кратко сформулирована решаемая задача, указаны язык программирования и операционная система, использованные в проекте.
  3. В разделе "Постановка задачи" должно быть приведено подробное словесное описание решаемой задачи. Приведены рисунки, чертежи и скриншоты, поясняющие постановку задачи.
  4. В разделе "Проектирование" при использовании объектно-ориентированного стиля программирования должна приводиться диаграмма классов. Основные классы должны быть подробно описаны. Для каждого из них желательно разработать "Структурную схему класса", отражающую его интерфейс и используемые методы, с указанием какие из них являются автоматными.
  5. В разделе "Автоматы" для каждого автомата должны быть приведены три документа: словесное описание, схема связей автомата, граф переходов.
  6. Словесное описание должно быть весьма подробным, но так как поведение сложного автомата понятно не описать, то она обычно представляет собой "декларацию о намерениях".
  7. Схема связей автомата подробно описывает его интерфейс. На этой схеме слева должны быть показаны:
    • источники информации;
    • подробное название каждой входной переменной;
    • подробное название каждого события;
    • предикаты с номерами состояний других автоматов, которые используются в рассматриваемом автомате в качестве входных воздействий. Например, может применяться предикат Y8 == 6, принимающий значение равное единице, когда восьмой автомат перейдет в шестое состояние);
    • входные переменные, обозначаемые как x с соответствующими индексами;
    • события, обозначаемые, как e с соответствующими индексами;
    • переменные для хранения состояний автомата с номером N, обозначаемые как YN.

    В схеме связей справа должны быть показаны:
    • выходные переменные, обозначаемые, как z с соответствующими индексами;
    • подробное название каждой выходной переменной;
    • события, порождаемые рассматриваемым автоматом (если они имеются);
    • подробное название каждого порождаемого события;
    • приемники информации.
  8. В разделе "Вычислительные алгоритмы" при использовании в вершинах или на переходах сложных вычислительных алгоритмов обосновывается их выбор и приводится их описание (в том числе и математическое). Эти алгоритмы обозначаются переменными x и z в зависимости от того, где выполняются вычисления: на входе или на выходе.
  9. В разделе "Реализация" должны быть описаны особенности реализации программы. В частности, должен быть приведен шаблон для формальной и изоморфной реализации автоматов. Здесь же должны быть приведены реализации автоматов.
  10. В "Заключении" описываются достоинства и недостатки выполненного проекта. Могут указываться пути его совершенствования.

9. Заключение

Призываю всех Вас:

Я надеюсь, что Автоматное программирование должно:

Если так будут программировать все программисты-трейдеры, то можно достичь цели - создание своего несливающего советника. А я этой первой статьей начинаю для вас новое направление творчества и поисков в автоматном проектировании и программировании, и даю всем толчок к новым изобретениям и открытиям.

И еще, я целиком присоединяюсь к статье автора и считаю важным дать вам ее в сокращенном виде (полный текст http://is.ifmo.ru/works/open_doc/):

Почему исходные тексты не решают проблему понимания программ?

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

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

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

Осознание неадекватности исходных текстов для понимания программ привело к попыткам объединить код и документацию более высокого уровня.

Если вы не принимали участия в работе над проектом, начиная с его ранних стадий, то сложность и объем фактически "закрывают" от вас исходные тексты, при условии, что отсутствует документация высокого уровня. Понимание "доисторического" кода в случае отсутствия первоначальных разработчиков или адекватной документации, позволяющей разобраться с соответствующими архитектурными решениями, является, вероятно, одним из труднейших видов программистской деятельности».

Почему программы не проектируются?

Итак, без исходных текстов плохо, но и с ними также нехорошо. Чего же не хватает "для полного счастья"? Ответ прост: проектной документации, выполненной весьма подробно и аккуратно, в которую программная документация входит как одна из составляющих.

Мосты, дороги и небоскребы без документации обычно не строятся, а вот о программах этого не скажешь.

В программировании сложилась ситуация, определяемая так: "Если бы строители строили дома так, как программисты пишут программы, достаточно было бы одного единственного дятла, чтобы разрушить цивилизацию".

Почему на аппаратуру выпускается море подробной и внятной проектной документации, в которой специалист средней квалификации может сравнительно быстро разобраться и изменить ее даже через много лет после выпуска, а для программ такая документация либо вовсе отсутствует, либо она пишется чисто формально, и для ее корректировки (если разработчик отсутствует) требуется специалист более высокой квалификации?

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

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

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

Это, видимо, происходит потому, что при программировании компилятор подсказывает несоответствия, в то время как при написании проектной документации подсказывать некому.

Вопрос о качестве документации на программное обеспечение приобретает все большее социальное значение. Разработка программ все больше напоминает шоу-бизнес с его погоней за прибылью. Все делается в дикой спешке, без раздумий о том, что будет с продуктом в будущем. Как и в шоу-бизнесе, в программировании используются критерии "выгодно и невыгодно", а не "хорошо и плохо". В большинстве случаев хороша не та технология, которая действительно хороша, а та, которая выгодна.

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

Подобный стиль работы, к сожалению, распространяется и на создание программного обеспечения для особо ответственных систем. Это во многом связано с тем, что в большинстве случаев программы пишутся, а не проектируются. "При проектировании любая техника, сложнее CRC-карточек или диаграмм использования, считается слишком сложной и не применяется. Программист всегда может отказаться от любой технологии, сказав начальнику, что он не укладывается в срок".

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

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

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

На сайте кафедры института, где работает Шалыто А.А., к сожалению, нет наших проблем и забот, у них свои задачи и цели, они не в теме и не курсе наших понятий и определений, поэтому примеров на нашу тему нет.

Основные книги-учебники автора Шалыто А.А:

  1. Автоматное программирование. http://is.ifmo.ru/books/_book.pdf
  2. Использование граф-схем и графов переходов при программной реализации алгоритмов логического управления. http://is.ifmo.ru/download/gsgp.pdf
  3. Автоматное программирование. http://is.ifmo.ru/works/_2010_09_08_automata_progr.pdf
  4. Преобразование итеративных алгоритмов в автоматные. http://is.ifmo.ru/download/iter.pdf
  5. switch-технология — автоматный подход к созданию программного обеспечения "реактивных" систем. http://is.ifmo.ru/download/switch.pdf
  6. Автоматное проектирование программ. Алгоритмизация и программирование задач логического управления. http://is.ifmo.ru/download/app-aplu.pdf
  7. Построение автопилота для упрощенной модели вертолета с помощью генетического алгоритма. http://is.ifmo.ru/works/2008/Vestnik/53/05-genetic-helicopter.pdf
  8. Программирование с явным выделением состояний. http://is.ifmo.ru/download/mirpk1.pdf
  9. Алгоритмизация и программирование для систем логического управления и "реактивных" систем. http://is.ifmo.ru/download/arew.pdf
  10. Объектно-ориентированный подход к автоматному программированию. http://is.ifmo.ru/works/ooaut.pdf
  11. Графическая нотация наследования автоматных классов. http://is.ifmo.ru/works/_12_12_2007_shopyrin.pdf
  12. Программирование за... 1 (одну) минуту. http://is.ifmo.ru/progeny/1minute/?i0=progeny&i1=1minute

В примерах проектов:

  1. Моделирование работы банкомата. http://is.ifmo.ru/unimod-projects/bankomat/
  2. Моделирование процесса управления ядерным реактором. http://is.ifmo.ru/projects/reactor/
  3. Система управления лифтом. http://is.ifmo.ru/projects/elevator/
  4. Разработка системы управления кофеваркой на основе автоматного подхода. http://is.ifmo.ru/projects/coffee2/
  5. Проектирование и исследование автоматов для решения задачи управления автомобилем. http://is.ifmo.ru/projects/novohatko/
  6. Моделирование цифрового фотоаппарата на основе автоматного программирования. http://project.ifmo.ru/shared/files/200906/5_80.pdf
  7. Применение автоматного программирования при моделировании мультиагентной системы беспилотных автомобилей. http://project.ifmo.ru/shared/files/200906/5_41.pdf
  8. Наглядная система сборки Кубика Рубика. http://is.ifmo.ru/projects/rubik/

и прочие интересные статьи и проекты: http://project.ifmo.ru/projects/, http://is.ifmo.ru/projects/ и http://is.ifmo.ru/works/.

P.S.

Число возможных различных событий кубика Рубика равно (8! × 38−1) × (12! × 212−1)/2 = 43 252 003 274 489 856 000. Это число не учитывает то, что ориентация центральных квадратов может быть разной.

С учётом ориентации центральных квадратов количество событий возрастает в 2048 раз, до 88 580 102 706 155 225 088 000.

У рынка Форекс или биржи намного меньше вариантов развития событий, но у них их задача решается легко за 100-200 шагов этим стилем программирования. Да! Рынок и советник соревнуются между собою как в шахматах, там никто не знает будущие ходы соперника (всё как у нас), но ведь созданы крутые программы типа Rybka (сильнейшая шахматная программа) на алгоритмах альфа-бета отсечения.

Пусть эти чужие успехи в других областях программирования дадут рвение и целеустремлённость нашему делу! Хотя, конечно, все мы знаем, что ничего не знаем.