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.
<JobDescription>
. Format danych jest następujący:
<Variable>
Zmienna</Variable>
definiowanie używanych zmiennych
<Constraint var="
Zmienna" onp="
Zmienne i wzór"></Constraint>
określenie wzoru w ONP obliczającego szukaną zmienną na podstawie podanych danych<Key var="
Zmienna">
Ciąg słów
</Key>
określenie słów kluczowych wyszukiwanych przez program
<Units var="
Zmienna">
Opisy jednostek
</Units>
gdzie opisy jednostek to:
<Unit name="
Tekst jednostki" mult="
Mnożnik"></Unit>
określa tekst reprezentujący daną jednostkę oraz mnożnik przeliczający ją na
jednostkę podstawową (z mnożnikiem 1)
<DefaultUnit var="
Zmienna" unit="
Tekst jednostki"></DefaultUnit>
określa tekst jednostki podstawowej, dla danej wielkości fizycznej
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.
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
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.