Wissensverarbeitung für Wirtschaftsinformatiker
Jürgen Dorn und Markus Stumptner
Achtung: Diese Mitschrift ist nicht autorisiert. Für Fehler und Auslassungen bin ich allein verantwortlich, weder die Professoren, noch die Tutorin.
Aktuelle Informationen zur Vorlesung
Prüfung und Klausur: 16. 6. 2000 (vor allem Fragen zu Prolog)
Komplettes Skriptum kommt später erst raus; kann in Teilen von der Homepage runtergeladen werden. (Wenn es nicht verständlich ist, bitte melden.)
Vier Aufgaben müssen in Prolog gelöst werden.
Unterstützung durch Tutorin: Bibiane Angerer
Termine: per e-mail anfragen, default Freitag 14-16 Uhr Favoritenstraße 11 Praktikumsraum HE 03.24, 3. Stock. 1. Termin: 17. 3. 14 Uhr, Einführung in SWI am PC.
SWI Prolog von der Uni Amsterdam (Link von der Übungshomepage).
Die Aufgaben müssen der Tutorin vorgeführt werden.
Eine Gruppe darf höchstens 3 Mitglieder haben, auch Einzelarbeiten möglich.
Wählen Sie ein Restaurant
Speisekarte des Restaurants mit Prolog
Programm, das alle Kombinationen von Menus ausgibt, die weniger als ein
vorgegebener Preis kosten
menu(X, 120)
Eine mögliche Antwort wäre: X=[pizza_margarita, tiramisu, cola]
Abgabe bis 24. 3. 2000
(eine ähnliche Aufgabe könnte zur Prüfung kommen)
Objekte des Restaurants (u.a. Zutaten zu Speisen)
"frame-basierte" Repräsentation
Vererbung und part-of-Beziehung
Anfragen
parts_of(restaurant). has(menu, zucker)
kürzester Transport bestellter Speise mit A*-Algorithmus
prototypisches Netz von ca. 50 Knotenpunkten, mit Schätzung von Koordinaten
Speise aus unterschiedlichen Restaurants
Abgabe bis 21. 4. 2000
Kundenprofil speichern
Auswahlmenü dynamisch an das Profil anpassen
verzweigte Abfragestruktur
das Aussagekräftigste zuerst
Lernalgorithmus ID3
Abgabe bis 2. 6. 2000
Anmeldung für die Übung per e-mail bei witutor: Matrikelnr, Studienkennzahl, Name usw.
Einführung in Wissensbasierte Systeme
Prolog
Wissensrepräsentation (Frame-Notation)
Constraint Verarbeitung
Wissensbasierte Suche
Wissensbasierte Planung
Wissensbasierte Konfiguration
Maschinelles Lernen
Neuronale Netze
Data Mining
Künstliche Intelligenz
Wissensbasierte Systeme (WBS) bzw. Expertensysteme (XPS)
Wofür können Wissensbasierte Systeme eingesetzt werden?
Regelbasierte Systeme
Zu hoher Anspruch.
Kriterium für Intelligenz: Turing-Test
(Ein Computer imitiert einen Menschen so, daß der Unterschied von
außen nicht festgestellt wird)
"das Salz in der Suppe": Maschinelles Lernen
Lernen von Objektattributen
neue Situationen
neue Inferenzen
aber keine tiefe Bedeutung
Auch neuronale Netze führen nur Klassifizierungen innerhalb vorgegebener Attribute durch.
Maschinelles Beweisen
Spielprogramme (Schach, Go, ...)
Verstehen natürlicher Sprache
Bildverarbeitung
Expertensysteme
Robotik
"Experten" verwenden sowohl heuristisches, auf Erfahrungen basierendes Wissen, aber auch Allgemeinwissen. Dieses "common sense knowledge" ist in Expertensystemen nicht gut darstellbar.
(Akku leer)
assertz(est_mere(mme_Pelloux, regine)).
Fakt soll immer gelten. Jede Eingabe mit Punkt abschließen!
Oder: eine ASCII-Textdatei [wissensbasis].pl schreiben und mit consult() oder [] laden.
Wenn ein Dateiname unter "" angegeben wird, können auch eine Verzeichnisstruktur und eine Endung angegeben werden.
Die Wissensbasis ist im Hauptspeicher, Prolog ist kein Datenbanksystem!
Nach halt. ist das Wissen weg. Zustände können aber abgespeichert werden.
<unix>Initialisierung mit [home]/.plrc oder mit der -f -Option.</unix>
<windows>Initialisierung mit ini.pl-Datei z.B.: :-file_search_path(speisen, 'c:\Wissensbasis\Speisekarten').</windows>
?- vorspeise(V). V=cresson ?- vorspeise(cresson). yes ?- vorspeise(tomate). no %nicht in der Wissensbasis
Weitere Antworten mit ; ansehen, am Ende sagt Prolog "no".
speise(S) :- fleischSpeise(S). speise(S) :- fischSpeise(S).
oder
speise(S) :- fleischSpeise(S); fischSpeise(S).
mahlzeit(V, H, D) :-
vorspeise(V),
speise(H),
dessert(D).
V, H, D genügen der Relation mahlzeit, wenn V der Relation vorspeise genügt usw.
Prozedurale Interpretation: Ausführung von mahlzeit bedeutet: Ausführung von vorspeise usw.
Um sofort alle Ergebnisse auszugeben:
findall([V, H, D], mahlzeit(V, H, D), L).
In die Liste L werden alle Elemente der Lösung reingeschrieben.
Einschränkung auf Fisch:
mahlzeit(V, H, D), fischSpeise(H).
(Akku leer)
Wissensbasis als Baumstruktur: Funktoren als Wurzel
Unifikation von Teilbäumen: Vergleich der Teilbäume / Instantiierung von Variablen zur Substitution
Kopf + '.' + Rest der Liste:
.('P', .('r', .('o',.('l',.('o',.('g',[]))))))
['P', 'r', 'o', 'l', 'o', 'g']
"Prolog" /* für Zeichenketten */
aber 'Prolog' ist ein Atom (auch wenn großgeschrieben)!
Überprüfung, ob ein Element in der Liste ist (typische Prüfungsfrage):
Normalerweise können wir immer nur aufs erste Element zugreifen, den Rest müssen wir rekursiv aufrufen.
member(X, [X|_]). member(X, [_|Y] :- meber(X, Y). /* Aufruf: member(l, "Prolog"). | teilt die Liste auf => X = P. Wäre P gesucht, würde das Prädikat Erfolg haben. Zweite Klausel wird rekursiv aufgerufen: Fragt, ob das erste Element der Restliste dem gesuchten Zeichen entspricht. member(A, "Prolog"). Gibt A=P aus, weil A durch P (erstes Zeichen) unifiziert werden kann */
Hinweis: Listen sollten in der Verarbeitung, aber nicht in der Wissensrepräsentation benutzt werden, da das die Änderung erschwert. Besser ist es, wenn für jedes Objekt eine eigene Klausel existiert. Listen sind aber für die Verarbeitung effizienter; z.B. dynamisch eine Liste aller Speisen erstellen und mit denen arbeiten.
Geschachtelte Listen:
hors_d_oeuvres([[truffes_sous_le_sel, 212], [artichauts_melanie, 150]]).
Vorspeise mit weniger als 200 Kalorien:
find(X, [[X,C]| _]) :- c < 200.
find(X, [_|Y]) :- find(X, Y).
Zugriff auf X-tes Element: [X1, X2, X3, | Rest]
Wenn Cut in einer Regel ausgeführt wird, wird jegliches Backtracking linksvom Cut-Operator verhindert.
Anwendungsfälle:
Ziel
ist erreicht, keine weitere Suche mehr:
est_mere(mme_pelloux, regine) :- !.
Die
Lösung ist falsch, es soll nicht mehr weitergesucht werden:
not(C) :- C, !, fail. not(C).
es
muß keine Information für Backtracking gespeichert werden
(prozeduraler Stil):
a(X) :- b(X, Y), c(Y, Z), !, a(Z).
Beispiel:
plat(P), P/=grillade-de-boeuf, !.
/* gibt die erste Lösung und hört auf*/
Fazit: Cut sollte nur sparsam für die eigentliche Wissensverarbeitung verwendet werden, wo notwendig.
Notwendig z.B. bei mehrfacher Vererbung und widersprüchlichen Klauseln in den Eltern-Klassen.
Prädikate können als Operatoren interpretiert werden.
Normale Prädikate: präfix (vor den Argumenten):
est_mere(mme_Pelloux, regine).
In der Mathematik typische Infix-Notation:
Y = X ** 2 + 3 * X + 5 wäre in Präfix: =(Y,
+(+(**(x, 2), *(x, X)), 5))
Postfix-Notation: n!
Operatoren gestalten das Programm lesbarer, sind aber (für den Computer) nicht notwendig. Syntax ändert sich, aber die Verarbeitung nicht.
Für Frames sollte nicht eine einfache Liste genommen werden, sondern Operatoren definiert, die die Eigenschaften beschreiben und lesbarer trennen.
1. Position des Operators (f) und der Argumente
(x und y)
fx und fy = Prefix
xfx, xfy und yfx = Infix
xf und yf = Postfix
2. Präzedenz (Reihenfolge der Bindung bei unterschiedlichen Operatoren)
(Spielt nicht nur bei der Berechnung, sondern auch bei der Unifikation eine Rolle.)
z.B. Präzedenz von * ist höher als von +
3. Assoziativität (Reihenfolge der Bindung bei mehreren gleichen Operatoren)
Rechtsassoziativität: xfy, z.B. a - (b -
c)
Linksassoziativität: yfx, z.B. (a - b) -
c
Merkregel: x ist ein Term, der nur durch stärkere
Operatoren gebunden wird (oder Atom). y ist der Rest.
and(C1, C2) :- C1, C2.
or(C1, C2) :- C1; C2.
op(60, yfx, 'and').
op(61, yfx, 'or').
/* nicht üblich! Normalerweise bindet and stärker
*/
op(950, xfy, ---).
op(949, xfy, ::).
op(948, xfy, :).
carte_menu(
chevalier --- hors_d_oeuvre::
artichauts_melanie: 150: 75::
truffes_sous_le_sel: 202: 160::
(...)
--- viande ::
grillade_de_boeuf: 532: 180 ::
(...)
(ISO-Norm und allgemein definierte Prädikate)
Bedeutung der abkürzenden Schreibweise für den Modus von Argumenten:
+ das Argument muß instantiiert sein
(Eingabeparameter)
? das Argument kann instantiiert oder frei sein
@ kann zusammengesetzter Term sein
- muß eine Variable sein, die durchs Prädikat
instantiiert wird (Ausgabevariable)
true, fail
X = regine.
/= nicht unifizierbar
not(not(dessert(X)) => X wird nicht unifiziert sein
Variable "ausführen" (wenn ich weiß, daß sie
ein Prädikat enthält): call(X).
var(X), nonvar(X) ist die Variable belegt (instantiiert)?
Typüberprüfung:
atom(X).
number(X) :- integer(X); float(X).
atomic(X) :- number(X); atom(X).
compound(x) :- not(atomic(X), var(X)).
/* Term aus verschiedenen Variablen/Atomen */
functor(@Term, +Functor, +Number)
/* Funktor-Definition, Anzahl der Argumente*/
arg(+Number, +Term, ?Argument)
/* Was ist das X-te Argument? */
-nonvar =.. +list
/* Zusammensetzen von Prädikaten, sog. univ-Operator. Erlaubt, Operatoren selbst zusammenzusetzen.*/
atom_chars(?Atom, ?List)
/* Zusammensetzen von Zeichenketten zu Atomen */
recorda(20, est_mere(madame_Pelloux, regine)).
recorded()
/* für effizientere Speicherung mit einem Index */
listing.
clause(+Head, ?Tail)
/* wie eine Regel oder Fakt bewiesen wird */
abolish(+Name, +Arity). /* Alles mit diesem Namen löschen
*/
abolish(Functor/N).
retract(est_mere(mme_Pelloux, regine)).
/* Einzelne Aussage aus der Wissensbasis löschen */
retractall(dessert(X)). /* Alle dessert-Aussagen löschen
*/
asserta(counter(1)).
Retract(counter(X)), X1 is X + 1, asserta(counter(X1)).
/* Globale Variable simulieren. Ineffizient, nur in Notfällen
verwenden. */
findall(+Var, +CompoundTerm, -List)
bagof(): auch doppelte Lösungen werden ausgegeben
setof(): Liste sortiert (im Wesentlichen alphabetisch)
Traditionelles Verhalten: bei einem assert()
während eines Prädikats kann die Wissensbasis geändert
werden.
Standard und SWI-Prolog: neues Fakt darf im Backtracking innerhalb des Prädikats nicht gefunden werden.
Ströme
Standardeingabestrom Terminalfenster
Standardausgabestrom Terminalfenster
Öffnen eines Stroms
open(+File, +Mode, -Stream)
Mode = {read|write|append|update}
Schließen des Stroms
close(+Stream)
Generisch: write_term(+T, +O) oder write_term(+S, +T,
+O)
üblicherweise: write(+T) oder write(+S,
+T)
write(poisson or viande) >> poisson or viande
write_canonical(poisson or viande) >> or(poisson,
viande)
/* "kanonische" Form */
put(X) /* Steuerzeichen */
nl /* Zeilenvorschub */
read_term(-X), read(-X) /* oder mit (+S, -X) */
Ein Punkt ist Endekriterium im Eingabestrom.
get(X) bzw. get_char(X) /* liest ein druckbares Zeichen ein */
peek_char(X) /* lesen, ohne Dateizeiger zu bewegen */
skip(X)
trace schaltet den "trace mode" ein, jeder
Klauselaufruf wird am Terminal ausgeben.
notrace schaltet das ab.
debug / nodebug /* Debugger */
spy(+Pred), nospy(+Pred) /* Haltepunkt, schrittweise Debuggen ab da
*/
Wissen: Information dargestellt in einer Weise, die zu neuem Wissen verknüpft werden kann
Ein System heißt wissensbasiert, wenn es Weltwissen deklarativ (auch deskriptiv) in Form einer Wissensbasis speichert und verwendet.
Eine Wissensbasis ist eine Datenstruktur, die als Beschreibung von Zuständen der Welt interpretiert werden kann.
Deklaratives Wissen beschreibt, wie die Welt ist.
Theoretische Vorteile: modular, veränderbar, verstehbar, erklärbar, verwendungsunabhängig (in der Praxis schwierig)
In der Praxis mehr oder weniger ausgeprägt
Symbolbasierte Darstellung (Symbol: Name eines Objekts in der Wissensbasis):
Explizite Bezeichnungen für Objekte und Beziehungen
andere Darstellungen: neuronale Netze, genetische Algorithmen.
Prolog ist keine Wissensrepräsentationssprache, da nicht voll deklarativ.
Es soll die Möglichkeit geben, nicht eindeutige Aussagen darzustellen:
ungenauer sprachlicher Ausdruck
unzuverlässige/statische Informationen ("in der Hälfte der Fälle")
ungenaue Informationen (z.B. von Meßgeräten)
Zusammenfassung von Informationen, die aus mehreren Quellen stammen
Logikorientierte Methoden
Prädikatenlogik
nichtmonotone Logiken (Defaultlogik)
Produktionsregeln: für klassische Expertensysteme verwendet, heute weniger.
Objektorientierte Methoden (Frames): Wissen wird über ein Objekt der realen Welt dargestellt.
Semantische Netze
Constraints: Spezielle Art von relationalen Tabellen, wobei die Tabelle nicht konkrete Daten, sondern mögliche Werte enthält. Bei der Verknüpfung mehrerer Tabellen können dann Lösungen ermittelt werden. Viele Probleme eignen sich gut für Constraint-Verarbeitung.
Bayes'sche Netze/Causality Graphs
Prozedurale Methoden: Bei Punkten, bei denen die deklarative Darstellung versagt, wird auf "herkömmliches" Programmieren ausgewichen.
... und andere. Häufig Mischformen.
Minsky 1975. Entstehung im Zusammenhang mit Computer Vision (Bilderkennung).
In Deutschland: Rahmen. In Österreich: Frame.
Ein Frame stellt dar
eine stereotype Situation mit ihren möglichen Eigenschaften (z.B. Hörsaal. In den Bänken sitzen StudentInnen und nicht Blumen.)
allgemeinen Rahmen für Eigenschaften
Prototyp von Situationen, mit Beschreibung gemeinsamer Eigenschaften ("Generischer Frame")
Einzelne Objekte der realen Welt
werden durch Instanzen dieses Prototyps dargestellt ("Individuelle Frames")
enthalten dann die dem jeweils aktuell darzustellenden Sachverhalt entsprechenden individuellen Werte oder Eigenschaften
Aufhebung des Widerspruchs zwischen prozeduraler und deklarativer Repräsentation
Objektstruktur der Frames bildet ein deklaratives Gerüst
an bestimmter Stelle sind Prozedurdefinitionen bzw. -aufrufe, also prozedurale Wissenskomponenten eingehängt (Procedural Attachment)
Jeder Frame hat einen eindeutigen Namen
haus, clyde, elefant_1
System weiß trotzdem nicht, was ein haus ist!
Ein Frame besteht aus einer Menge von Slots (entsprechen Eigenschaften des durch den Frame beschriebenen Sachverhalts)
Slots haben Namen:
größe, instance, farbe
Je nach Frame kann es unterschiedliche Slots geben.
Facet (Facette): $VALUE [20]
instance $VALUE : Alle individuellen Frames
Facet:
enthält eine Liste von Werten
$VALUE: enthält den eigentlichen Slotwert
$DEFAULT: wenn $VALUE nicht gesetzt ist
$REQUIRE: Bedingungen, die der Slotwert erfüllen muß
$IF-ADDED, $IF-REMOVED: automatische Ausführung beim Eintragen oder Löschen eines Werts ("Demons")
$IF-NEEDED: beim Aufruf der FRL-Funktion Fneed automatisch ausgeführt.
$IF*: Möglichkeit, Procedural Attachments einzubinden
Wichtig: Abgesehen von der Vererbung bieten Frames relativ wenige eingebaute Schlußfolgerungsmechanismen.
Generischer Frame A kann Informationen an Frame B vererben.
A muß im ako-Slot (AKO = A Kind Of) von B eingetragen sein.
Wird in B nach einem Slotwert gesucht und keiner gefunden, dann wird A untersucht.
Inverser Slot zu ako: instance. B ist im instance-Slot von A eingetragen.
Im ako-Slot sind mehrere Einträge zulässig
Suche nach vererbten Werten in FRL:
zuerst der erste im ako-Slot eingetragene Frame untersucht, dann der zweite usw.
=> Depth-First-Suche.
Werte können auf drei Arten in der $VALUE-Facet eingetragen sein:
primitive Datenobjekte: Zahlen, Strings, Namen von Frames
Indirection: Pfad zu einem Slot eines anderen Frames.
Evaluation: $VALUE enthält Ausdruck, der beim Zugriff ausgewertet wird und den eigentlichen Wert liefert (eine Art Procedural Attachment)
Liefert den Inhalt von Facet von Slot von Frame. Wird kein Wert gefunden: Verwendung der Vererbung. Wenn immer noch erfolglos: Defaults.
Fügt Wert zum Inhalt des Slots hinzu. $IF-ADDED-demon wird ausgeführt, falls angegeben
Führt den Inhalt der $IF-NEEDED-facet des Slots aus.
Liefert eine Instanz eines Frames, die nur den ako-Slot enthält.
Testet, ob alle in der $REQUIRE-Facet enthaltenen (oder vererbten) Bedingungen in Bezug auf den Slotwert erfüllt sind.
Fügt Slots zu einem Frame hinzu
Verschiedene Möglichkeiten:
Fakten für Slots
speise_1(preis, value, [102]).
Fakten für Facets
frame(speise_1, preis, value, [102]).
Frames als Prolog-Strukturen (aufwendig und langsam)
frame(speise_1, [slot(ako, [value([102]), slot(beauftragt,
[ifadded(...), ifneeded(...)]...)
Einfachste Implementierung: frame(Framename, Slot, Facet,
Value).
frame(peking_ente_1, ako, value, [peking_ente]).
Implementierung von fput:
fput(Frame, Slot, Facet, Value) :-
asserta(current(Frame, Slot, Facet, Value)),
get_and_retract(Frame Slot, Facet, OldValues),
assert(frame(Slot, Facet, [Value | OldValues])),
check_ifadded,
retract(current(Frame, Slot, Facet, Value)).
get_and_retract(Frame, Slot, Facet, Value) :-
% Wertzugriff ohne Vererbung
frame(Frame, Slot, Facet, Value),
retract(frame(Slot, Facet, OldValues)), !.
get_and_retract(Frame, Slot, Facet []).
% Wenn es den alten Wert nicht gab, leere Liste zurückgeben
% Annahme: Ausführung der Procedural Attachments immer erfolgreich
check_ifadded:-
current(Frame, Slot, Facet, Value),
fget(Frame, Slot, ifadded, Demon), !,
Call(Demon).
check_ifadded. % kein Demon => nix tun
%Beispiel-Demon ($IF-ADDED für beauftragt() bei bestellung()):
add_Koch :-
current(F, S, _, [V]),
fput(V, belegt, value, F).
Sehr viel für Sprachverarbeitung verwendet.
Darstellung von Wissen in Form gerichteter Graphen
Knoten: Konzepte, Objekte der realen Welt, Abstraktionen, Eigenschaften, Ereignisse, Zustände
Kanten ("konzeptuelle Relationen"): Beziehungen zwischen den Konzeptknoten
Große Vielfalt
Relationale Graphen: Knoten und dazwischen benannte Relationen.
Semantische Fälle: Relationen zur Beschreibung von Satzstrukturen.
Vorteile:
Leicht lesbar und verständlich, effizient in der Verarbeitung
Nachteil: weniger mächtig als Prädikatenlogik.
Anwendungen: Expertensysteme, Verarbeitung natürlicher Sprache, Machine Learning.
Netzwerke (Propositionen) werden geschachtelt. Eine Proposition ist ein abgeschlossener Sachverhalt ("Kontext").
Versuch, semantische Netze auf eine formale Basis zu stellen
Welt beschrieben über Konzepte ("Typen" im OO-Sinn) und Beziehungen zwischen Konzepten ("Rollen")
Konzepte und Rollen legen "Terminologie" fest
Beispiel für Konzeptdefinition: "Ehefrauen sind weibliche Menschen, die einen Ehemann haben"
Alle Objektinstanzen, die dieser inhaltlichen Definition entsprechen,
gehören zu dem Konzept.
(Unterschied zu Frames! Z.B. "Lieferzeit": in einem Frame-System
weiß ich nicht, welche Objekte eine Lieferzeit haben. Objekte mit
Lieferzeit sind nicht unbedingt Gerichte.)
Monotone Vererbung: Überdecken von ererbten Eigenschaften nicht möglich!
Prädikatenlogik erster Stufe mit Identität und Funktionssymbolen (PIF).
PIF ist unentscheidbar: Es können Prädikate aufgeschrieben werden, die so komplex sind, daß sie nicht bewiesen werden können.
In der Praxis daher reduzierte Teilsysteme, aber manchmal um nicht-PIF-Elemente erweitert.
Regeln von S: R(S)
Fakten von S: F(S)
z.B. Datenbanksprache DATALOG
Nur spezielle Interpretationen. Nur solche Fakten kommen vor, die in dieser Interpretation gelten.
Regel ist erfüllt, wenn bei beliebiger Ersetzung von Variablen durch Konstantensymbole der Kopf der Regel immer erfüllt ist.
In Prolog als Metainterpreter:
forward :-
(A -> B),
call(A),
call(not (C)), !,
assert(B),
forward.
forward.
Gibt alle beweisbaren Fakten aus. Extrem ineffizient. Die Reihenfolge der Regeln ist irrelevant (Unterschied zu Prolog).
Vereinfachter Beschreibungsvorgang durch teilweise Benutzung der Beschreibung existierender verwandter Objekte, Modifikation ihrer Eigenschaften. Nicht veränderte Eigenschaften werden vererbt.
Alle Elefanten sind scheu. Zirkuselefanten sind Elefanten. Zirkuselefanten sind nicht scheu. Clyde ist ein Zirkuselefant. Ist Clyde scheu?
Mit normalen logischen Methoden führt das zu einem Widerspruch.
- ad-hoc definiert (Algorithmus): Frames
- formal: Nichtmonotoner Ansatz
"Nixon Diamond"
Nixon ist Quäker und Republikaner. Quäker sind Pazifisten. Republikaner sind keine Pazifisten ("negative Kante"). Ist Nixon jetzt ein Pazifist oder nicht?
Ansätze:
credulous (leichtgläubig): Ich nehme eine Variante an und schließe daraus weiter.
sceptical: ich nehme nur Dinge an, die eindeutig sind.
Ist Clyde scheu?
skeptische Lösung: Ich weiß nicht.
leichtgläubige Lösung: die meisten Ansätze sind so definiert, daß tatsächlich "Clyde ist nicht scheu" herauskommt:
Ordnung der Kanten (Zirkuselefant ist näher an Clyde als Elefant) gibt der negativen Kante den Vorzug.
Motivation: deklarative Wissensrepräsentation erfordert Suche: z.B. Wegsuche, Suche in Constraint Graphen, Vererbungshierarchien, Hypothesenraum (bei maschinellem Lernen), nach optimalen Lösungen
Blinde "brute force" Suche
durch Wissen gesteuerte Suche
implizit
explizit
Meist durch Regeln, Operatoren oder ähnliches beschrieben.
Kanten stehen nicht in der Wissensrepräsentation drinnen.
Die Regeln beschreiben den Übergang von einem Zustand zum nächsten; die Punkte der Suche sind die Zustände, die angewendeten Lösungswege sind die Kanten.
Existieren direkt in der Wissensbasis.
Es existieren Prädikate für die Kanten
Punkte können u.U. komplexe Objekte sein
Explizite Repräsentation der Kanten
u1(taubstummengasse, karlsplatz). U1(karlsplatz, stephansplatz). U3(stephansplatz, stubentor).
Nachteil bei Wegsuche: Alle Prädikate müßten bekannt sein
Repräsentation der Kanten mit Ressourcen und Kosten
edge(taubstummengasse, karlsplatz, u1, 2, 1). % oder Listenstruktur, oder frame-basierte Struktur
primitive Suche:
connected(P1, P2) :-
edge(P1, P2, _, _).
connected(P1, P2) :-
edge(P1, P3, _, _), connected(P3, P2).
% Nachbarpunkt suchen und schauen, ob mit dem Ziel verbunden
% Problem: Suche im Kreis
Verzweigungsfaktor: Grad (=Anzahl der Kanten aus diesem Punkt) eines Punktes -1
interessant für Komplexitätsbetrachtung bei den Suchstrategien ist der durchschnittliche Verzweigungsfaktor v
die Tiefe eines Suchbaumes t
unterschiedliche Kanten(typen) können unterschiedliche Kosten Ci zugeordnet sein.
Allgemeine Prozedur:
Start- und Zielpunkt ps, pz
Suchgraph: Graph und Suchbraum: Tree
bereits untersuchte Punkte: Closed
als nächstes zu untersuchende Punkte: Open
sortieren von Open: heuristic_sort
Kein Wissen über die Qualität eines eingeschlagenen Weges
brute force oder exhausting search: ausschöpfende Suche
Punkte, die "tiefer" im Graphen liegen (also weiter vom Ausgangspunkt entfernt sind), in die Open-Liste übernehmen
Tiefenbeschränkung t ist notwendig
Aufwand: im ungünstigsten Fall exponentiell
auf der untersten Ebene existieren vt Punkte
ähnelt der Backtracking-Suche
Punkte, die "höher" liegen, werden in der Open-Liste nach vorne sortiert
wenn ein kürzester Weg l (mit den wenigsten Kanten) gefunden wird, Suche beenden
Aufwand im schlimmsten Fall auch exponentiell
Bei großem Verzweigungsfaktor ist die Suche in die Tiefe oft günstiger
Ähnlich wie Suche in die Tiefe
Nur der aktuelle Lösungsweg abgespeichert, weniger Speicherplatz benötigt
Probleme beim nachträglichen Erweitern der Wissensbasis
Speicherbedarf annähernd linear bzgl. der Tiefenschranke
Zeitaufwand wie bei Tiefensuche
in Prolog eingebaut, aber Tiefenschranke fehlt
Backtracking effizient durch Kellerstrukturen (stacks)
Depth first iterative deepening (dfid)
Versuch, die Vorteile von Backtracking- (linearer Speicherbedarf) und Breitensuche (kürzeste Lösung) zu verknüpfen
erster Schritt: Suche mit Backtracking bis zur Tiefe 1
die Suchtiefe wird dann beim nächsten Versuch um 1 erhöht
wiederholen der Backtrackingsuche bis Weg gefunden
der Algorithmus funktioniert, weil die unterste Suchebene mehr Punkte enthält als alle Ebenen über ihr
Best first search
Punkte mit kleinen Kosten stehen vorne in der Liste "Open"
die Güte eines Weges vom Startpunkt ps zu einem Zielpunkt pz über eine Zwischenpunkt wird geschätzt
Kostenfunktion für Kante
optimale Kosten unbekannt
deswegen Schätzfunktionen
Bedingung: 0 < h(p) <= h*(p)
% die Schätzfunktion <= optimale Kosten. Z.B. bei geografischer Suche
die Diagonale
Spezialfall h(p) = 0 und c(pi, pj) = 1 => Suche in die Breite
Länge des Weges
Güte eines Zustands
usw.
Kombination von A* und Backtracking
Backtracking benutzt die geschätzten Kosten als Tiefenschranke
die geschätzten Kosten zwischen ps und pz sind Tiefenschranke
bei guter Heuristik nicht so gut wie dfid
linearer Speicheraufwand im Gegensatz zu A*
theoretisch höherer Zeitaufwand als A*
Bisherige Graphen sind Oder-Graphen
wenn verschiedene Bedingungen gleichzeitig erfüllt sein sollen, dann Und/Oder-Graphen
z.B. Fahrschein für U-Bahn
Hypergraphen
(Graphen von Graphen)
es existieren Kanten zwischen Mengen von Punkten
Lösungen sind nicht mehr Lösungswege, sondern Lösungsgraphen
das Ziel kann eine Menge von Punkten sein
der Algorithmus benutzt einen vielversprechendsten Lösungsgraphen
Suche in Nullsummenspielen
der Gewinn des einen Spielers ist gleich hoch wie der Verlust des anderen Spielers
wenn die Gegner nun abwechselnd eine Aktion ausführen, muß A immer damit rechnen, daß B die für A ungünstigste Alternative wählt
der sog. Spielbaum wird wie ein Und/Oder-Graph repräsentiert
die Suche wird jedoch anders durchgeführt
Aufgabe 3: Lösung mit A* (Prolog-Programm im Skriptum)
mehrere Wege zu finden, da Teilprodukte von unterschiedlichen Restaurants geliefert werden sollen
unterschiedliche Lösungsmöglichkeiten
einfache und u.U. Optimale Lösung.
Was ist Planung?
Problem: große Komplexität (großer Baum)
Gedanklicher Vorgang
BWL: Dispositiver Prozeß
Vorhersage über die Zukunft: Wenn A, dann wird B gelten, sonst C
bewußte Beeinflussung der Umgebung
Einplanung von Aktionen, damit etwas passiert
Vermeidung von Situationen
Erreichen von Situationen
Kausales Modell
was muß getan werden, damit etwas gewünschtes gilt?
was muß gelten, damit eine Aktion ausführbar ist?
Zeitliches Modell
Deskriptive Beschreibung der Problemstellung
Startsituation wird modelliert (z.B. Transportfahrzeug ist am Ort A, Essen ist am Ort B)
gesucht: zeitlich geordnete Aktionen = Plan,
der die Situation in eine andere Situation - die Zielsituation - überführt
die Zielsituation bezieht sich auf die Zukunft
Trennung von Wissensrepräsentation und -verarbeitung
Konfiguration (z.B. Rechner)
Designprozess (z.B. Architektur)
Handlungsplanung (z.B. Roboter)
Spezialprobleme
Zeitliche Planung
Wegoptimierung
Platzoptimierung
Expertenprobleme (z.B. Planung von chemischen Experimenten)
Planung von "Alltagsbanalitäten" im Gegensatz zu Expertenproblemen
Rechtzeitigkeit (Ergebnis muß rechtzeitig geliefert werden)
Zuverlässigkeit
Sicherheit
Parallelität von Planung und Ausführung
manchmal Kompromiß zwischen Zeit und Optimalität
Transport von Essen zum Kunden des virtuellen Restaurants
Aktionen
beladen(Akteur, Essen, Transporteur, Restaurant)entladen(Akteur, Essen, Transporter, Kunde)fahren(Akteur, Fahrzeug, Ort1, Ort2)zubereiten(Restaurant)ausliefern(Essen, Kunde)
Startsituation
Eine Menge von Operatoren und ihrer Effekte auf die Plaungsumgebung
Zielsituation
Die Situationen werden durch logische Aussagen des Prädikatenkalküls beschrieben
beschreiben eine Umformung eines Zustands in einen Folgezustand
das Operatorschema "beladen", um einen Gegenstand in das Fahrzeug zu laden
wird ein Schema angewendet, werden die Parameter durch Konstanten substituiert
Ein Operator enthält vier Listen:
Einschränkungen: Bedingungen an die Instantiierung der Variablen
Vorbedingungen
Hinzufügungen
Aufhebungen
Ziel: z.B. petra hat pizza_margherita
welches Schema erfüllt dieses Ziel?
Das Schema entladen wird gewählt und mit den Konstanten
pizza_margherita und petra instantiiert.
Ein Plan ist eine Folge von Operatoren
zwischen einem Start- und Zielzustand wird ein Weg durch den Zustandsraum gesucht
der Weg ist auch eine Folge von Zuständen, dieren Übergang durch die Operatoren beschrieben wird
"erfülle die Unterziele des Operators, der zum Ziel führt"
die Vorbedingungen sind im einfachsten Fall bereits in der Startsituation gegeben
Überprüfung der Einschränkungen
Wenn nur eine Instantiierung möglich, dann wird diese durchgeführt
"A ist mensch" hat aber mehrere
Instantiierungsmöglichkeiten
Zwei Listen zur Verwaltung der Ziele
noch zu beweisende Ziele und bereits erfüllte Ziele
drei Möglichkeiten, ein Ziel zu beweisen
die Aussage kann in der Startsituation gegeben sein
ein bereits eingeplanter Operator erfüllt das Ziel
ein neuer Operator, der das Ziel in seiner Aufhebungslieste beitzt, wird hinter den letzten Operator des aktuellen Plans eingefügt
ein bewiesenes Ziel wird aus der Liste eliminiert
kann Ziel nicht bewiesen werden, wird versucht, ein anderes Ziel zuerst zu beweisen
Vektor mit drei Listen:
Aussagen, die im momentanen Planungszustand gelten
der bisherige Plan
die offenen Einschränkungen
rekursive Planung
Tiefenschranke notwendig
1. Welches Teilziel einer Liste wird zuerst gelöst
bisher Reihenfolge der Liste, dann Permutation
2. unterschiedliche anwendbare Schemata
Heuristik: jeweils spezifischeren Operator auswählen
3. Unifikation der Literale (Zielaussagen)
möglichst zuerst die instantiierten, die weniger Alternativen bieten
die Stellen der Nichtdeterminiertheit sind potentielle Punkte für Backtracking
Entscheidung durch Heuristiken
entspricht der Strategie der geringsten Festlegung (least-commitment strategy)
Meist wird rückwärtsverkettet geplant
von einer Zielsituation zu einer Startsituation (typisch für Prolog)
Suchalgorithmen (z.B. A*) suchen meist vorwärtsverkettet
typisch für Produktionsregelsysteme
im Prinzip können Suchstrategien auch rückwärts-verkettet benutzt werden
die Schemata können auch vorwärtsverkettet benutzt werden
Wissensrepräsentation und keine Suchstrategie
Suchrichtung hängt von 3 Faktoren ab:
1. dem mittleren Verzweigungsfaktor
2. Start der Situation, die weniger komplex ist
3. Erklärungsfähigkeit
Weiteres Ziel: "petra hat tiramisu"
Alter Plan (siehe Skriptum)
drei neue Aktionen
regressive Suche nach Platz für Operatoren im alten Plan
kritischere Vorbedingungen beitzen die höheren Werte
ein Problem dieser Bewertung ist, daß diese Bewertung dynamisch sein sollte, da die Schwierigkeit von Zielen problemabhängig ist
auf einer Abstraktionsebene werden alle Ziele geplant
zuerst werden die Ziele mit dem Wert untersucht
Fragenliste für die Klausur noch nicht fertig, sollte bis 21. 5. im Netz erscheinen.
3 Sichtweisen:
Schließen - Ableiten von neuen Aussagen aus einer Menge von Axiomen
Suche - durch einen Raum von möglichen Zuständen
Constraint Satisfaction - das allmähliche Hinzufügen von Einschränkungen, die eine Menge von Objekten auf jene Teilmenge einschränken, die alle Constraints erfüllt
Ein Constraintproblem ist zusammengesetzt aus:
einer Menge von Variablen Z (diskret)
D: Domain (Wertebereich) der Variable
einer Menge von n-stelligen Constraints C, die festlegen, welche Variablenwerte bei verschiedenen Variablen "zusammenpassen"
z.B. Königinnen-Problem
|
j |
Typ |
Werte Z |
Gültige Tupeln |
Rj |
|
1 |
A |
{z1, z2} |
{(13) (14) (24) (31) (41) (42)} |
"6/16" |
Rj: "Constraint looseness"
Konfiguration: Zusammensetzen komplexer Systeme aus einer Menge von Komponenten
Scheduling: Zeitplanung, Festlegung von Fahrplänen, Hörsaal- und Schulklassenbelegungen
Analyse: Identifikation von chemischen Verbindungen und Proteinstrukturen
Baumsuche (Tree Search): Ausprobieren der Variablen und Werte der Reihe nach
Konsistenzalgorithmen: Ausprobieren der Constraints der Reihe nach
Problem: findet nicht immer die Lösung
in Kombination mit Baumsuche
Reparaturbasierte Algorithmen: Nimm blind eine Lösung, bastele herum, bis sie paßt
"Basteln": Nimm eine Variable, die an einer Constraintverletzung beteiligt ist (z.B. die, die am meisten Constraints verletzt) und nimm für sie einen neuen Wert usw.
Garantiert nicht, daß Lösung gefunden wird
kann sehr effizient sein
erzeugt Baum aller möglichen Wertezuweisungen an die n Variablen z.
Änderung der Suchreihenfolge kann helfen, die Menge der Vergleichoperationen zu verringern.
Heuristik: z.B. nach constraint looseness oder Anzahl der Constraints sortieren
Backjumping: Vermeidung eines ganzen Suchbaums ("dependency directed backtracking"): Schauen, wovon die Fehlschläge abhängen
Anhand der Constraints wird angeschaut, welche Werte in der Lösung "sowieso" nicht vorkommen können.
Kantenkonsistenz: Variablen, die an den Enden einer "Kante" liegen, miteinander konstistent machen
Pfadkonsistenz: Forderungen suchen, die miteinander in Widerspruch stehen (Pfade durch den Graphen suchen)
Ein Constraint-Netz ist kantenkonsistent, wenn alle Kanten kantenkonsistent sind.
Worst case: 4-Königinnen: 90 Überprüfungen, aber keine eliminiert!
Problem: reicht im allgemeinen nicht aus, um ein CSP zu lösen.
Möglichkeiten:
Suche nach höheren Graden der Konsistenz als nur Kantenkonsistenz, z.B. Pfadkonsistenz oder j-Konsistenz
Kombinieren der Kantenkonsistenz oder anderer Konsistenztypen mit der Baumsuche
Forward Checking: wenn ein Variablenwert ausgewählt wurde, werden von den folgenden Variablen gleich alle unpassenden Werte ausgefiltert.
Grundidee: Nicht allmähliches Einschränken, sondern Verbessern einer unvollständigen Lösung
1. Suche eine zufällige Belegung
2. Suche eine Variable z heraus, die an Konflikten beteiligt ist
3. Wähle einen neuen Wert für z
4. Wenn noch keine Lösung, dann weiter bei 2.
Heuristik: Nimm Variable, die an den meisten Konflikten beteiligt ist
Nicht vollständig, keine Garantie, daß eine Lösung gefunden wird - oft aber eine Lösung, wenn die Baumsuche aus Zeitgründen nicht mehr relevant
Die Vorlesung am 5. 6. entfällt.
Konfiguration: Zusammensetzen komplexer Systeme aus einer Menge von Komponenten
Motivation: "individuelle Massenfertigung": einzelne Komponenten, automatische Zusammensetzung zu komplexen Systemen für den Einzelkunden.
Komplexe Produkte erfordern Software-Unterstützung => Einsatz wissensbasierter Systeme
Strukturbasierte Methoden: Zerlegungsbäume können auch rein hierarchisch sein
entwickelt aus Stücklistenverarbeitung
einfachster Ansatz, aber beschränkt
Vorgaben, z.B.
bestimmte Teile müssen enthalten sein (key components)
globale Anforderungen: minimaler Platz, minimale Kosten
Schwelleneffekt: kleine Unterschiede in der Spezifikation können große Effekte auslösen
Horizonteffekt: spätes Feststellen von getroffenen Fehlentscheidungen
Problem für heuristische Algorithmen (z.B. A*): in der Regel keine korrekte Abschrankung für Heuristiken möglich, es kann immer am Ende ein bisher nicht überprüfter Constraint auftauchen.
Propose-and-revise: Lösung zusammenstellen, Schwachstellen finden, mit heuristischem Reparaturwissen verbessern
Partial Commitment: z.B. CD-Player A und B zur Wahl, beide erfordern Verstärker C. Reihenfolge: C festlegen, A/B unentschieden lassen.
Projektziel: Entwicklung eines problemunabhängigen Konfigurationstools, schnelle Beschreibung und leichte Wartung
Korrekte Lösung, nicht der Weg dazu, wird beschrieben.
Constraints sind ausdrucksstärker als Regeln, können also eine Strategie besser unterstützen und auch ALLE Lösungen auffinden, während regelbasierte Systeme immer nur eine deterministische Lösung liefern.
Kognitionswissenschaftlich: Prinzipien menschlichen Lernens sollen mit Hilfe von operationalen Modellen untersucht werden
praxis-anwendungsorientiert: Arbeit am Rechner durch Lernfähigkeit erleichtern
theoretisch-technisch: theoretische Untersuchung, was allgemeine Lernverfahren ermöglichen
Verbesserung von Programmen: Programm kann effizienter sein, oder Probleme lösen, die es vorher nicht lösen konnte.
Wissensakquisition
Erlernen von Konzepten aus Beispielen
Erlernen von Regeln (Entscheidungsbäumen)
Cluster
Unüberwachtes Lernen (unsupervized learning)
überwachtes Lernen anhand von Beispielen (supervized learning)
verstärkendes Lernen durch positive oder negative Bewertung (reinforcement learning)
Lernen durch Analogien (analogy learning)
Lernsystem bekommt Beispiele und leitet daraus Wissen ab => Inferenzkomponente, Problemlöser
Das Lernsystem beobachtet seine Umwelt und baut auch diese Erfahrungen in seine Wissensbasis ein.
Menschen sind sterblich => Anna ist Mensch => Anna ist sterblich
Alle dem System bekannten Menschen sind sterblich => Annahme: alle Menschen sterblich (statistische Bewertung)
Hinznahme einer Theorie möglich.
X: Menge von Objekten
C: ein Konzept aus X
C kann als Funktion interpretiert werden, die 1 ("stimmt") oder 0 liefert
[x, c(x)] ist ein Lernbeispiel.
Ziel: Hypothese (bzw. Schätzfunktion h(X)), die
alle positiven Beispiele korrekt zum Zielkonzept gehörend klassifiziert und
alle negativen Beispiele ausschließt
Suche durch einen Raum von Hypothesen
Strukturierung des Raums durch Generalisierungs- und Spezialisierungsrelation
Bottom-up: minimale Generalisierung (=Spezialisierung) wird gesucht, neue Generalisierung muß negative Beispiele ausschließen, ansonsten Backtracking.
Top-Down
Versionsraum (bi-direktionale Suche)
untere Schranke als Menge von möglichen Hypothesen, die alle Beispiele generalisieren
obere Schranke als Menge von möglichen Hypothesen, die Negativlösungen ausschließen
Konzepte (Beispiele) werden durch Attribut-Wert-Paare beschrieben
Menge von positiven und negativen Beispielen, z.B.
Kredite
Diagnose von Krankheiten
Schach: König+Turm gegen König+Springer
Generierung eines Entscheidungsbaums
Startseite
Auswahl 1
Seite 1
Auswahl 11
Auswahl 2
Seite 2
Auswahl 11
usw.
Welches Attribut soll zuerst abgefragt werden? Das, das am schnellsten zum Wunschgericht führt.
Wenn der Kunde nur österreichisch ißt, zuerst diese Auswahl anzeigen.
ID3 versucht das Attribut abzufragen, das den größten Informationsgehalt besitzt
n Attribute
pm die Wahrscheinlichkeit, daß ein Objekt mit m-ten Attribut zum Zielbegriff gehört
Entropie eines Attributes
16 positive Beispiele, 5 negative
Entropie der Gesamtmenge bestimmen
Kleinster Entropiewert wird als erstes abgefragt
Probleme samt Lösung werden als "Fallbasis" gespeichert. Bei einem neuen Problem wird nach ähnlichen Problemen (=Problemen mit ähnlichen Attributen) gesucht. Evt. Simulation des neuen Falls. Reparatur (automatisch oder mit menschlicher Einwirkung). Lernen der Fälle => wieder in der Fallbasis gespeichert.
Ständig zunehmende Menge an weltweit gespeicherten Daten, ca. alle 20 Monate verdoppelt sich die Menge
Ist es möglich, daraus neues Wissen herauszulesen?
Grundsätzlich: Der Prozeß der Suche nach interessanten und nützlichen Mustern ("Wissen") in großen Datenbanken
Fachliteratur bezeichnet Data Mining nur den Analyseteil; der Gesamtprozeß wird Knowledge Discovery genannt.
Vorbereitung: Verständnis für Problembereich, Datenbestand, Ziele des Anwenders
praktisch keine sinnvollen Ergebnisse ohne feste Einbindung der Problemexperten
Datensammlung und Datenauswahl
Data Cleaning: Entfernung offensichtlich falscher Daten
Auswahl der Art der Aufgabe: Klassifikation, Regression, Gruppierung
Vorverarbeitung:
Subsampling (Auswahl der Datensätze)
Feature Selection (welche Attribute sind überhaupt relevant - manuelle oder automatische Feststellung)
Auswahl der Algorithmen
Transformation (z.B. numerische Kodierung von symbolischen Werten, Normalisierung, Diskretisierung)
Mining: Eigentliche Durchführung
Auswertung: Interpretation, Präsentation, Anwendung
KDD ist der Prozeß der Suche nach gültigen, neuartigen, möglicherweise nützlichen, verständlichen, aber nichttrivialen Mustern.
Muster: Beschreibung einer Eigenschaft einer Datenmenge, die kürzer ist als die Aufzählung der Daten, z.B.: "wenn Einkommen < t $, dann wird die Person den Kredit nicht bezahlen".
Regeln, die Zusammenhänge zwischen Objektattributen herstellen
Verknüpfungen/Abhängigkeiten zwischen Objekten (Verbindungen)
typische Abfolgen (zeitliche/räumliche Sequenzen)
Gruppierungen (Clusters)
Abweichungen (auffällig unterschiedliche Attribute bei Einzelobjekten in einer Gruppe)
Einordnung von Objekten in bestimmte Klassen, z.B. Identifikation von Objekten in Bilddaten etc.
Suche nach begrenzter Menge von Kategorien zur Einteilung der Daten
überlappend/exklusiv
ausfüllend/partiell
hierarchisch
z.B. Gruppierung von KundInnen
(Verwandt: Abschätzung der Dichtefunktionen für Wahrscheinlichkeitsverteilungen)
Abhängigkeiten (Assoziationen): "In 34 % der Transaktionen, bei denen Milch, Brot und Butter gekauft wurden, wurde auch Kaffee gekauft."
Zeitliche Abfolgen: Videorecorder => innerhalb von 5 Tagen auch Kassetten gekauft
Muggleton, 1991
Ziel: Einschränkungen der Standard-Entscheidungsbaum-Algorithmen zu vermeiden
"Empirisches ILP"
alle Beispiele im Voraus
Lernen im Batchbetrieb, ohne interaktive Beeinflussung
einfacher zu erklären, momentan wichtiger für KDD
Gegeben: Hintergrundwissen H, positive und negative Beispiele B (B+, B-)
Gesucht: Definition D des Prädikats, so daß
H und D => b für b aus B+ (vollständig)
Tägliche Auswertung anfallender Daten, Verarbeitung und Übernahme ins Data Warehouse
Typischerweise Gruppierung und Gliederung
BenutzerIn kann komplexe Auswertungstransaktionen effektiv ausführen
Data Mining: möglichst autoamtische Steuerung des Suchprozesses, welche Abfragen denn überhaupt relevant sind
Auch bekannt als OLAP (On Line Analytical Processing) im Gegensatz zu OLTP (On Line Transactional Processing)
Suche nach Fehlerursachen in technischen Systemen
Versuch der medizinischen Diagnose beim Menschen
Grundsätzliche Annahme: Information über Symptome wird benutzt, um ausgehend von Bereichswissen auf mögliche Ursachen zu schließen
Grundsätzlicher Ansatz: Darstellung kausaler Zusammenhänge in Systemen
© Balázs Bárány.
(Homepage)
Zuletzt geändert:
2003-12-23.