%******************************************************************************
%
% ekspertni sistem za diferenciranje i uproscavanje
%
%******************************************************************************
% program se startuje sa start. a prekida sa stop.
%******************************************************************************
start:-
   write('Mogucnosti koje vam nudi sistem su:'),nl,
   write('  1. Diferenciranje unetog izraza i uproscavanje dobijenog'),nl,
   write('  2. Uproscavanje unetog izraza'),nl,
   write('Za opciju 1. na ulazu uneti:'),nl,
   write('  izraz :promenljiva po kojoj se diferencira.'),nl,
   write('ili'),nl,
   write('  izraz ;[promenljive po kojima se diferencira ].'),nl,nl,
   write('Za opciju 2. na ulazu uneti :'),nl,
   write('  izraz .'),nl,nl,
   write('Za izlaz iz programa uneti stop.'),nl,
   program, nl, nl, nl,
   write('Za ponovno startovanje programa uneti start.').

program:-repeat,
         read(X),
         (izlaz(X);
          d_u(X),fail).
      
izlaz(stop).        

d_u(X:Y):-X:Y,!.
d_u(X):-u(X,Y),
        stampanje(Y),nl,nl,!.

X:[Y]:-!,X:Y.
X:[Y|Z]:-d(X,Y,DX),
         write('diferenciran po '),write(Y),write(' : '),write(DX),nl,
         u(DX,R),
         write('uproscen : '),write(R),nl,
         !,
         R:Z.
X:Y:-d(X,Y,DX),
     write('diferenciran po '),write(Y),write(' : '),write(DX),nl,
     u(DX,R),
     write('rezultat : '),
     stampanje(R),nl,nl.

d(X,X,1).
d(C,X,0):-atom(C);
          number(C).
d(-U,X,-R):-d(U,X,R).
d(U+V,X,DU+DV):-d(U,X,DU),
                d(V,X,DV).
d(U-V,X,DU+ (-DV)):-d(U,X,DU),
                   d(V,X,DV).
d(C*U,X,C*DU):-number(C),
               d(U,X,DU).
d(U*V,X,DU*V+U*DV):-d(U,X,DU),
                    d(V,X,DV).
d(U/V,X,R):-d(U*V ^ (-1),X,R).
d(U^C,X,C*DU*U^ (C+ (-1))):-number(C),
                          d(U,X,DU).
d(U^V,X,DV*ln(U)*U^V+V*DU*U^ (V+ (-1))):-d(U,X,DU),d(V,X,DV).
d(sin(U),X,DU*cos(U)):-d(U,X,DU).
d(cos(U),X,(-DU)*sin(U)):-d(U,X,DU).
d(tan(U),X,R):-d(sin(U)/cos(U),X,R).
d(exp(U),X,DU*exp(U)):-d(U,X,DU).
d(ln(U),X,DU*U^ (-1)):-d(U,X,DU).

u(X,X):-atomic(X).
u(X,Y):-X=..[Op,U],u(U,U1),upr(Op,U1,Y).
u(X,Y):-X=..[Op,U,V],u(U,U1),u(V,V1),upr(Op,U1,V1,Y).

upr(+,C1*X,C2*X,R*X):-number(C1),number(C2),u2(+,C1,C2,R).
upr(/,X,Y^ (-1),R):-upr(*,X,Y,R).
upr(*,exp(X),exp(Y),exp(R)):-u2(+,X,Y,R).
upr(*,X,X,Y):-u2(^,X,2,Y).
upr(*,X,-X,Y):-u2(^,X,2,Z),u1(-,Z,Y).
upr(*,-X,X,Y):-u2(^,X,2,Z),u1(-,Z,Y).
upr(*,X,-Y,R):-u2(*,X,Y,Z),u1(-,Z,R).
upr(*,-X,Y,R):-u2(*,X,Y,Z),u1(-,Z,R).
upr(*,-X,-Y,R):-u2(*,X,Y,R).
upr(*,Z^X,Z^Y,R):-u2(+,X,Y,R1),u2(^,Z,R1,R).
upr(*,X^Z,Y^Z,R):-u2(*,X,Y,R1),u2(^,R1,Z,R).
upr(^,X^ (-1),-Z,R):-u2(^,X,Z,R).
upr(^,X*Y^ (-1),-Z,R):-u2(^,Y*X^ (-1),Z,R).
upr(Op,X,Y,R):-u2(Op,X,Y,R).
upr(-,X+Y,U+V):-u1(-,X,U),u1(-,Y,V).
upr(exp,C*ln(X),Y):-u2(^,X,C,Y).
upr(Op,X,Y):-u1(Op,X,Y).

