% generated: 7 March 1990
% option(s): 
%
%   (deriv) times10
%
%   David H. D. Warren
%
%   symbolic derivatives

#ifndef	MERCURY

#include "harness.cpp"

data(_Data).

benchmark(_Data, quad(E1, E2, E3, E4)) :-
	ops8(E1), divide10(E2), log10(E3), times10(E4).

#define	num(n)	n
#define	cut	!

#else

#define	cut	true

:- module deriv.

:- import_module int, io.

:- interface.

:- type expr --->	log(expr)
		;	expr * expr
		;	expr / expr
		;	x
		;	num(int)
		;	expr + expr
		;	expr - expr
		;	- expr
		;	^(expr, int)
		;	exp(expr)
		.

:- type quad --->	quad(expr, expr, expr, expr).

:- pred benchmark(quad).
:- mode benchmark(out) is det.

:- pred main(io__state, io__state).
:- mode main(di, uo) is det.

:- implementation.

:- import_module require.

benchmark(quad(E1, E2, E3, E4)) :-
	ops8(E1),
	divide10(E2),
	log10(E3),
	times10(E4).

main -->
	{ ops8(E1) },
	print_expr(E1),
	io__write_string("\n\n"),
	{ divide10(E2) },
	print_expr(E2),
	io__write_string("\n\n"),
	{ log10(E3) },
	print_expr(E3),
	io__write_string("\n\n"),
	{ times10(E4) },
	print_expr(E4),
	io__write_string("\n").

:- pred times10(expr).
:- mode times10(out) is det.

:- pred log10(expr).
:- mode log10(out) is det.

:- pred ops8(expr).
:- mode ops8(out) is det.

:- pred divide10(expr).
:- mode divide10(out) is det.

:- pred d(expr, expr, expr).
:- mode d(in, in, out) is det.

:- pred print_expr(expr, io__state, io__state).
:- mode print_expr(in, di, uo) is det.

print_expr(x) -->
	io__write_string("x").
print_expr(num(N)) -->
	io__write_int(N).
print_expr(log(E)) -->
	io__write_string("log("),
	print_expr(E),
	io__write_string(")").
print_expr(exp(E)) -->
	io__write_string("exp("),
	print_expr(E),
	io__write_string(")").
print_expr(^(E, N)) -->
	io__write_string("^("),
	print_expr(E),
	io__write_string(", "),
	io__write_int(N),
	io__write_string(")").
print_expr(E1 + E2) -->
	io__write_string("("),
	print_expr(E1),
	io__write_string(" + "),
	print_expr(E2),
	io__write_string(")").
print_expr(E1 - E2) -->
	io__write_string("("),
	print_expr(E1),
	io__write_string(" - "),
	print_expr(E2),
	io__write_string(")").
print_expr(E1 * E2) -->
	io__write_string("("),
	print_expr(E1),
	io__write_string(" * "),
	print_expr(E2),
	io__write_string(")").
print_expr(E1 / E2) -->
	io__write_string("("),
	print_expr(E1),
	io__write_string(" / "),
	print_expr(E2),
	io__write_string(")").
print_expr(-E) -->
	io__write_string("- ("),
	print_expr(E),
	io__write_string(")").

#endif

#ifdef	AQUARIUS_DECLS
:- mode((d(E, X, R) :-
		ground(E),
		rderef(E),
		ground(X),
		rderef(X)
	)).
#endif

ops8(E) :-
	d((x + num(1)) * ((^(x, 2) + num(2)) * (^(x, 3) + num(3))), x, E).

divide10(E) :-
	d(((((((((x / x) / x) / x) / x) / x) / x) / x) / x) / x, x, E).

log10(E) :-
	d(log(log(log(log(log(log(log(log(log(log(x)))))))))), x, E).

times10(E) :-
	d(((((((((x * x) * x) * x) * x) * x) * x) * x) * x) * x, x, E).

#ifdef	NUPROLOG_DECLS
:- d(E, X, R) when E and X.
#endif

#ifdef	SICSTUS_DECLS
:- block d(-, ?, ?).
#endif

d(U + V, X, DU + DV) :-
	cut,
	d(U, X, DU),
	d(V, X, DV).
d(U - V, X, DU - DV) :-
	cut,
	d(U, X, DU),
	d(V, X, DV).
d(U * V, X, DU * V + U * DV) :-
	cut,
	d(U, X, DU),
	d(V, X, DV).
d(U / V, X, (DU * V - U * DV) / ^(V, 2)) :-
	cut,
	d(U, X, DU),
	d(V, X, DV).
d(^(U, N), X, DU * num(N) * ^(U, N1)) :-
	cut,
	N1 is N - 1,
	d(U, X, DU).
d(-U, X, -DU) :-
	cut,
	d(U, X, DU).
d(exp(U), X, exp(U) * DU) :-
	cut,
	d(U, X, DU).
d(log(U), X, DU / U) :-
	cut,
	d(U, X, DU).
#ifdef	MERCURY
d(x, X, num(1)) :-
	( X = x ->
		true
	;
		error("differentiating wrt nonvariable")
	).
#else
d(X, X, num(1)) :-
	cut.
#endif
d(num(_), _, num(0)).