Waldemar Pawlaszek
Raport z projektu ze sztucznej inteligencji
25.06.2004 r.


  1. Problem
  2. Zastosowana metoda
  3. Format opisu zadania
  4. Implementacja programowa
  5. Przykłady testowe i działanie programu
  6. Wyniki i wnioski
  7. Źródła


1. Problem

Zadanie dotyczy napisania programu czytającego i rozwiązującego proste zadania z fizyki. Z założenie ich prostota ma polegać na ścisłym trzymaniu sie danego działu, aby analiza była w ogóle możliwa. Dla każdego działu, z którego zadanie chcemy rozwiązać, definiowany jest jego opis na podstawie ktorego program analizuje treść zadania, ekstrahuje dane liczbowe oraz oblicza wynik podstawiając do wzoru.

2. Zastosowana metoda

Cała "inteligencja" w projekcie opiera się na zauważeniu, że w typowych zdaniach języka polskiego okoliczniki zwykle są po dopełnieniach (ew. podmiotach), a więc piszemy Niebo jest niebieskie, zamiast Niebieskie jest niebo . W kontekście zadań z fizyki typowa formuła to (...) z prędkością 100 km/godz.(...), a więc okolicznik 100 km/godz. jest po dopełnieniu prędkością (aczkolwiek nie zawsze bezpośrednio).

Program działa na zasadzie wyszukiwania słów spełniających rolę wymienionych częśc mowy. W pliku opisu problemu wymienione są wszystkie słowa, na które musi zwracać uwagę, a więc słowa oznaczające interesujące nas wielkości (np.: prędkośc, długości, przyspieszeniu), dane liczbowe, oraz słowa określające jednostki (np.: m/sec, cm/sec^2, godz. itp). Zasada parsowania jest prosta: filtrujemy wszystkie słowa różne od powyższych, jeśli po słowie oznaczającym wielkość fizyczną znajdziemy liczbę, a następnie jednostkę, to oznacza to, że dana wielkość jest dana, jeżeli zaś po wielkości fizycznej odnajdziemy inną wielkość lub koniec pliku, to znaczy, że jest to szukana.

W poniższym przykładzie wielkości fizyczne oznacze na czerwono, wartości liczbowe na zielono, a jednostki na niebiesko.

Pociąg pospieszny poruszający się z prędkością v0 = 18 m/sec zaczyna hamować i zatrzymuje się w ciągu czasu t = 15 sec. Obliczyć wartość przyspieszenia a i drogę s przebytą przez pociąg do momentu zatrzymania się, zakładając, że jego ruch podczas hamowania jest jednostajnie opóźniony.

Po odfiltrowaniu niepotrzebnych elementów pozostaje nam ciąg:

prędkością 18 m/sec czasu 15 sec przyspieszenia drogę

Po przefiltrowaniu tekstu liczby i jednostki występują bezpośrednio po prędkością i czasu, a więc to są nasze dane. Dalej widzimy, że przyspieszenia oraz drogę to szukane, bo nie występują po nich żadne liczby.

3. Format opisu zadania

Aby program mogł rozwiązać zdanie potrzebny jest zadany zewnętrznie opis typu zadania. Dla łatwości wczytywania zdecydowałem się na przechowywania danych w plikach XML. Wszystkie dane są wewnątrz tagu <JobDescription> . Format danych jest następujący: Przykład pliku opisującego zadanie znajduje się w punkcie Przykłady testowe i działanie programu

4. Implementacja programowa

Program napisałem w języku C# na platformę .NET, ze względu na łatwość używania tablic asocjacyjnych (potrzebnych do indeksowania nazwami zmiennych) oraz wbudowaną obsługę formatu XML. Program ma dobry projekt obiektowy. Wszystkimi danymi zarządza obiekt JobListManager przechowujący listy problemów do rozwiązania (klasa JobBundle). Problem składa się z opisu zadania reprezentowanego przez klasę JobDescription oraz szeregu konkretnych zadań przechowywanych w klasie Job. Do rozwiązania zadania na podstawie jego opisu i treści służy klasa JobProcessor. Status każdego słowa trzymany jest w obiektach klasy WordStatus, a do samych obliczeń służy klasa Calculator wykonująca obliczenia w odwrotnej notacji polskiej.

Program jest konsolowy i wywołuje się go z jednym argumentem będącym nazwą pliku z listą problemów do rozwiązania. Intersfejs użytkownika jest bardzo prymitywny i ogranicza się do wypisania wyników rozwiązania zadań lub komunikatu o błędzie.

