logo search
TurboProlog / Документация / TOM_2

Расширения экспертной системы

В этом разделе мы рассмотрим предикаты unify_body и call, настоящей

оболочки экспертной системы, используемые в механизме вывода, обсужденном

в предыдущих разделах данного приложения.

Используемые оболочкой области термов более или менее совпадают с

уже описнными. Поэтому мы не станем выписывать предложения для

unify_term, т.к. в них нет ничего нового.

Определение этой оболочки включает три требования, выходящие за пре-

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

1. Фактор уверенности формирует часть правил и выводов из них.

2. Если пользователю задан вопрос, то система всегда может объ-

яснить, почему она его задала.

3. Все выводы могут быть объяснены с помощью ссылок на предыду-

щие рассуждения.

Эти требования суммированы в трех дополнительных аргументах предика-

та unify_body.

1. real, являющийся фактором уверенности, созданным заключением

подцели.

2. Терм, являющийся заголовком выполняемого в даныый момент

правила; он позволяет системе сформулировать фразу: "Я задаю

этот вопрос, потому что пытаюсь устаносить <заголовок правила>.

3. Статический терм, осуществляющий продвигающуюся вперед трас-

сировку; он будет получать установленную версию тела, над кото-

рой работает unify_body, подразумевая, что термы, которые явля-

ются переменными в процессе перехода тела в unify_body и call,

будут изменены на те значения, которые они получат в процессе

выполнения.

Поместив эти установки тела в базу данных, любое заключение можно

будет объяснять ссылкой на ранее доказанные положения.

Конечно, мы не приводим здесь всю программу. Это только показ воз-

можного расширения возможностей первоначального механизма вывода. Дейст-

вительный код для unify_body и call выглядит так:

predicates

nondeterm unify_body(sTerm, sTerm, real, env, aTerm)

nondeterm call(string, aTermList, real, aTerm)

unify_body_once(sTerm, sTerm, real, env, aTerm)

clauses

call(true_tok, [], 1.0,_):-!.

call("=", [X, X], 1.0,_):-!.

call(Eval_tok, [Res, T2], 1.0,_):-!.

bound(T2), !,

eval(T2, r),

Res=R.

call(ID, ATermList, Cf,_):-

fact(_, cmp(ID, STermList), Cf),

free(E),

unify_terml(ATermList, STermList, E), !.

call(ID, ATermList, Cf,_):-

rule(Rule_Numder, cmp(ID, ATermList1), Body, Ruke_Cf,_),

free(Env),

unify_terml(ATermList, ATermList1, Env),

FID=ID,

unify_body_once(Body, Sbody, Cf_Out, Env, cmp(FID,ATermList)),

unify_terml(ATermList, STermList, Env),

min(Cf_out, Rule_Cf, Cf),

asserta(fact(Rule_Number, cmp(ID, STermList), Cf)),

conclude(cmp(ID, STermList), Sbody, Cf, Env).

call(ID, ATermList, Cf, Mum):-

question(Rule_Number, cmp(ID, STermList), Proplist),

free(E),

unify_terml(ATermList, STermList, E),

FID =ID,

askuser(cmp(FID, ATermList), Cf, Proplist, Mum, E),

unify_terml(ATermList, STermList1, E),

asserta(fact(Rule_Number, cmp(ID, STermList1), Cf)),

unify_body_once(Body, Sbody, Cf_Out, Env, Mum):-

unify_body(Body, Sbody, Cf_Out, Env, Mum), !.

unify_body(cmp(and_tok, [Term1, Term2]),

cmp(and_tok, [ST1, ST2]), Cout, Env, Mum):- !,

unify_body(Term1, ST1, Cf1, Env, Mum), Cf1>0.0,

unify_body(Term2, ST2, Cf2, Env, Mum), Cf2>0.0,

min(Cf1, Cf2, cout).

unify_body(cmp(or_tok, [T1, T2]), STerm, Cf, Env, Mum):-

unify_body(T1, STerm, Cf, Env, Mum),

Cf>0.0;

unify_body(T2, STerm, Cf, Env, Mum),

Cf>0.0 !.

