:- module(_,_,[sr/bfall]).

% Trees example: symbolic differenciation

% deriv(E,X,D): `D` is the derivative of expression `E` w.r.t. `X`.

deriv(X,     X, s(0)                 ).
deriv(C,    _X, 0                    ) :- pconstant(C).
deriv(U+V,   X, DU+DV                ) :- deriv(U,X,DU), deriv(V,X,DV). 
deriv(U-V,   X, DU-DV                ) :- deriv(U,X,DU), deriv(V,X,DV).
deriv(U*V,   X, DU*V+U*DV            ) :- deriv(U,X,DU), deriv(V,X,DV).
deriv(U/V,   X, (DU*V-U*DV)/V^s(s(0))) :- deriv(U,X,DU), deriv(V,X,DV).
deriv(U^s(N),X, s(N)*U^N*DU          ) :- deriv(U,X,DU), nat_num(N).
deriv(log(U),X, DU/U                 ) :- deriv(U,X,DU).

pconstant(X) :- nat_num(X).
pconstant(a).
pconstant(b).
pconstant(c).

% Try:
% ?- deriv(s(s(s(0)))*x+s(s(0)),x,Y).
% ?- deriv(s(s(s(0)))*x+s(s(0)),x,0*x+s(s(s(0)))*s(0)+0).
% ?- deriv(E,x,0*x+s(s(s(0)))*s(0)+0).


% Version using functional notation: 
:- use_package(fsyntax).
derivf(X,          X) := s(0).
derivf(~pconstant, _) := 0.
derivf(U+V,        X) := ~derivf(U,X) + ~derivf(V,X).
derivf(U-V,        X) := ~derivf(U,X) - ~derivf(V,X).
derivf(U*V,        X) := ~derivf(U,X) * V  +  U * ~derivf(V,X).
derivf(U/V,        X) := ( ~derivf(U,X) * V - U * ~derivf(V,X) ) / V^s(s(0)).
derivf(U^s(N),     X) := s(N) * U^N * ~derivf(U,X) :- nat_num(N).
derivf(log(U),     X) := ~derivf(U,X) / U.

% Try:
% ?- derivf(s(s(s(0)))*x+s(s(0)),x,Y).
% ?- derivf(s(s(s(0)))*x+s(s(0)),x,0*x+s(s(s(0)))*s(0)+0).
% ?- derivf(E,x,0*x+s(s(s(0)))*s(0)+0).


% Auxiliary predicates: 
nat_num(0).
nat_num(s(X)) :- 
    nat_num(X).
