Научная статья на тему 'Объектно-ориентированный симулятор машины Тьюринга'

Объектно-ориентированный симулятор машины Тьюринга Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
2129
160
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
МАШИНА ТЬЮРИНГА / СИМУЛЯТОР / ЯЗЫК ПРОГРАММИРОВАНИЯ С++

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Штанюк А.А.

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

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Объектно-ориентированный симулятор машины Тьюринга»

2. Шаров, О. Г. Нейтрализация синтаксических ошибок в графических языках / О. Г. Шаров, А. Н. Афанасьев // Программирование. - 2008. - № 1. - С. 61 -66.

4. Шаров, О. Г. Методы и средства трансляции графических диаграмм / О. Г. Шаров, А. Н. Афанасьев // Программирование. - 2011. - № 3. - С. 65 - 76.

5. Афанасьев, А. Н. Программная система анализа диаграммных языков / А. Н. Афанасьев, Р. Ф. Гайнуллин, О. Г. Шаров // Программные продукты и системы. - 2012. - № 3. - С. 138 - 141.

УДК 519.688, 004.42

ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ СИМУЛЯТОР МАШИНЫ ТЬЮРИНГА

Штанюк Антон Александрович, к.т.н., доцент кафедры программной инженерии Нижегородского государственного университета им. Н.И. Лобачевского, shtan@land.ru

Введение

Цель данной работы состоит в построении программного симулятора машины Тьюринга (МТ) с использованием объектно-ориентированного языка программирования C++ [1]. Программа может быть полезной в рамках учебного процесса при изучении и программировании МТ. Цель состояла в том, чтобы создать максимально простую программную реализацию, которую легко изучать и развивать. Для упрощения программирования самой МТ команды машины были описаны в виде строк на достаточно простом языке, соответствующем классическому представлению команд [2].

1. Описание МТ

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

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

Указатель имеет возможность просматривать содержимое ячеек, менять свое состояние, а также перезаписывать содержимое ленты.

Математически машина полностью описывается набором следующих множеств:

129

Q={q0,qi,...,qm} - множество состояний машины (одно будет начальным, еще одно -конечным);

C={ c1, c2cn} - множество символов, записанных на ленте;

D={d1,d2,d3} - команды (движение вправо/влево, на месте);

R={r1,r2,.,rk} - множество правил (программа).

Множество правил задает поведение машины. Пример правила:

q00*->q01xR

Интерпретировать его нужно следующим образом: если текущее состояние машины -q0 0, а текущий символ на ленте ‘*’, то нужно сменить состояние на q01, записать символ ‘x’ на место текущего и сдвинуться по ленте вправо.

Исходные данные - это содержимое ленты до пуска машины. Результатом является содержимое ленты после остановки машины. Остановка происходит, если машина перешла в указанное состояние.

2. Программная реализация

Множество команд для перемещений вдоль ленты задается с помощью механизма перечислимых типов:

enum {R=1,L=-1,H=0};

(символы обозначают, соответственно, движение вправо, влево и стояние на месте) Состояние машины задается с помощью структуры, в которую входит название состояния (например “q0 0”), а также текущий символ на ленте.

struct State {

string q; char sym;

};

Каждое правило программы описывается с помощью структуры

struct Rule {

string text; // содержимое правила string curQ; // текущее состояние string nextQ; // следующее состояние char curSym; // текущий символ char nextSym; // следующий символ char cmd; // команда на перемещение

};

Экземпляр данной структуры заполняется информацией, извлеченной из строки правила. Так, если мы вводим в машину правило «q00*->q01xR»,

то содержимое полей будет следующим:

text - q00*->q01xR curQ - q00

nextQ - q01

curSym - * nextSym - x cmd - R

Алгоритм разбора строки правила предполагает наличие всех символов на определенных позициях. Единственное, что может меняться в этом формате - ширина поля записи состояния. То есть запись q0 0 требует трех знакомест, а q0 0 0 - уже четырёх. Эта

130

ширина определяется, исходя из предполагаемого числа состояний, и передается в машину при ее создании (параметр width).

Теперь опишем главный компонент симулятора - класс машины Тьюринга (class MT):

class MT

{

public:

MT(string,string,int); char getSym()const { return mem[curPos];

}

string getState()const { return curState.q;

}

string getMem() const { return mem;

// конструктор

// селектор символа из тек. позиции // селектор текущего состояния // селектор содержимого ленты

}

bool addRule(string); // добавление правила void step(); // шаг машины

private:

void process(int);

string mem; // содержимое ленты

int width; // ширина поля записи состояния

int curPos; // текущая позиция на ленте

State curState; // текущее состояние машины vector<Rule> rules; // вектор правил (программа) int rNum; // количество правил

};

