SUMA A 15.000 NUMERE
/************************************
Problema:
Sa se insumeze toate numerele date ca fapte intr-o baza interna, de forma:
nr(real).
Problema este interesanta pentru valori mari, de exemplu 15.000 de fapte in
baza, caz in care o solutie de tip findall esueaza.
Dificultatea consta in transmiterea unei sume partiale odata cu parcurgerea
solutiilor alternative nr(X), dat fiind ca atingerea unei solutii ulterioare
presupune backtracking, iar in acel moment orice informatie calculata
prin unificarea unor variabile se pierde prin insasi natura mecanismului
de backtracking.
Solutie:
- Se salveaza baza continand faptele
- Se verifica daca exista un fapt nr(X), se insumeaza intr-o variabila intermediara,
faptul se sterge din baza, apoi se apeleaza recursiv; astfel, reusim sa parcurgem
toate faptele din baza fara sa apelam la backtracking.
- La sfarsit, se consulta baza salvata la primul fapt, pentru a restaura faptele.
Pentru valori mici, putem testa corectitudinea solutiei suma2 comparativ cu
solutia suma1, printr-un goal de genul:
genereaza(1000), suma1(S1), suma2(S2)
Dat fiind ca numerele sunt parcurse in aceeasi ordine in ambele solutii,
se poate adauga si S1 = S2, altfel ar putea exista erori:
genereaza(1000), suma1(S1), suma2(S2), S1 = S2
Paul Mateescu, grupa 309-Informatica, an III-ZI, 2009.
Facultatea de Matematica si Informatica, Universitatea Spiru Haret Bucuresti.
*************************************/
domains
rl = real*
predicates
genereaza(real) % genereaza faptele nr(real) in baza
suma1(real) %prin findall
suma1(rl, real, real)
suma2(real) % prin retract de nr(real) pe masura ce este insumat
suma2(real, real)
database - numere
nr(real)
clauses
% Genereaza N fapte de forma nr(real) in baza de date "numere"
genereaza(N) :-
N > 0,
random(R),
R1 = 1000* R,
assertz(nr(R1)),
N1 = N - 1,
!,
genereaza(N1).
genereaza(_).
% Insumeaza toti X-ii pentru care nr(X). Esueaza pentru valori mari,
% de exemplu 15000!
suma1(S) :-
findall(X, nr(X), L),
suma1(L, 0, S).
suma1([], S, S) :- !.
suma1([H|T], SI, S) :-
SIA = SI + H,
!,
suma1(T, SIA, S).
% Insumeaza toti X-ii pentru care nr(X), evitand backtracking-ul:
suma2(S) :-
save("DBNUMERE.TXT", numere),
suma2(0, S),
consult("DBNUMERE.TXT", numere).
suma2(SI, S) :-
nr(X),
SIA = SI + X,
retract(nr(X)),
!,
suma2(SIA, S).
suma2(S, S).