Ilmutamata võrrandite lahendamine

Paljud võrrandid esitavad neis esinevate suuruste vahelise sõltuvuse, kuid ei kujul, kus mingi üks neist suurustest on avaldatud ülejäänud suuruste funktsioonina; selline on näiteks täisnurkse kolmnurga kaatedite A,B ja hüpotenuusi C vaheline seos C2 = A2 + B2. Selliseid võrrandeid nimetatakse ilmutamata võrranditeks. Et näiteks eeltoodud võrrandit kasutada näiteks hüpotenuusi arvutamiseks kaatetite järgi, tuleb see võrrand hüpotenuusi suhtes ilmutada, s.t. viia kujule C = v(A2 + B2) . Tavaliselt ei hakka keegi ühe ilmutamata võrrandi asemel esitama kolme ilmutamata võrrandit - seos esitatakse ilmutamata kujul ja alles siis, kui on teada, millised suurused on antud ja millised tuleb arvutada, teisendatakse ilmutamata seos avutamiseks sobivale ilmutatud kujule.

Ka Prologi saab õpetada ilmutamata võrrandeid kasutama. Siin tekib siiski probleem Prologi sisseegitatud matemaatiliste avaldiste arvutamise algoritmiga, mis käitatakse operaatoriga X is Avaldis, kus X peab olema väärtustamata muutuja ja Avaldis peab olema arvutatav, s.t. ei tohi sisaldada (väärtustamata) muutujaid. Viimase tingimuse rikkumisel ei ole tulemuseks operaatori X is Avaldis ebaõnnestumine (fail), vaid kogu programmi peatumine veateatega.

Ilmutamata võrrandite poolte (avaldised) arvutamiseks on palju mugavam selline avaldise arvutamise operaator, mis muutujaid sisaldava avaldise puhul ei "lenda õhku", vaid lihtsalt ebaõnnestub ja programm saab tööd jätkata. Järgnevas kirjeldatud predikaat eval(Avaldis,X) arvutab avaldise Avaldis väärtuse (kui see on arvutatav) ja omistab tulemuse muutujale X; kui Avaldis ei ole arvutatav (sisaldab väärtustamata muutujaid), siis eval ebaõnnestub. Järgnevas kirjeldatud eval oskab arvutada vaid nelja aritmeetilist tehet (+, -, *, /) ja ruutjuurt sqrt sisaldavaid avaldisi, kuid seda on lihtne täiendada nii et see sobiks ka trigonomeetrilisi funktsioone, astmeid, logaritme jne sisaldavate avaldiste arvutamiseks.

eval(X,_):-
var(X),!,fail.
eval(X,X):-
number(X),!.
eval(X+Y,Z):-
eval(X,X1),eval(Y,Y1),Z is X1+Y1,!.
eval(X-Y,Z):-
eval(X,X1),eval(Y,Y1),Z is X1-Y1,!.
eval(X*Y,Z):-
eval(X,X1),eval(Y,Y1),Z is X1*Y1,!.
eval(X/Y,Z):-
eval(X,X1),eval(Y,Y1),not(Y1=0),Z is X1/Y1,!.
eval(sqrt(X),Z):-
eval(X,X1), Z is sqrt(X1).
Testimiseks võib lasta midagi arvutada:
?- eval(3+2*sqrt(4),X).

X = 7

- töötab!.

Predikaadi eval abil saab koostada ilmutamata võrrandeid lahendava predikaadi rel(Võrrand). Kui ilmutamata võrrandis Võrrand on vaid üks väärtustamata muutuja (kõigil ülejäänud muutujatel on väärtus), leiab rel selle muutuja väärtuse. Siin kirjeldatud lihtne rel versioon nõuab, et otsitav muutuja võib esineda võrrandis vaid ühes kohas (näiteks 2*X + 1 = 7 - X ei ei ole lubatud); erandina võib muutuja esineda kaks korda ruutavaldises X*X.

rel(E1=E2):-
eval(E1,X1),
eval(E2,X2),!, %mõlemal pool on juba arvud!
fail. %õnnestumiseks oleks pidanud leidma mingi muutuja väärtuse
rel(X=A):-
var(X),!,
eval(A,A1),!, % parema poole saab välja arvutada
X = A1.
rel(A = X):-
eval(A,Abi),!,
rel(X=Abi).

rel(A + B = C):-
eval(A,AbiX),!,
rel(B = C - AbiX).

rel(A + B = C):-
eval(B,AbiX),!,
rel(A = C - AbiX).
rel(A - B = C):-
eval(A,AbiX),!,
rel(B = AbiX - C).
rel(A - B = C):-
eval(B,AbiX),!,
rel(A = C + AbiX).

rel(A * B = C):-

eval(A,AbiX),!,
((not(AbiX=0),!,rel(B = C/AbiX));write('Viga: jagamine nulliga')).
rel(A * B = C):-
eval(B,AbiX),!,
((not(AbiX=0),!,rel(A = C / AbiX));write('Viga: jagamine nulliga')).
rel(A / B = C):-
eval(A,AbiX),!,
rel(B = AbiX/C).
rel(A / B = C):-
eval(B,AbiX),!,
rel(A = C * AbiX).

rel(X1*X2=A):-
var(X1),var(X2),not(X1==X2),!,fail.

rel(X*X=A):-
var(X),
eval(A,A1),!,call(X is sqrt(A1)).
rel(X^2=A):-
var(X),
eval(A,A1),!,call(X is sqrt(A1)).
rel(X**2=A):-
var(X),
eval(A,A1),!,call(X is sqrt(A1)).

Testime:

?- A=3,C=5,rel(A*A+B*B=C*C).
A = 3
C = 5
B = 4
- see predikaat suudab leida täisnurkse kolmnurga külje kahe antud külje jälgi.
Ülesandeid:
1. Täienda ülalesitatud predikaadi eval kirjeldust, nii et sellega saaks arvutada ka trigonomeetrilis funktsioone, astmeid ja logaritme sisaldavaid avaldisi.
2. Täienda ülalesitatud predikaadi rel kirjeldust nii et sellega saaks lahendada ilmutamata võrrandeid,mis on lineaarsed otsitava muutuja suhtes, s.t. kus otsitav muutuja võib esineda kõikjal vaid esimeses astmes (kuid võib esineda mitmes kohas, nagu ülaltoodud näites 2*X + 1 = 7 - X)


Küsimused, probleemid: ©2004 Jaak Henno