Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Цикл активизации агента






 

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

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

 

  Рис. 12.3. Общий вид простого логического цикла активизации агента

 

 

12.4.2.2. Стратегии логического вывода агента

Этот агент обладает способностями рассуждать, реализованными частично классом proposition и частично м етодо м determineVacationAppropriate(). Вспомните, что в классе proposition объявлен метод operator() =0 в виде чисто виртуальной функции. Поэто м у в производно м к л ассе необходи м о реализовать м етод operator (). Мы используем этот оператор, чтобы объект предположения мог самостоятельно определить свою «суть», т. е. понять, истинно данное предположение или ложно. Это означает самодостаточность классов предположений. Именно в самодостаточности и состоит фундаментальный принцип объектно-ориентированного программирования: класс представляет собой самостоятельную конструкцию, инкапсулирующую его характеристики и поведение. Итак, одной из основных линий поведения класса предположений и его потомков является способность определять, истинно данное предположение или нет. Для реализации этого средства используется перегрузка операторов и объекты-функции. Рассмотри м фрагменты определения класса proposition и определений его потомков.

//Листинг 12.6. Фрагменты определений класса

// proposition и его потомков

template < class C> bool proposition< C>:: operator& & (

proposition & X)

{

return((*this)() & & X());

template < class C> bool proposition< C>:: operator||(

proposition & X)

{

return((*this)() || X());

template< class C> proposition< C>:: operator void*(void) {

return((void*)(TruthValue));

bool trip__announcement:: operator()(void) {

list< trip_announcement>:: iterator I; if(directTrip()){

return(true);

}

I = UniverseOfDiscourse.begin();

if(validTrip(I, Origin)){

return(true);

}

return(false);

}

Операторы " ||" и " & & ", используемые в классах предположений, позволяют определить, истинно данное предположение или ложно. В каждом из этих определений операторов в конечном счете вызывается метод operator (), определенный в классе-потомке. Обратите внимание на определение оператора " ||" (см. листинг 12.6). Этот оператор определен следующим образом.

template < class C> bool proposition< C>:: operator||

(proposition & X)

{

return((*this)() || X());

}

Это определение позволяет использовать следующий код.

trip_announcement А;

performance_statement В;

if (А || В) {

// Какие-нибудь действия.

}

 

При вычис л ении выражений А или В будет вызван оператор operator (). Каждый класс предположений определяет поведение оператора operator () по своему. Напри м ер, в классе trip_announcement оператор operator () определяется так.

bool trip_announcement:: operator()(void) {

list< trip_announcement>:: iterator I;

if(directTrip()){

return(true);

}

I = UniverseOfDiscourse.begin();

if(validTrip(I, Origin)){

return(true);

}

return(false);

}

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

Детройт - Толедо

Толедо - Колу м бус

Тогда объект класса trip_announcement «доложит» о то м, что утверждение о су щ ествовании автобусного м аршрута из Детройта в Колу м бус истинно, нес м отря на то, что область рассуждений не содержит утверждения о пря м о м маршруте:

Детройт - Колу м бус

Объект класса trip_announcement действительно проверит, существует ли прямой маршрут из Детройта в Колумбус. Если он существует, объект возвратит значение ИСТИНА. В противном случае он попытается найти обходной путь. Подобное поведение реализуется так.

if(directTrip()){

return(true);

}

I = UniverseOfDiscourse.begin();

if(validTrip(I, Origin)){

return(true);

}

«Самоопределением» истинности объект обязан оператору operator () класса trip_anouncement. Метод directTrip () довольно прост, и его работа заключается в последовательном просмотре области рассуждений на предмет существования следующего утверждения:

Детройт - Колу м бус

Метод validTrip (), чтобы узнать, существует ли обходной путь, использует технологию поиска вглубь (Depth First Search— DFS). Определения методов validTrip () и directTrip () приведены в листинге 12.7.

// Листинг 12.7. Определения методов validTrip() и // directTrip()

bool trip_announcement:: validTrip(list< trip_announcement>:: iterator I, string TempOrigin)

{

if(I == UniverseOfDiscourse.end()){ if(Candidates.empty()){ TruthValue = false; return(false);

}

else{

trip_announcement Temp; Temp = Candidates.top(); I = find(UniverseOfDiscourse.begin(), UniverseOfDiscourse.end(), Temp); UniverseOfDiscourse.erase(I); Candidates.pop(); I = UniverseOfDiscourse.begin(); if(I! = UniverseOfDiscourse.end()){ TempOrigin = Origin;

} else {

TruthValue = false; return(false);

}

}

>

if((*I).origin() == TempOrigin & &

(*I).destination() == Destination){ Candidates.push(*I); TruthValue = true; return(true);

}

if((*I).origin() == TempOrigin){ TempOrigin = (*I).destination(); Candidates.push(*I);

}

I++;

return(validTrip(I, TempOrigin));

bool trip_announcement:: directTrip(void) {

list< trip_announcement>:: iterator I; I = find(UniverseOfDiscourse.begin(),

UniverseOfDiscourse.end(), *this); if(I == UniverseOfDiscourse.end()){

TruthValue = false;

return(false);

}

TruthValue = true; return(true);

 

В обоих методах validTrip () и directTrip () используется алгоритм find() из стандартной библиотеки С++. UniverseOfDiscourse — это контейнер, который содержит убеждения агента и подготовленные для него утверждения. Вспомните, что одним из первых действий, предпринимаемых агентом, является вызов метода updateBeliefs(), который заполняет контейнер UniverseOfDiscourse. Определение метода updateBeliefs () приведено в листинге 12.8.

// Листинг 12.8. Обновление убеждений

void agent:: updateBeliefs(void) {

performance_statement TempP;

TempP.sales(203.0);

TempP.perHour(10 0.0);

TempP.bays(4);

PerformanceBeliefs.push_back(TempP);

trip_announcement Temp;

Temp.origin(«Detroit»);

Temp.destination(«LA»);

TripBeliefs.push_back(Temp);

Temp.origin(«LA»);

Temp.destination(«NJ»);

TripBeliefs.push_back(Temp);

Temp.origin(«NJ»);

Temp.destination(«Windsor»);

TripBeliefs.push_back(Temp);

}

На практике убеждения обычно поступают из среды выполнения агента ( т.е. из файлов, от датчиков, портов, устройств сбора данных и пр.). В листинге 12.8 инфор м ация, поступающая в списки TripBeliefs и PerformanceBeliefs, представляет новые высказывания, которые агент получает о приемлемых маршрутах и эффективности авторемонтной мастерской. Эти высказывания оцениваются относительно директив, выданных агенту. Установкой директив агента зани м ается м етод setGoals (). (Его опреде л ение приведено в л истинге 12.9.)

// Листинг 12.9. Метод установки целей агента

void agent:: setGoals(void) {

Managerl.perHour(15.0);

Managerl.bays(8);

Managerl.sales(123.2 3);

Manager2.perHour(2 5.3 4);

Manager2.bays(4);

Manager2.sales(12.33);

Manager3.perHour(3 4.3 4);

Manager3.sales(100000.12);

Manager3.bays(10);

Trip1.origin(«Detroit»);

Tripl.destination(«Chicago»);

Trip2.origin(«Detroit»);

Trip2.destination(«NY»);

Trip3.origin(«Detroit»);

Trip3.destination(«Windsor»);

}

Эти директивы сообщают агенту о том, что его владелец хотел бы отправиться в отпуск из Детройта в Чикаго, из Детройта в Нью-Йорк или из Детройта в Виндзор. Помимо маршрутов, также устанавливаются финансовые цели. Чтобы отпуск состоялся, необходимо достижение одной или нескольких таких целей. После установки целей агент обновляет свои убеждения, и его следующая задача будет определена в зависимости от целей и убеждений при условии возможности планирования отпуска. И тогда вызывается второй компонент методов рассуждений агента: determineVacationAppropriate()

Этот метод передает контейнер UniverseOfDiscourse каждому из объектов предположен и й. После это г о он использует утверждение, выраженное в следую щ ей форме: (А v В v С) ^ (Q v R v S) --> W

Это выражение можно озвучить так: если хотя бы одно из утверждений каждой группы истинно, то элемент W примет значение ИСТИНА. Для наше г о а г ента это означает, что если дости г нута хотя бы одна из целей эффективности бизнеса и существует хотя бы один из приемлемых автобусных м аршрутов, то отпуск м ожно планировать. Определение м етода determineVacationAppropriate () представлено в листинге 12.10.

// Листинг 12.10. Второй метод рассуждений

bool agent:: determineVacationAppropriate(void) {

bool TruthValue;

Managerl.universe(PerformanceBeliefs);

Manager2.universe(PerformanceBeliefs);

Manager3.universe(PerformanceBeliefs);

Tripl.universe(TripBeliefs);

Trip2.universe(TripBeliefs);

Trip3.universe(TripBeliefs);

TruthValue = ((Managerl || Manager2 || Manager3) & &

(Tripl || Trip2 || Trip3)); return(TruthValue);

}

Обратите внимание на то, что списки TripBeliefs и PerformanceBeliefs являются аргументами метода universe() объектов Trip и Manager. Именно здесь объекты предположений получают информацию из предметной области (UniverseOfDiscourse). Прежде чем объект класса proposition вызовет оператор operator(), его контейнер UniverseOfDiscourse должен заполниться имеющимися у агента данными. В листинге 12.10 при вычислении выражения

((Managerl || Manager2 || Manager3) & & (Tripl || Trip2 || Trip3));

оценивается шесть предположений (посредством выполнения оператора " ||"). Оператор " | |" для каждого предположения выполняет оператор operator (), который для определения истинности предположения использует список UniverseOfDiscourse. Слелует иметь в виду, что классы trip_announcement Hperformance_statement наследуют довольно много функций класса proposition. В листингах 12.6 и 12.7 было показано, как определяется оператор operator() для класса trip_announcement, а в листинге12.11 приведено определение оператора operator () для класса performance_statement.

// Листинг 12.11. Класс performance_statement

bool performance_statement:: operator()(void) {

bool Satisfactory = false;

list< performance_statement>:: iterator I;

I = UniverseOfDiscourse.begin();

while(I! = UniverseOfDiscourse.end() & &! Satisfactory) {

if(((*I).bays() > = Bays) || ((*I).sales() > = Sales)

|| ((*I).perHour() > =PerHour)){ Satisfactory = true;

}

I++;

}

return(Satisfactory);

}

Оператор operator () для каждого класса proposition играет «свою» роль в способности класса агента делать логические выводы. В листинге 12.6 показано, как вызывается оператор operator () при каждом вычислении оператора " || " или " & & " для класса proposition или для одного из его потомков. Именно такое сочетание методов operator (), определенных в proposition-классах, и методов класса agent образует стратегии логического вывода для класса agent. В дополнение к операторам " ||" и " & & ", определенным в классе proposition, классы trip_announcement и performance_statement содержат свои определения.

friend bool operator||(bool X, trip_announcement & Y); friend bool operator& & (bool X, trip_announcement & Y);

Эти friend -объявления позволяют использовать предположения в более длинных выражениях. Сделаем следующие объявления.

//...

trip_announcement А, В, С; bool X;

X = А || В || С;

//...

При этом объекты А и В будут объединены с помощью операции ИЛИ, а результат этой операции будет иметь тип bool. Затем мы попробуем с помощью той же операции ИЛИ получить значение типа bool и объект типа trip_announcement: bool || trip_announcement

Без приведенных выше friend -объявлений такая операция была бы недопустимой. Определение этих функций-«друзей» показано влистинге 12.12.

// Листинг 12.12. Перегрузка операторов " ||" и " & & "

bool operator||(bool X, trip_announcement & Y) {

return(X | | YO);

}

bool operator& & (bool X, trip_announcement & Y) {

return(X & & Y());

}

Обратите внимание на то, что в определении этих функций-«друзей» (благодаря ссылке на элемент Y ()) также используется вызов функции operator (). Эти функции определяются и в классе performance_statement. Наша задача — сделать использование proposition-классов таким же простым, как использование встроенных типов данных. В классе proposition также определен другой оператор, который позволяет использовать предположение естественным образом. Рассмотрим следующий код.

//...

trip_announcement А; if(A) {

//... Некоторые действия.

}

//...

Как в этом случае компилятор тестирует объект А? При выполнении инструкции if () компилятор стремится найти в скобках значение целочисленного типа данных или типа bool. Но тип объекта А совсем другой. Мы хотим, чтобы ко м пилятор восприни м ал объект А как высказывание, которое м ожет быть либо истинны м, либо ложны м. При таких обстоятельствах функция operator () не вызывается. Поэто м у для получения нужного эффекта м ы определяем оператор void*. Эту функцию-оператор можно определить следующим образом.

template< class C> proposition< C>:: operator void*(void) {

return((void*)(TruthValue));

}

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

// Листинг 12.13. Метод displayTravelPlan()

void agent:: displayTravelPlan(void) {

stack< trip_announcement> Route;

if(Tripl){

Route = Tripl.candidates();

}

if(Trip2){

Route = Trip2.candidates();

}

if(Trip3){

Route = Trip3.candidates();

}

while(! Route.empty()) {

cout < < Route.top().origin() < < " TO " «Route.top().destination() «endl; Route.pop();

}

 

Обратите внимание на то, что объекты Tripl, Trip2 и Trip3 тестируются так, как будто они имеют тип bool. Метод candidates () просто возвращает путь следования, соответствующий заданному маршруту. Таким образом, разработка стратегий логического вывода и когнитивных структур данных становится проще благодаря использованию перегрузки операторов и С++-шаблонов. Именно стратегии логического вывода и когнитивные структуры данных делают объект рациональным. C++-программист для разработки агентов использует конструкцию класса, а для реализации когнитивных сгруктур данных (CDS) — контейнерные объекты в сочетании со встроенными алгоритмами. Класс, который содержит CDS-структуры, становится рациональным, а рациональный класс — агентом.

 

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.