5. Przykłady testowe i działanie programu

Przykładowa testowa lista problemów może wyglądać tak:
desc1.txt zad1.1.txt zad1.2.txt zad1.3.txt
desc2.txt zad2.1.txt zad2.2.txt zad2.3.txt

Gdzie desc1.txt to opis zadań z ruchu jednostajnego, a desc2.txt opisuje ruch jednostajnie przyspieszony. Reszta plików, to treści zadań. Opis zadań z ruchu jednostajnego wygląda następująco:

<?xml version="1.0" encoding="windows-1250"?>
<JobDescription>
	<Version>1.0</Version>
	<Description>Ruch jednostajny</Description>
	<Variable>V</Variable>
	<Variable>S</Variable>
	<Variable>T</Variable>
	<Constraint var="V" onp="ST:ST/"></Constraint>
	<Constraint var="S" onp="VT:VT*"></Constraint>
	<Constraint var="T" onp="SV:SV/"></Constraint>
	<Key var="V">
		prędkość prędkości prędkością
	</Key>
	<Key var="T">
		czas czasu czasie czasem
		ciągu
	</Key>
	<Key var="S">
		droga drogi drogę drodze
		odcinek odcinka
		odległość odległości
		dystans dystansu
	</Key>
	<Units var="V">
		<Unit name="m/s" mult="1"></Unit>
		<Unit name="m/sec" mult="1"></Unit>
		<Unit name="m/h" mult="0,0002777778"></Unit>
		<Unit name="m/godz" mult="0,0002777778"></Unit>
		<Unit name="km/s" mult="0,001"></Unit>
		<Unit name="km/sec" mult="0,001"></Unit>
		<Unit name="km/h" mult="0,2777778"></Unit>
		<Unit name="km/godz" mult="0,2777778"></Unit>
	</Units>
	<Units var="S">
		<Unit name="m" mult="1"></Unit>
		<Unit name="km" mult="1000"></Unit>
	</Units>
	<Units var="T">
		<Unit name="s" mult="1"></Unit>
		<Unit name="sec" mult="1"></Unit>
		<Unit name="h" mult="3600"></Unit>
		<Unit name="godz" mult="3600"></Unit>
	</Units>
	<DefaultUnit var="V" unit="m/s"></DefaultUnit>
	<DefaultUnit var="S" unit="m"></DefaultUnit>
	<DefaultUnit var="T" unit="s"></DefaultUnit>
</JobDescription>

Treści zadań to kolejno:

Ile czasu t potrzeba do przebycia drogi a = 100 m ruchem jednostajnym z prędkością v = 100 m/sec?

Z jaką prędkością biegnie sprinter, który odcinek 100 m pokonuje w czasie 10 s?

Samochód w ciągu 6 sec. jechał z prędkością 60 km/h. Obliczyć przejechany dystans.

Jaką drogę pokona tramwaj posiadający jednostajne przyspieszenie a = 1 m/sec^2, w czasie 12 sec?

Pociąg opuszcza przystanek ruchem jednostajnie przyspieszonym z przyspieszeniem a = 30 cm/sec^2. W jakiej odległości od przystanku uzyska on prędkość v = 15 m/sec?

Tramwaj wyrusza z przystanku ruchem jednostajnie przyspieszonym i po przebyciu drogi s = 28,5 m uzyskuje prędkość v = 18 km/godz. Obliczyc przyspieszenie a oraz czas t, w którym tramwaj przebył drogę s.

Wynik działania programu to:

T = 1 s

V = 10 m/s

S = 100 m

S = 72 m

S = 375 m

A = 0,439 m/sec^2
T = 11,4 sec

6. Wyniki i wnioski

