Albatross
isa
Colour
Brown
\ ^^ movingmethod
;olour /
Black and white
Albert
\ isa
\
Ross
is a \
\act |
ActrVe_at night
<^
Walk
Рис, 15.5. Пример семантической сети
Обратите внимание, что отношение принадлежности (обозначается как "isa") иногда связывает класс объектов с суперклассом этого класса (животные — это суперкласс класса птиц), а иногда — экземпляр класса с самим классом (Альберт является альбатросом).
Данные, представленные с помощью сети такого рода, можно немедленно перевести на язык фактов Prolog, например, следующим образом:
isa( bird, animal) . % Птица - это животное
isa ( ross, albatross). % Росс - альбатрос
raoving_method( bird, fly).% Способ передвижения птиц - полет
moving_method< kiwi,walk). % Способ передвижения киви - ходьба
Кроме явно указанных фактов, на основании информации в этой сети могут быть выведены некоторые другие факты. Способы вывода других фактов встраиваются в
Глава 15.Представление знаний и экспертные системы
средства представления семантической сети конкретного типа как часть этого представления. К типичному встроенному способу вывода относится наследование. Поэтому в сети, приведенной на рис. 15.5, тот факт, что "альбатрос летает", может быть унаследован от факта "птицы летают". Аналогичным образом с помощью наследования могут быть получены факты "Росс летает" и "Ким ходит". Факты наследуются с использованием отношения isa. На языке Prolog можно указать следующим образом, что способ передвижения наследуется: moving_method ( X, Method) :-
isa [ X, superx), % Восхождение по иерархии isa
moving_irieth0d{ SuperX, Method). Но если бы для каждого отношения пришлось задавать отдельное правило наследования, то программа стала бы довольно громоздкой. Поэтому проще задать следующим образом более общее правило, касающееся фактов: "Факты могут быть либо явно заданы в сети, либо унаследованы":
(act(Fact) :- i Факт - не переменная; Fact = Rel ( Argl, Дгд2) Fact, !. % Факт задан в сети явно - наследование не требуется
fact (Fact) :-
Fact =.. [ Rel, Argl, Arg2J,
isa с arclt Su.erArgl, S Восхождение по иерархии isa
SucpterF S a uperFact) Re1' *"***", "**'
Теперь программе обработки этой семантической сети можно задать некоторые вопросы, например, следующим образом:
7- fact) moving method[ kim, Method) ) . Method = walk ~
Этот факт унаследован от явно заданного факта, что киви не летают, а ходят. С другой стороны, ответ на следующий вопрос является совсем иным:
?- fact ( moving method ( albert, Method)). Method - fly -
Этот факт был унаследован от класса bird. Обратите внимание на то, что унаследованным становится тот факт, который был получен первым при перемещении вверх по иерархии isa.
Фреймы
Б представлении знаний в виде фреймов факты ассоциируются с объектами. В этом контексте под "объектом" подразумевается конкретный физический объект либо более абстрактное понятие, такое как класс объектов или ситуация. Например, в виде фреймов удобно представить типичную ситуацию обмена мнениями или ситуацию игрового конфликта. Подобные ситуации, как правило, имеют некоторую общую, стереотипную структуру, которая может быть дополнена сведениями о конкретном событии.
Фрейм — это структура данных, компоненты которой называются слотами. Слоты обозначаются именами и применяются для размещения в них информации различного рода. Поэтому в слотах можно найти элементарные значения, ссылки на другие фреймы или процедуры, с помощью которых на основе какой-то иной информации может быть вычислено значение слота. Слот может также оставаться незаполненным. Незаполненные слоты могут заполняться с применением логического вывода. Как и в семантических сетях, наиболее широко применяемым принципом логического вывода является наследование. Если фрейм представляет собой класс объектов (таких как альбатросы), а другой фрейм - суперкласс этого класса (такой как птицы), то фрейм класса может наследовать значения от фрейма суперкласса.
Некоторые знания о птицах можно поместить во фреймы, например, следующим образом:
Часть II. Применение языка Prolog в области искусственного интеллекта
FRAME: bird
a_kind_of: animal
moving_methcd: fly
| |
active_at: daylight Этот фрейм содержит сведения о классе всех птиц. Три его слота сообщают о том, что птицы относятся (a_kir.d_of) к животным (животные — это суперкласс птиц), что типичным способом передвижения птиц (moving ir.ethod) является полет и что птицы являются активными (activeat) в дневное время. Ниже приведены фреймы для двух подклассов птиц — альбатросов и киви.
FRAME; albatross a_kind_of: bird colour: black and_white size: 115
FRAME kiwi a kind of: bird movingjriethod: walk active at: night colour: brown size: 40
Альбатрос — это очень типичная птица, которая наследует от фрейма птиц способность летать и дневную активность. Поэтому во фрейме albatross нет никаких сведений о способе передвижения moving method и периоде активности active at. С другой стороны, киви — это довольно нетипичная птица, поэтому при ее описании необходимо перекрыть обычные значения movingjuethod и active_at, характерные для птиц. Может быть также определен конкретный экземпляр класса, например альбатрос по имени Альберт, следующим образом:
FRAME Albert instance of: albatross size: 120"
Обратите внимание на различие между двумя отношениями, a_kind_of и instance_of. Первое является отношением между классом и суперклассом, а второе — отношением между членом класса и классом.
Информация о фреймах, применяемых здесь в качестве примера, может быть представлена на языке Prolog в виде множества фактов, таким образом, чтобы один факт определял значение каждого отдельного слота. Такую задачу можно выполнить несколькими способами. А в данном разделе используется следующий формат для представления таких фактов: Frame_name( Slot, Value]
Преимущество этого формата состоит в том. что теперь все факты о конкретном фрейме собраны в виде отношения, имя которого совпадает с именем самого фрейма. В листинге 15.10 показаны некоторые фреймы в таком формате.
Листинг 15.10. Некоторые примеры фреймов
% Фрейм представлен в виде множества фактов Prolog:
% frame name ( Slot, Value)
Здесь "Value - либо простое значение, либо процедура
% Фрейм bird - определение типичной птицы
bird) a kind_of, animal). bird( moving_method, fly) . bird{ active_at, daylight).
% Фрейм albatross; альбатрос - это типичная птица, но для его определения % нужны дополнительные факты: он черно-белкй и имеет в среднем длину 115 см
albatross С a_kind_of, bird).
Глава 15,Представление знаний и экспертные системы 351
albatross { colour, black_and_white) . albatross; size, 115) .
% Фрейм kiwi; киви - довольно нетипичная птица, поскольку она ходит, % а не летает, и активна в ночное время
kiwi[ a_kind_of, bird) . kiwi [ moving_method, walk) . kiwi( active_at, night) . kiwi( size, 40) . kiwi ( colour, bro«n) .
% Фрейм albert - экземпляр йзрослого альбатроса
albert( instance_of, albatross). albert( size, 120).
% Фрейм ross - экземпляр альбатроса-птениа
ross( instance of, albatross). rossi size, 40").
% Фрейм animal - слот relative size получает свое значение i в результате выполнения процедуры relative_size
animal ( relative size, execute ( relative size( Object, Value) , object, Value) ).
Для использования подобного набора фреймов необходима процедура, позволяющая осуществлять выборку фактов о значениях слотов. Реализуем такую процедуру выборки фактов как процедуру Prolog следующим образом:
value( Frame, Slot, Value)
где Value - значение слога Slot во фрейме Frame. Если слот заполнен определенным значением (так что его значение явно задано во фрейме), то оно и принимается в качестве требуемого значения; в противном случае происходит получение нужного значения с помощью логического вывода, например наследования. Чтобы найти значение с помощью наследования, необходимо перейти от текущего фрейма к более общему фрейму в соответствии с отношением a kind of или instance of между фреймами. Такой переход ведет к "родительскому фрейму", и искомое значение может быть найдено э этом фрейме явно или с помощью дальнейшего наследования. Эта операция непосредственной выборки или выборки путем наследования может быть определена на языке Prolog- следующим образом:
value { Frame, Slot, Value) :-
Query =.. [ Frame, Slot, Value],
call С Query), !. % Получение значения с помощью непосредственной выборки
value) Frame, Slot, Value) :-
parent { Frame, Parent Frame) , % Фрейм более общего типа
value ( ParentFrame, Slot, Value).
parent( Frame, ParentFrame) :-
( Query =.. { Frame, a_kind_of, Parent Frame]
Query =.. [ Frame, instance_of, ParentFrame]), call £ Query).
Эта процедура вполне позволяет находить значения во фреймах, показанных в листинге 15.10, например, с помощью следующих вопросов:
?- valuet albert, active_at, AlbertTime). AlbertTime = daylight
?- valuet kiwi, active_at, KiwiTirae). KiwiTime = night
352 Часть li.Применение языка Prolog в области искусственного интеллекта
Теперь рассмотрим более сложный случай логического вывода, при котором в слоте определена процедура вычисления значения вместо самого значения. Например, в одном из слотов для всех животных может быть задан их размер, установленный с учетом типичного размера взрослого экземпляра особи соответствующего вида. В таком случае относительные размеры двух альбатросов, описанных в листинге 15.10, заданные в процентах, составляют: Альберт- 104%, Росс - 35%. Эти цифры получены кик соотношение (и процентах) между размером конкретного индивидуума и типичным размером представителя класса этого индивидуума. Например, для альбатроса Росс это значение получено следующим образом:
40/115 * 100%= 34.78%
Итак, значение для слота relativesize получено путем выполнения некоторой процедуры. Эта процедура является в равной степениприменимой для всех животных, поэтому целесообразно определить слот relative_size во фрейме animal иввести в этот слот определение соответствующей процедуры. Теперь интерпретатор фреймов value должен быть способен ответить на такой вопрос:
?- value( ross, relative_size, R} . R = 34.78
Способ получения этого результата должен состоять примерно в следующем. Процедура начинает поиск с фрейма ross и, не обнаружив значения для relative size, поднимаемся вверх по цепочке отношений instance_of (чтобы перейти к фрейму albatross), a_k±nd_of (чтобы перейти к фрейму bird), и снова a_M.nd._of, чтобы, наконец, дойти до фрейма animal. Здесь обнаруживается процедура вычисления относительного размера. Для этой процедуры требуются значения из слота size фреймов ross и albatross. Эти значения могут быть получены с помощью наследования из существующей процедуры value. Остается лишь дополнить процедуру value, чтобы она учитывала случаи, в которых требуется выполнить процедуру в определенном слоте. Прежде чем это сделать, необходимо продумать, как такая процедура может быть (косвенно) представлена в виде содержимого слота, Предположим, что процедура вычисления относительного размера представлена в виде предиката Prolog следующим образом:
relativesize c Object, RelativeSize) :-
value ( ObjClass, size, ClassSize),
RelativeSize is objSize/ClassSize * 100. % процентная доля от размера класса
Теперь в слот relative_size фрейма animal можно ввести вызов этой процедуры. Чтобы предотвратить потерю параметров Object (Объект) и RelativeSize (Относительный размер) при взаимодействии фреймов, необходимо также определить их как часть информации слота relative size. Все содержимое этого слота можно собрать в один терм Prolog, например, как показано ниже. execute! relative_size ( Object, RelSize), Object, RelSize}
После этого слот relative_size фрейма animal определяется таким образом: animal! relative_size, execute! relative_size£ Obj, Val), Obj, Val)).
Теперь можно приступить к модификации процедуры value для обработки с ее помощью процедурных слогов. Прежде всего мы должны учесть, что информация, находящаяся в слоте, может представлять собой вызов процедуры, поэтому для ее дальнейшей обработки необходимо осуществить этот вызов. Для такого вызова в качестве параметров могут потребоваться значения слогов первоначально рассматриваемого фрейма. В старой версии процедуры value этот фрейм исчезал из памяти после перехода по иерархическому дереву к более общим фреймам. Поэтому необходимо определить первоначальный фрейм в качестве дополнительного параметра. Эта задача решается в следующем фрагменте программы:
value! Frame, Slot, Value):-
value{ Frame, Frame, Slot, Value).
Глава 15. Представление знаний и экспертные системы
% Непосредственная выборка информации из слота (супер) фрейма value) frame, SuperFrame, Slot, Value) ;-
Query-. . [ SuperFrame, Slot, Information],
call* Query!, % Значение, полученное с помощью непосредственной выборки
process< information, Frame, Value), !. % Информация может быть задана либо
% в виде значения, лиСо как вызов процедуры % Логический вывод значения с помощью наследования value) Frame, SuperFrame, Slot, Value) :-
paren tt SuperFrame, FarentSuperFrame),
value! Frame, FarentSuperFrame, Slot, Value). % process) Information, Frame, Value)
process! execute! Goal, Frame, Value), Frame, Value) :— ! ,
call ( Goal) . process! Value, _, Value). ч Значение, а не вызов процедуры
Введя указанное дополнение в интерпретатор фреймов, мы вступили в область применения такого подхода к программированию, как объектно-ориентированное программирование. Хотя при описании указанного подхода обычно применяется иная терминология, его реализация фактически основана на активизации выполнения процедур, которые принадлежат к разным фреймам.
Применение логического вывода, основанного на переходе между фреймами, характеризуется многими нюансами, которые здесь не рассматриваются. Коснемся лишь вопроса множественного наследования. Необходимость в его использовании возникает, если фрейм имеет больше одного "родительского" фрейма (согласно отношению instance_of или a_kind_of). При этом унаследованное значение слота может быть получено больше чем от одного родительского фрейма, и возникает вопрос, на каком из них следует остановиться. Процедура value в том виде, в каком она определена в этом разделе, просто принимает первое обнаруженное значение, которое найдено с помощью поиска в глубину среди фреймов, обладающих способностью предоставить такое значение. Но могут оказаться более приемлемыми другие стратегии или правила выбора среди нескольких альтернатив.