Интерфейс класса включает в себя конструктор (MT), три селектора (getSym,getState,getMem), возвращающих значения внутренних переменных, метод (addRule), добавляющий правила, и метод (step), моделирующий работу одного шага машины. В закрытый раздел класса помещен еще один вспомогательный метод (process), упрощающий выполнение программы машиной.

В состав машины входит содержимое ленты с ячейками в виде строки стандартной библиотеки (mem), текущая позиция на ленте в виде числового значения (curPos), текущее состояние машины (curState), вектор правил (rules), а также две вспомогательные переменные: width - для хранения ширины поля записи состояния и rNum - количество правил в программе.

Реализация конструктора проста. Создается новая машина, для которой указывается запись на ленте, начальное состояние и значение переменной width:

MT::MT(string mem,string beg state,int width)

{

this->mem=mem;

this->width=width;

curPos=0;

curState.q=beg state;

curState.sym=mem[curPos];

rNum=0;

}

Текущая позиция устанавливается на первый символ строки.

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

131

bool MT::addRule(string rule)

{

rules.push back(*new Rule); rules[rNum].text=rule;

rules[rNum].curQ.assign(rule,0,width);

rules[rNum].curSym=rule[width];

size t pos=rule.find("->")+(width-1);

rules[rNum].nextQ.assign(rule,pos,width);

rules[rNum].cmd=rule[rule.length()-1];

rules[rNum++].nextSym=rule[rule.length()-2];

return true;

}

Рассмотрим работу функций process и step :

void MT::process(int i)

{

if(rules[i].cmd=='L')

curPos+=L;

else if(rules[i].cmd=='R') curPos+=R;

curState.q=rules[i].nextQ;

if(curPos<0)

return;

if(curPos>=mem.length())

mem.resize(mem.size()+1,,AI);

curState.sym=mem[curPos];

}

void MT::step()

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

{

int i;

for(i=0;i<rNum;i++) {

if(curState.q==rules[i].curQ&&curState.sym==rules[i].curSym)

{

if(rules[i].nextSym!=' ')

mem[curPos]=rules[i].nextSym;

process(i);

}

}

}

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

3. Пример работы машины

132

Рассмотрим пример реализации программы, эмулирующей умножение двух целых чисел в единичной системе счисления (1-1,11-2,111-3,...).

int main() {

MT mt("*11x11=*","q00",3); cout<<mt.getMem()

<<" "<<mt.getState()

<<" "<<mt.getSym()<<endl;

mt.addRule("q00*->q00 R"); mt.addRule("q001->q00 R"); mt.addRule("q00x->q01xR"); mt.addRule("q011->q02aR"); mt.addRule("q021->q021L"); mt.addRule("q02a->q02aL"); mt.addRule("q02=->q02=L"); mt.addRule("q02x->q03xL"); mt.addRule("q031->q04aR"); mt.addRule("q03a->q03aL"); mt.addRule("q03*->q06*R"); mt.addRule("q04x->q04xR"); mt.addRule("q04a->q04aR"); mt.addRule("q04=->q04=R"); mt.addRule("q041->q041R"); mt.addRule("q04*->q051R"); mt.addRule("q05A->q02*L"); mt.addRule("q06a->q061R"); mt.addRule("q06x->q07xR"); mt.addRule("q07a->q07aR"); mt.addRule("q071->q02aR"); mt.addRule("q07=->q08=L"); mt.addRule("q08a->q081L"); mt.addRule("q08x->q09 H");

for(;;) {

mt.step();

cout<<mt.getMem()

<<""<<mt.getState()

<<""<<mt.getSym()<<endl; if(mt.getState()=="q09") break;

}

return 0;

}

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

*11x11=* q0 0 * *aaxa1=11* q02 = *1axaa=111* q03 a

*11x11=* q0 0 1 *aaxa1=11* q02 1 *1axaa=111* О CO 1

*11x11=* q0 0 1 *aaxa1=11* q02 a *aaxaa=111* q04 a

*11x11=* q0 0 x *aaxa1=11* q02 x *aaxaa=111* q04 x

*11x11=* q01 1 *aaxa1=11* q03 a *aaxaa=111* q04 a

*11xa1=* q02 1 *aaxa1=11* q03 a *aaxaa=111* q04 a

*11xa1=* q02 a *aaxa1=11* q03 * *aaxaa=111* q04 =