unify_body(cmp(or_tok, TL1), cmp(or_tok, TL2), 0.0, Env,_):- !,

unify_term1(T, TL1, Env),

unify_term1(T, TL2, Env),

unify_body(cmp(not_tok, [ATerm]), cmp(not_tok,

[NTerm]), Cout, Env, Mum):- !,

unify_body(ATerm, NTerm, Cf, Env, Mum), !,

cout= 1.0-Cf, Cout>0.0.

unify_body(cmp(not_tok, [ATerm]), cmp(not_tok,

[NTerm]), 1.0, Env,_):- !,

unify_term(T, ATerm, Env),

unify_term(T, NTerm, Env).

unify_body(cmp(ID, ATermList), cmp(ID, TL), Cf, Env,Mum):-

unify_term1(Call, ATermList, Env),

FID=ID,

Call(FID, Call, Cf, Mum),

Cf>0.0,

unify_term1(Call, TL, Env).

Символические константы (такие как and_tok) получают свои действи-

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

самым облегчая разработку различных статических идентефикаторов.

Первый аргмент unify_body - это аргумент ввода, как и в первоначаль-

ном механизме вывода, в то время как второй - это версия вывода с уста-

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

на примере трех предложений для дизъюнкции (or_tok): если не выполняются

обе возможности, предусмотренные для дизъюнкции, то нам все равно надо

выполнить двойное объединение термов, чтобы получить какие-либо значения,

которые могут быть в среде, объясняющие терм:

unify_body(cmp(or_tok, TL1), cmp(or_tok, TL2), 0.0, Env,_):- !,

unify_term1(T, TL1, Env), unify_term1(T, TL2, Env),

Невыполнение по-прежнему вызывается успешным выполнением с уверен-

ностью 0.0. То же самое происходит в случае not:

unify_body(cmp(not_tok, [ATerm]), cmp(not_tok,

[NTerm]), Cout, Env, Mum):- !,

unify_body(ATerm, NTerm, Cf, Env, Mum), !,

cout= 1.0-Cf, Cout>0.0.

unify_body(cmp(not_tok, [ATerm]), cmp(not_tok,

[NTerm]), 1.0, Env,_):- !,

unify_term(T, ATerm, Env),

unify_term(T, NTerm, Env).

Если вызывается второе предложение для not, то это означает, что

ATrem не может быть выполнен: поэтому мы достигли успеха с вероятностью

1.0. Это показывает одну из сложностей, связанных с предикатом not; на

самом деле not не генерирует значения, противоположного своему аргументу,

поэтому неуспех при попытке выполнить not может возникнуть только при

факторе уверенности равном 0.0. Фактор уверенности 0.00001 уже будет рас-

ценен как успех.

Последнее предложение unify_body:

unify_body(cmp(ID, ATermList), cmp(ID, TL), Cf, Env,Mum):-

unify_term1(Call, ATermList, Env),

FID=ID,

Call(FID, Call, Cf, Mum), Cf>0.0,

unify_term1(Call, TL, Env).

затем вызывает call и унифицирует терм из списка термов, возвращенного из

call. Мы не станем углубляться в детали работы предиката call (хватит -

значит хватит). Достаточно сказать, что база данных содержит три различ-

ных структуры: факты, правила и вопросы. Это противоречит только одной

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

предикатом clause.

Когда нужно выполнить требование некоторой подцели, то система пер-

вым делом смотрит, может ли это быть получено как факт. Если нельзя, сис-

тема ищет правило и, если это также не получается, она ищет вопрос, кото-

рый можно задать пользователю. Обратите внимание, что успех или неуспех

правила или вопроса поступает в базу данных как факт, чтобы избежать за-

давания одно и того же вопроса или вычисления одного и того же правила по

нескольку раз.

Запоминание полученных результатов является очень удобной стратеги-

ей, когда база правил работает только с принятием или отвержением гипоте-

зы, т.к. позволяет значительно экономить время работы процессора. Но эта

стратегия становится плохой, если правила включают предикаты, дающие по-

бочные эффекты, как в примерах рассмотренных ранее. Это пример определе-

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

гипотезы и побочными эффектами, к которым может привести ее доказательст-

во.