Zaimplementowany schemat jest bardzo restrykcyjny jesli chodzi o formułę opisu zadania, ale okazuje się, że da się nim rozwiązać większość zadań, które można opisać właśnie jako schematyczne, a więc takie, w ktorych odpowiedź uzyskujemy po podstawieniu danych do wzory. Jeśli o takie chodzi program napotykał tylko na problemy natury raczej technicznej. Np. w zadaniu Pociąg wyrusza ze stacji i przebywa drogę 750 m (...). W jakim czasie przebywa pociąg początkowy odcinek drogi? słowa oznaczające długość (na czerwono) występują trzykrotnie, jednak za pierwszym razem definiują szukaną odległość na 750 metrów, a za drugim są składową pytania o drogę i wcale nie oznaczają, ze droga jest szukana. Algorytm tego nie zauważy. Akurat w tym przypadku rozwiązanie jest proste: wystarczy ignorować oznaczenia wielkości jako szukanej gdy jest ona już dana oraz przemianować ją z szukanej na daną w przeciwnym razie. Podobny problem ma miejsce, gdy słowo interpretowane jako klucz pojawia się w innym znaczeniu. Np. gdy oznaczymy jednostkę sekundy jako s, a będziemy przetwarzać zdanie zawierające zwrot typu droga s = 100 m, to słowo s które powinno zostać pominięte, zostanie zinterpretowane jako jednostka sekundy i zostanie zgłoszony błąd wystąpienia jednostki w niewłaściwym miejscu. W tym przypadku jedynym rozwiązaniem wydaje się być przebudowanie zdania. Innym rodzajem problemów może być napotkanie zdania zbudowanego w innym szyku niż akceptowalny. Takich zadań oczywiście nie da się rozwiązać, gdyż mamy to do czynienia z załamaniem się podstawowego założenia pozwalającego na "rozumienie" zadania. Musimy zadowolić się spostrzeżeniem, że takie sformułowania są bardzo żadkie i brzmią natyle sztucznie, aby były unikane przez autorów zadań. Dodatkowo można nadmienić, że w obecnej formie program radzi sobie tylko z pojedynczymi danymi z takiej samej wielkości. Czyli np. nie potrafiłby rozwiązać zadania sumującego dwie prędkości, gdyż na raz jako daną może pamiętać tylko jedną prędkość. Można to jednak łatwo zaimplementować.

Pozostaje jeszcze pytanie, czy tym schematem można rozwiązywać trudniejsze zadania? Okazuje się, że w przeważającej liczbie przypadków odpowiedź musi być przecząca. Problem tkwi w ograniczonej ilości informacji jakie można wyekstrahować z treści zadania. Zaprezentowana przeze mnie metoda nie robi nic więcej poza generowaniem zbiorów wielkości które uważamy jako szukane oraz dane. XMLowy opis zadania dla każdej zmiennej, ktora może być szukaną określa listę zmiennych, które muszą być określone, aby problem można było rozwiązać. Gdy zatem liczba danych jest odpowiednia, wówczas podstawianę są one wzoru obliczającego szukaną wartość i to wszystko. Samo zadanie może być bardzo proste, ale jeśli zawiera w sobie istotne dane nieliczbowe, to jesteśmy z góry na przegranej pozycji. Weźmy na przykład zadanie: Pociąg pędzący z prędkością v1 = 80 km/godz przebija kula wystrzelona prostopadle do toru z prędkością v2 = 200 m/sec. Jaka jest wielkość oraz kierunek prędkości v kuli względem układu odniesienia związanego z pociągiem? Jest to zadanie zawierające elementy wektorów, których wartości typu prostopadle są nieliczbowe i program nie potrafi sobie z nimi radzić. Jedyne co program może wywnioskować to to, że są dane dwie prędkości oraz jedna szukana. Już te dwie prędkości mogą nastręczyć problemu, gdyż program nie potrafi skojarzyć prędkości 80 km/godz z pociągiem, a 200 m/sec z kulą, gdyż nie został zaprogramowany na analizowanie podmiotów i tam gdzie jest to istotne nie potrafimy nic zrobić. Inne problemy mogą być tak specyficzne, że wymagałyby odrębnego opisu dla konkretnych zadań. Bywają one czesto na tyle trudne, że zwykłe przekształcenie wzoru nie wystarcza do rozwiązania ich i trzeba wykazać się do tego inteligencją. W tym miejscu stoimy przed problemem niewystarczających możliwości oferowanych przez system opisu zadań, a to już jest kwestia zdecydowanie nie do przeskoczenia.

Reasumując program doskonale radzi sobie z zadaniami, gdzie wszystkie dane są liczbowe, a rozwiązanie otrzymuje się po podstawieniu ich do wzoru. Wszystkie inne sytuacje gdzie dane lub szukane liczbowe nie determinują rozwiązania, lub problem jest trudniejszy, nie mogą zostać rozwiązane, gdyż dostępnym systemem nie można opisać bardziej złożonych modeli niż trywialne podstawianie do wzoru.

7. Źródła

Do ostatecznej wersji programu nie udało mi się znaleźć żądnej literatury, jednakże jako źródło danych testowych niezbędny był podręcznik: J. Kalisz, M. Massalska, J. M. Massalski "Zbiór zadań z fizyki" PWN Warszawa 1961.