VIII. Produktionssysteme
- Produktionssysteme
- Auswertung
- Darstellung in PROLOG
- Ein grundlegender Auswerter für Produktionssysteme
- Konfliktauflösung
© 2001
François Bry
Dieses Lehrmaterial wird ausschließlich zur privaten Verwendung
angeboten. Eine nichtprivate Nutzung (z.B. im Unterricht oder eine
Veröffentlichung von Kopien oder Übersetzungen) dieses Lehrmaterials
bedarf der Erlaubnis des Autors.
wenn Bedingung-1,
Bedingung-2,
.
.
.
Bedingung-n
dann Aktion-1,
Aktion-2,
.
.
.
Aktion-m
bei Ereignis
wenn Bedingung-1,
Bedingung-2,
.
.
.
Bedingung-n
dann Aktion-1,
Aktion-2,
.
.
.
Aktion-m
F
.F
.F
in ein Faktum
G
.A1, ..., An
von Aktionen wird
dadurch durchgeführt, daß die einzelne Aktionen in der
Reihenfolge der Sequenz durchgeführt werden.
sigma(B ---> A)
,
deren Bedingungsteil sigma(B)
erfüllt ist. Man
sagt auch, daß diese Regelinstanzen anwendbar sind
oder feuern können.
sigma(B ---> A)
ausgewählt, so wird nun der Aktionsteil
sigma(A)
durchgeführt.
_ : Bedingungsteil *--> Aktionssequenz
:
wird für
unten erläuterte Zusatzinformationen verwendet,
etwa für einen Regelidentifikator.
+ F
das Faktum F
hinzufügen.- F
das Faktum F
löschen.F -> G
das Faktum F
durch das Faktum G
ersetzen.
:- op(1200, xfx, :), op(1190, xfx, *-->).
auswerten(Ziel) :- Ziel.
auswerten(Ziel) :- konfliktmenge(Menge),
auswaehlen((_ : _ *--> A), Menge),
durchfuehren(A),
auswerten(Ziel).
konfliktmenge(Regelinstanzen) :- setof( (I : B *--> A),
( (I : B *--> A), B ),
Regelinstanzen ).
durchfuehren( (A1,A2) ) :- !, durchfuehren(A1), durchfuehren(A2).
durchfuehren(+F) :- F, !. %%% optional
durchfuehren(+F) :- !, assert(F).
durchfuehren(-F) :- retract_all(F), !.
durchfuehren(F -> G) :- !, durchfuehren(-F), durchfuehren(+G).
durchfuehren(Programmaufruf) :- Programmaufruf.
retract_all(X) :- retract(X), fail.
retract_all(_).
auswaehlen
nicht definiert. Der nächste
Abschnitt beschäftigt sich damit.
auswaehlen
die Konfliktauflösung durch.
Das Regelsystem wird so definiert, daß zu jeder Zeit höchstens eine Regelinstanz anwendbar ist, also feuern kann.
Dazu werden bestimmte Fakten ausgezeichnet, die einen sogenannten Kontext beschreiben. Für jeden Kontext gibt es kontextspezifische Regeln, die das Vorhandensein der entsprechenden Fakten in ihrem Bedingungsteil testen. Andere Regeln dienen dazu, den Kontext zu wechseln, indem sie die entsprechenden Fakten austauschen.
Betrachten wir das Beispiel eines medizinischen Diagnosesystems. Ein Kontext entspricht der Untersuchung einer Hypothese. Beim Symptom "verstopfte Nase" kann zum Beispiel jede der Hypothesen "Allergie" und "Erkältung" einen Kontext bilden. In derartigen Anwendungen erweist sich der Ansatz der kontextuellen Einschränkung oft als natürlich und sinnvoll.
Diese Vorgehensweise kann durch das Refraktionsprinzip ergänzt werden. Nach diesem Prinzip darf eine "gleiche" Regelinstanz nicht zweimal feuern. Die Gleichheit, die dabei berücksichtigt wird, unterscheidet oft "gleiche" Fakten nach den Zeitpunkten ihrer Generierung.
Zur Implementierung des Refraktionsprinzips werden wir ein
Faktum F
darstellen als:
faktum(Id, F).
wobei Id
ein Identifikator (englisch "tag") des
Vorkommens von F
sein wird. Die Fakten des
Produktionssystems können entweder alle denselben
Identifikator 0 erhalten, oder verschiedene Identifikatoren.
Später generierte Fakten werden dann natürliche Zahlen als
Identifikatoren erhalten: je größer die Zahl, desto neuer
das Vorkommen des Faktums.
durchfuehren
an
diese Darstellung der Fakten:
:- dynamic(faktum/2), dynamic(id_zaehler/1).
durchfuehren( (A1,A2) ) :- !, durchfuehren(A1), durchfuehren(A2).
durchfuehren(+F) :- faktum(_, F), !. %%% optional
durchfuehren(+F) :- !, neu_id(Id), asserta(faktum(Id, F)).
durchfuehren(-F) :- retract_all(faktum(_, F)), !.
durchfuehren(F -> G) :- !, durchfuehren(-F), durchfuehren(+G).
durchfuehren(Programmaufruf) :- Programmaufruf.
id_zaehler(1).
neu_id(I) :- retract( id_zaehler(I) ),
Iplus1 is I + 1,
assert( id_zaehler(Iplus1) ).
RId
:
RId : Bedingungsteil *--> Aktionssequenz
(RId, Bedingungsteil-Id)
wobei Bedingungsteil-Id
die absteigend
sortierte Liste der Identifikatoren der Fakten ist, mit
denen der Bedingungsteil erfüllt wurde.
1 : s(X) *--> +t(X).
2 : p(X), q(X) *--> +u(X).
3 : p(X), q(X), r(X) *--> +v(X)
4 : q(X), r(X) *--> +w(X).
faktum(2, q(a)).
faktum(6, p(a)).
faktum(7, s(a)).
faktum(8, r(a)).
(1, [7] ) : s(a) *--> +t(a).
(2, [6,2] ) : p(a), q(a) *--> +u(a).
(3, [8,6,2]) : p(a), q(a), r(a) *--> +v(a).
(4, [8,2] ) : q(a), r(a) *--> +w(a).
(2, [6,2])
ausgewählt, dann wird in die PROLOG-Datenbank
das PROLOG-Faktum
hat_gefeuert(2, [6,2])
hinzugefügt.
durchfuehren
aus
P77 arbeitet.
:- op(1200, xfx, :), op(1190, xfx, *-->),
dynamic(hat_gefeuert/2).
auswerten(Ziel) :- faktum(_, Ziel).
auswerten(Ziel) :- konfliktmenge(Menge),
auswaehlen((RId, BId, ASeq), Menge),
durchfuehren(ASeq),
asserta( hat_gefeuert(RId, BId) ),
auswerten(Ziel).
konfliktmenge(RegelinstanzDeskriptoren) :-
setof( (RId, BId, ASeq),
B^( (RId : B *--> ASeq),
erfuellt(B, [], BId),
not hat_gefeuert(RId, BId) ),
RegelinstanzDeskriptoren ).
erfuellt( (B,C), L1, L) :- !, faktum(Id,B),
einsortieren(Id, L1, L2),
erfuellt(C, L2, L).
erfuellt( not B, L, L) :- !, not erfuellt(B, _, _).
erfuellt((X = Y), L, L) :- !, X = Y.
erfuellt( B, L1, L) :- faktum(Id,B), einsortieren(Id, L1, L).
einsortieren(E, [], [E]).
einsortieren(E, [K|R], [E,K|R]) :- E > K, !.
einsortieren(E, [K|R], [K|R]) :- E = K, !.
einsortieren(E, [K|R], [K|S]) :- einsortieren(E, R, S).
not hat_gefeuert(RId,BId)
bei der
Berechnung der Konfliktmenge ist das Refraktionsprinzip
implementiert. Das Prädikat auswaehlen
ist noch
nicht definiert, da es von den übrigen Prinzipien der
Konfliktauflösung abhängt.
RegelinstanzDeskriptoren
der
Konfliktmenge, also aus den Tripeln (RId, BId,
ASeq)
, dasjenige Tripel auszuwählen, dessen
Bedingungsidentifikator BId
maximal bezüglich
der lexikographischen Ordnung ist. Dadurch bekommt das
Neuheitsprinzip den Vorrang vor dem
Spezifitätsprinzip.
8
, so daß nur die Regelinstanzen mit den
Identifikatoren (3, [8,6,2])
und (4,
[8,2])
in Frage kommen. Nach dem Spezifitätsprinzip
hat die Instanz der Regel 3
Vorrang vor der anderen.
Da die Listen absteigend sortiert sind, ist die Liste, die
weniger Element enthält, nach der lexikographischen Ordnung
kleiner.
@<
für die lexikographische Ordnung
wird diese Konfliktauflösung durch folgende Definitionen
geleistet:
auswaehlen(Max, [Max]).
auswaehlen(Max, [K|R]) :- listmax(R, K, Max).
listmax([K|R], Alt, Max) :- kleiner(K, Alt), !,
listmax(R, Alt, Max).
listmax([K|R], Alt, Max) :- listmax(R, K, Max).
listmax([], Max, Max).
kleiner(Tripel1, Tripel2) :- bedingungs_id(Tripel1, BId1),
bedingungs_id(Tripel2, BId2),
BId1 @< BId2.
bedingungs_id( (_RId, BId, _ASeq), BId).
id_zaehler
für die hergeleiteten Fakten mit dem
Startwert 1, im zweiten Fall mit dem Startwert n+1
definiert werden.
id_zaehler
.
:- [user].
1 : s(X) *--> +t(X).
2 : p(X), q(X) *--> +u(X).
3 : p(X), q(X), r(X) *--> +v(X).
4 : q(X), r(X) *--> +w(X).
faktum(2, q(a)).
faktum(6, p(a)).
faktum(7, s(a)).
faktum(8, r(a)).
yes.
:- konfliktmenge(Menge).
Menge = [ (1, [7], +(t(a))), (2, [6, 2], +(u(a))),
(3, [8, 6, 2], +(v(a))), (4, [8, 2], +(w(a))) ]
yes.
:- auswerten( t(X) ).
X = a More? (;)
yes.
:- listing(faktum/2), listing(hat_gefeuert/2).
faktum(13, t(a)).
faktum(12, w(a)).
faktum(11, v(a)).
faktum(2, q(a)).
faktum(6, p(a)).
faktum(7, s(a)).
faktum(8, r(a)).
hat_gefeuert(1, [7]).
hat_gefeuert(4, [8, 2]).
hat_gefeuert(3, [8, 6, 2]).
yes.
Letzte Änderung: 18. August 1998