Od czasu do czasu zawracam Wam głowę moimi projektami ze Sztucznej Inteligencji. Ostatnim projektem był Svarog i jego demko – Dorban, dostępne z www.perkun.org . Ostatnio napisałem po polsku książkę popularno naukową pt. Algorytm Perkuna, bez wzorów i bez kodu – jest dostępna tu. Chciałem luźno pogawędzić (jeżeli ktoś zechce) o moim kolejnym projekcie, który z założenia będzie wspierał dużą liczbę zmiennych ukrytych. Będę musiał zmodyfikować nieco algorytm. Ale nie o tym chciałem. Wymyśliłem ostatnio nieco lepszy niż predykaty (znane z Prologu) sposób reprezentacji wiedzy, przynajmniej tak mi się wydaje. Można oczywiście zapisać te same dane i przez predykaty, ale Prolog nie wspiera pewnej szczególnej koncepcji, którą najlepiej wyjaśnić na przykładzie.
Założmy, że deklarujemy typy wyliczeniowe w następującej składni:
type osoba={Gotrek, Gerrudir, Gwaigilion};
type miasto={Krakow,Warszawa,Poznan,Wroclaw,Gdansk};
type klucz={czerwony_klucz,zielony_klucz,niebieski_klucz};
type bron={brak,miecz,topor};
type budynek={zamek,dom,chatka};
type boolean={falsz,prawda};
Składnię tą rozszerzamy w ten sposób, że wartości wyliczone w poszczególnych typach mogą mieć postać: <item1><item2>...<item_n>, przy czym każdy kolejny item to literał alfanumeryczny albo wyrażenie postaci
(X:<nazwa typu>)
oznaczające jakby placeholder pewnego typu.
type
akcja={nic_nie_rob,
idz_do_(X:miasto),
powiedz_(Y:osoba)_(X:informacja),
popros_(X:osoba)_zeby_(Y:akcja),
spytaj_(X:osoba)_czy_(Y:informacja),
zaatakuj_(X:osoba),
ukradnij_(X:bron)_(Y:osoba),
ukradnij_(K:klucz)_(Y:osoba),
daj_(X:osoba)_(Y:bron),
daj_(X:osoba)_(K:klucz),
sprobuj_otworzyc_(X:budynek)_(K:klucz)},
informacja={(X:osoba)_jest_w_(Y:miasto),
(X:osoba)_wykonuje_akcje_(Y:akcja),
(X:osoba)_mysli_ze_(Y:informacja),
(X:osoba)_powiedzial_(Y:osoba)_(Z:informacja),
(X:osoba)_zaatakowal_(Y:osoba),
(X:osoba)_ma_bron_(Y:bron),
(X:osoba)_ma_klucz_(K:klucz),
(X:osoba)_ukradl_(Y:osoba)_(K:klucz),
(X:osoba)_ukradl_(Y:osoba)_(Z:bron),
(X:osoba)_dal_(Y:osoba)_(K:klucz),
(X:osoba)_dal_(Y:osoba)_(Z:bron),
(X:osoba)_sprobowal_otworzyc_(Y:budynek)_kluczem_(K:klucz),
(X:klucz)_moze_otworzyc_(Y:budynek),
(X:budynek)_jest_w_(Y:miasto)};
Ciekawe jest to, że w niektórych wartościach typu “informacja” używamy typu “informacja”, więc jest to niejako typ rekurencyjny. Więcej, są nawet informacje zależne od typu akcja i są akcje zależne z kolei od typu informacja. Poza tym wolno używać niezdefiniowanych jeszcze typów, pod warunkiem, że gdzieś jednak będą zdefiniowane. Możliwe są “cykle”, nawet bardzo skomplikowane.
Istnieje specjalne polecenie – expand(<integer>), które powoduje rozwinięcie tej rekurencji do zadanej głębokości. Jeżeli damy expand(1), to jedyną akcją jest “nic_nie_rób”, a typ informacja jest pusty. Ale już expand(2) daje mnóstwo wartości.
Jak się domyślacie mam już interpreter i nie liczyłem tego na piechotę.
W oparciu o identyczną składnię definiuję zmienne, np. zmienna wyjściowa to:
output variable wykonaj:akcja;
Oczywiście nie poprzestaję na rozwinięciu tych typów do głębokości 2, np. już dla 4 są takie akcje:
spytaj_Gotrek_czy_Gwaigilion_powiedzial_Gerrudir_chatka_jest_w_Wroclaw
To znaczy po polsku “spytaj Gotreka czy Gwaigilion powiedział Gerrudirowi, że chatka jest we Wrocławiu”.
Oczywiście w Prologu dałoby się napisać odpowiedni ekwiwalent, ale mój język wspiera tę rekurencję typów i wydaje mi się przez to bardzo intrygujący. Jak powiedziałem dzięki tym placeholderom będzie można prosto wygenerować całe “rodziny” zmiennych, np:
input variable gdzie_jestem:miasto,
(X:osoba)_mowi_mi_ze_(Y:informacja):boolean;
Ta pierwsza zmienna to po prostu:
gdzie_jestem:{Krakow,Warszawa,Poznan,Wroclaw,Gdansk};
Ale ta druga to cała rodzina zmiennych wejściowych, do których należy na przykład zmienna:
Gerrudir_mowi_mi_ze_Gotrek_powiedzial_Gwaigilion_Gerrudir_powiedzial_Gwaigilion_chatka_jest_w_Gdansk:{falsz,prawda};
Reprezentuję wiedzę o moich zmiennych w postaci reguł, ale na razie projekt nie jest skończony, więc więcej Wam nie powiem. Mam nadzieję uzyskać jakąś formę mojego algorytmu planowania, który będzie zakładał tym razem, że zmienne są niezależne, więc to, w co agent wierzy będzie musiało być nieco inaczej reprezentowane. I będzie mogło być bardzo dużo zmiennych ukrytych. Zależy mi zwłaszcza na zmiennych ukrytych. Wyobraźcie sobie na przykład:
hidden variable (X:osoba)_mysli_ze_(Y:informacja):boolean;
Dla głębokości rekurencji 3 daje to 8460 zmiennych ukrytych (tylko jedna rodzina). To jest liczba niemożliwa do udźwignięcia dla Svaroga, bo miałby 2 ^ 8460 stanów. A w moim nowym projekcie będzie 2*8460 takich jakby “projekcji”, czyli rozsądna ilość. Mam nadzieję zrobić coś podobnego jak prekalkulacja wiedzy w Svarogu, czyli zadajemy model świata (za pomocą bardzo silnych reguł opartych o te placeholdery) i dajemy komputerowi czas. Po kilku, kilkunastu dniach oblicza sobie reguły dla każdej ewentualności (a właściwie tylko dla tych “projekcji”). Potem będzie działał szybko, tak samo jak Svarog. Postaram się zrównoleglić te obliczenia (tak jak w Svarogu).
Robocza nazwa projektu to “Borsuk”. Napiszę od razu demko, będzie w tym samym projekcie.