*11xa1=* q02 x *aaxa1=11* q06 a *aaxaa=111* q04 1

*11xa1=* О CO 1 *1axa1=11* q06 a *aaxaa=111* q04 1

*1axa1=* q04 x *11xa1=11* q06 x *aaxaa=111* q04 1

*1axa1=* q04 a *11xa1=11* q07 a *aaxaa=111* q04 *

*1axa1=* q04 1 *11xa1=11* q07 1 *aaxaa=1111 > о СЛ

133

*1axa1=* q04 = *11xaa=11* q02 = *aaxaa=1111* q02 1

*1axa1=* q04 * *11xaa=11* q02 a *aaxaa=1111* q02 1

*1axa1=1A q05 л *11xaa=11* q02 a *aaxaa=1111* q02 1

*1axa1=1* q02 1 *11xaa=11* q02 x *aaxaa=1111* q02 1

*1axa1=1* q02 = *11xaa=11* q03 1 *aaxaa=1111* q02 =

*1axa1=1* q02 1 *1axaa=11* q04 x *aaxaa=1111* q02 a

*1axa1=1* q02 a *1axaa=11* q04 a *aaxaa=1111* q02 a

*1axa1=1* q02 x *1axaa=11* q04 a *aaxaa=1111* q02 x

*1axa1=1* q03 a *1axaa=11* q04 = *aaxaa=1111* q03 a

*1axa1=1* q03 1 *1axaa=11* q04 1 *aaxaa=1111* q03 a

*aaxa1=1* q04 a *1axaa=11* q04 1 *aaxaa=1111* q03 *

*aaxa1=1* q04 x *1axaa=11* q04 * *aaxaa=1111* q06 a

*aaxa1=1* q04 a *1axaa=111 л q05 л *1axaa=1111* q06 a

*aaxa1=1* q04 1 *1axaa=111 * q02 1 *11xaa=1111* q06 x

*aaxa1=1* q04 = *1axaa=111 * q02 1 *11xaa=1111* q07 a

*aaxa1=1* q04 1 *1axaa=111 * q02 1 *11xaa=1111* q07 a

*aaxa1=1* q04 * *1axaa=111 * q02 = *11xaa=1111* q07 =

*aaxa1=11 л q05 л *1axaa=111 * q02 a *11xaa=1111* q0 8 a

*aaxa1=11 * q02 1 *1axaa=111 * q02 a *11xa1=1111* q0 8 a

*aaxa1=11 * q02 1 *1axaa=111 * q02 x *11x11=1111* q0 8 x

*11x11=1111* q0 9 x

Конечная строка содержит условие задачи и числовой результат (*11x11 = 1111 *) .

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

• проверка правил на корректность;

• расширение ленты в обе стороны;

• загрузка правил из текстового файла.

Литература

1. Бьярне Страуструп. Программирование: принципы и практика использования C++,

исправленное издание— М.: «Вильямс», 2011

2. Википедия [Электронный ресурс] http://en.wikipedia.org/wiki/Машина Тьюринга

УДК 621.311

ПРИНЦИПЫ ПОСТРОЕНИЯ ОРГАНИЗАЦИОННОЙ И РАСЧЕТНОЙ МОДЕЛЕЙ В ИНФОРМАЦИОННЫХ СИСТЕМАХ ДЛЯ ЗАДАЧ ПРОИЗВОДСТВЕННОГО И ФИНАНСОВОГО ПЛАНИРОВАНИЯ ГЕНЕРИРУЮЩИХ КОМПАНИЙ

Сердюкова Надежда Викторовна, аспирант, Саратовский государственный технический университет имени Гагарина Ю.А., Россия, Саратов, nadeida.serd@yandex.ru

Основной обязанностью аналитиков и оперативного персонала генерирующих компаний (ГК) является контроль большого числа технико-экономических показателей (ТЭП), характеризующих себестоимость производства энергии. Главным свойствами большинства ТЭП являются их зависимость от используемого оборудования и взаимозависимость показателей друг от друга. Для учёта ТЭП и расчёта их значений в динамике часто применяются MES-системы (от английского Manufacturing Execution Systems - системы управления производством), задачами которых являются построение технологической модели ТЭС, сбор технологической информации, расчёт необходимых ТЭП и хранение всей этой информации в разрезах построенной модели. На основании этих данных в MES-системах работают модули визуализации и управления моделями, модули планирования и оптимизации производства, модули формирования корпоративной отчётности и финансового планирования.

134

i Надоели баннеры? Вы всегда можете отключить рекламу.