u1(-,0,0).
u1(-,-X,X).
u1(-,X,Y):-Y is -X,Y\=err.
u1(sin,0,0).
u1(sin,-X,-sin(X)).
u1(cos,0,1).
u1(cos,-X,cos(X)).
u1(tan,0,0).
u1(tan,-X,-tan(X)).
u1(exp,0,1).
u1(exp,ln(X),X).
u1(ln,1,0).
u1(ln,exp(X),X).
u1(Op,X,Y):-Y=..[Op,X].

u2(+,X,0,X).
u2(+,0,X,X).
u2(+,X,-X,0).
u2(+,-X,X,0).
u2(+,A,B+X,R+X):-R is A+B,R\=err.
u2(+,A+X,C,R+X):-R is A+C,R\=err.
u2(+,(sin(X))^2,(cos(X))^2,1).
u2(+,(cos(X))^2,(sin(X))^2,1).
u2(+,(cos(X))^2,-(sin(X)^2),cos(R)):-u2(*,2,X,R).
u2(+,-(sin(X)^2),(cos(X))^2,cos(R)):-u2(*,2,X,R).
u2(+,X,Y,Z):-Z is X+Y,Z\=err.
u2(+,X,A,A+X):-number(A).
u2(*,0,_,0).
u2(*,_,0,0).
u2(*,X,1,X).
u2(*,1,X,X).
u2(*,-1,X,-X).
u2(*,X,-1,-X).
u2(*,X,X^ (-1),1).
u2(*,X^ (-1),X,1).
u2(*,X,Y/X,Y).
u2(*,Y/X,X,Y).
u2(*,2*sin(X),cos(X),sin(R)):-u2(*,2,X,R).
u2(*,sin(X),2*cos(X),sin(R)):-u2(*,2,X,R).
u2(*,cos(X),2*sin(X),sin(R)):-u2(*,2,X,R).
u2(*,2*cos(X),sin(X),sin(R)):-u2(*,2,X,R).
u2(*,sin(X),tan(X),cos(X)).
u2(*,tan(X),sin(X),cos(X)).
u2(*,A,B*X,R*X):-R is A*B,R\=err.
u2(*,A,X*B,R*X):-R is A*B,R\=err.
u2(*,X,Y,Z):-Z is X*Y,Z\=err.
u2(*,X,A,X*A):-number(A).
u2(^,1,_,1).
u2(^,_,0,1).
u2(^,X,1,X).
u2(/,X,1,X).
u2(/,X,X,1).
u2(/,1,X,X^ (-1)).
u2(/,sin(X),cos(X),tan(X)).
u2(/,X,Y,R):-Z is X/Y,Z\=err.
u2(Op,X,Y,R):-R=..[Op,X,Y].

stampanje(X):-ukloni(X,Y),write(Y).

ukloni(X,X):-atom(X);number(X).
ukloni(X,Y):-X=..[Op,U],ukloni(U,U1),Y=..[Op,U1].
ukloni(X,Y):-X=..[Op,U,V],ukloni(U,U1),
             ukloni(V,V1),W=..[Op,U1,V1],
             zameni(W,Y).

zameni(-Y+X,X-Y).
zameni(X+ (-Y),X-Y).
zameni(X*Y^ (-1),X/Y).
zameni(X^ (-1)*Y,Y/X).
zameni(X,X).
      




