% poly_10 % % Ralph Haygood (based on Prolog version by Rick McGeer % based on Lisp version by R. P. Gabriel) % % raise a polynomial (1+x+y+z) to the 10th power (symbolically) #ifndef MERCURY #include "harness.cpp" data(Data) :- test_poly(Data). benchmark(Data, Out) :- poly_exp(10, Data, Out). #define const(n) n #else :- module poly. :- interface. :- import_module int, io. :- type var ---> x ; y ; z. :- type pterm ---> term(int, poly). :- type poly ---> poly(var, list(pterm)) ; const(int). :- pred main(io__state, io__state). :- mode main(di, uo) is det. :- pred benchmark(poly). :- mode benchmark(out) is det. :- implementation. main --> { benchmark(Out) }, print_poly(Out), io__write_string("\n"). benchmark(Out) :- test_poly(P), poly_exp(10, P, Out). :- pred test_poly1(poly). :- mode test_poly1(out) is det. :- pred test_poly2(poly). :- mode test_poly2(out) is det. :- pred test_poly3(poly). :- mode test_poly3(out) is det. :- pred test_poly(poly). :- mode test_poly(out) is det. :- pred poly_add(poly, poly, poly). :- mode poly_add(in, in, out) is det. :- pred term_add(list(pterm), list(pterm), list(pterm)). :- mode term_add(in, in, out) is det. :- pred add_to_order_zero_term(list(pterm), poly, list(pterm)). :- mode add_to_order_zero_term(in, in, out) is det. :- pred poly_exp(int, poly, poly). :- mode poly_exp(in, in, out) is det. :- pred poly_mul(poly, poly, poly). :- mode poly_mul(in, in, out) is det. :- pred term_mul(list(pterm), list(pterm), list(pterm)). :- mode term_mul(in, in, out) is det. :- pred single_term_mul(list(pterm), pterm, list(pterm)). :- mode single_term_mul(in, in, out) is det. :- pred mul_through(list(pterm), poly, list(pterm)). :- mode mul_through(in, in, out) is det. :- pred lt(var, var). :- mode lt(in, in) is semidet. :- pred even(int). :- mode even(in) is semidet. :- pred print_poly(poly, io__state, io__state). :- mode print_poly(in, di, uo) is det. :- pred print_var(var, io__state, io__state). :- mode print_var(in, di, uo) is det. :- pred print_terms(list(pterm), io__state, io__state). :- mode print_terms(in, di, uo) is det. :- pred print_terms_2(list(pterm), io__state, io__state). :- mode print_terms_2(in, di, uo) is det. :- pred print_term(pterm, io__state, io__state). :- mode print_term(in, di, uo) is det. print_poly(const(N)) --> io__write_string("const("), io__write_int(N), io__write_string(")"). print_poly(poly(Var, Terms)) --> io__write_string("poly("), print_var(Var), io__write_string(", "), print_terms(Terms), io__write_string(")"). print_var(x) --> io__write_string("x"). print_var(y) --> io__write_string("y"). print_var(z) --> io__write_string("z"). print_terms(Terms) --> ( { Terms = [] } -> io__write_string("[]\n") ; io__write_string("["), print_terms_2(Terms), io__write_string("]") ). print_terms_2([]) --> []. print_terms_2([Term|Terms]) --> print_term(Term), ( { Terms = [] } -> [] ; io__write_string(", "), print_terms_2(Terms) ). print_term(term(N, Poly)) --> io__write_string("term("), io__write_int(N), io__write_string(", "), print_poly(Poly), io__write_string(")"). #endif #ifdef AQUARIUS_DECLS :- mode((poly_add(P1, P2, R) :- ground(P1), rderef(P1), ground(P2), rderef(P2) )). :- mode((term_add(L1, L2, R) :- ground(L1), rderef(L1), list(L1), ground(L2), rderef(L2), list(L2) )). :- mode((add_to_order_zero_term(L, P, R) :- ground(L), rderef(L), list(L), ground(P), rderef(P) )). :- mode((poly_exp(I, P, R) :- ground(I), rderef(I), integer(I), ground(P), rderef(P) )). :- mode((poly_mul(P1, P2, R) :- ground(P1), rderef(P1), ground(P2), rderef(P2) )). :- mode((term_mul(L1, L2, R) :- ground(L1), rderef(L1), list(L1), ground(L2), rderef(L2), list(L2) )). :- mode((single_term_mul(L, T, R) :- ground(L), rderef(L), list(L), ground(T), rderef(T) )). :- mode((mul_through(L, P, R) :- ground(L), rderef(L), list(L), ground(P), rderef(P) )). :- mode((lt(V1, V2) :- ground(V1), rderef(V1), ground(V2), rderef(V2) )). :- mode((even(N) :- ground(N), rderef(N), integer(N) )). #endif test_poly1(P) :- P = poly(x, [term(0,const(1)), term(1,const(1))]). test_poly2(P) :- P = poly(y, [term(1,const(1))]). test_poly3(P) :- P = poly(z, [term(1,const(1))]). test_poly(P) :- poly_add(poly(x, [term(0,const(1)), term(1,const(1))]), poly(y, [term(1, const(1))]), Q), poly_add(poly(z, [term(1,const(1))]), Q, P). #ifdef MERCURY poly_add(poly(Var1, Terms1), poly(Var2, Terms2), Result) :- ( Var1 = Var2 -> term_add(Terms1, Terms2, Terms), Result = poly(Var1, Terms) ; lt(Var1, Var2) -> add_to_order_zero_term(Terms1, poly(Var2, Terms2), Terms), Result = poly(Var1, Terms) ; add_to_order_zero_term(Terms2, poly(Var1, Terms1), Terms), Result = poly(Var2, Terms) ). poly_add(poly(Var1, Terms1), const(C2), poly(Var1, Terms)) :- add_to_order_zero_term(Terms1, const(C2), Terms). poly_add(const(C1), poly(Var2, Terms2), poly(Var2, Terms)) :- add_to_order_zero_term(Terms2, const(C1), Terms). poly_add(const(C1), const(C2), const(C)) :- C is C1 + C2. #else #ifdef NUPROLOG_DECLS :- poly_add(P1, P2, R) when P1 and P2. #endif #ifdef SICSTUS_DECLS :- block poly_add(-, ?, ?), poly_add(?, -, ?). #endif poly_add(poly(Var,Terms1), poly(Var,Terms2), poly(Var,Terms)) :- !, term_add(Terms1, Terms2, Terms). poly_add(poly(Var1,Terms1), poly(Var2,Terms2), poly(Var1,Terms)) :- lt(Var1, Var2), !, add_to_order_zero_term(Terms1, poly(Var2,Terms2), Terms). poly_add(Poly, poly(Var,Terms2), poly(Var,Terms)) :- !, add_to_order_zero_term(Terms2, Poly, Terms). poly_add(poly(Var,Terms1), C, poly(Var,Terms)) :- !, add_to_order_zero_term(Terms1, C, Terms). poly_add(C1, C2, C) :- C is C1 + C2. #endif #ifdef MERCURY term_add([], List2, List2). term_add([term(E1,C1)|Terms1], [], [term(E1,C1)|Terms1]). term_add([term(E1,C1)|Terms1], [term(E2,C2)|Terms2], Result) :- ( E1 = E2 -> poly_add(C1, C2, C), term_add(Terms1, Terms2, Terms), Result = [term(E1,C)|Terms] ; E1 < E2 -> term_add(Terms1, [term(E2,C2)|Terms2], Terms), Result = [term(E1,C1)|Terms] ; term_add([term(E1,C1)|Terms1], Terms2, Terms), Result = [term(E2,C2)|Terms] ). #else #ifdef NUPROLOG_DECLS :- term_add(L1, L2, R) when L1 and L2. #endif #ifdef SICSTUS_DECLS :- block term_add(-, ?, ?), term_add(?, -, ?). #endif term_add([], X, X) :- !. term_add(X, [], X) :- !. term_add([term(E,C1)|Terms1], [term(E,C2)|Terms2], [term(E,C)|Terms]) :- !, poly_add(C1, C2, C), term_add(Terms1, Terms2, Terms). term_add([term(E1,C1)|Terms1], [term(E2,C2)|Terms2], [term(E1,C1)|Terms]) :- E1 < E2, !, term_add(Terms1, [term(E2,C2)|Terms2], Terms). term_add(Terms1, [term(E2,C2)|Terms2], [term(E2,C2)|Terms]) :- term_add(Terms1, Terms2, Terms). #endif #ifdef MERCURY add_to_order_zero_term(List, C2, Result) :- ( List = [term(0,C1)|Terms] -> poly_add(C1, C2, C), Result = [term(0,C)|Terms] ; Result = [term(0,C2)|List] ). #else #ifdef NUPROLOG_DECLS :- add_to_order_zero_term(L1, L2, R) when L1 and L2. #endif #ifdef SICSTUS_DECLS :- block add_to_order_zero_term(-, ?, ?), add_to_order_zero_term(?, -, ?). #endif add_to_order_zero_term([term(0,C1)|Terms], C2, [term(0,C)|Terms]) :- !, poly_add(C1, C2, C). add_to_order_zero_term(Terms, C, [term(0,C)|Terms]). #endif #ifdef MERCURY poly_exp(N, Poly, Result) :- ( N = 0 -> Result = const(1) ; even(N) -> M is N // 2, poly_exp(M, Poly, Part), poly_mul(Part, Part, Result) ; M is N - 1, poly_exp(M, Poly, Part), poly_mul(Poly, Part, Result) ). #else #ifdef NUPROLOG_DECLS :- poly_exp(N, P, R) when N. #endif #ifdef SICSTUS_DECLS :- block poly_exp(-, ?, ?). #endif poly_exp(0, _, 1) :- !. poly_exp(N, Poly, Result) :- M is N>>1, N is M<<1, !, poly_exp(M, Poly, Part), poly_mul(Part, Part, Result). poly_exp(N, Poly, Result) :- M is N - 1, poly_exp(M, Poly, Part), poly_mul(Poly, Part, Result). #endif #ifdef MERCURY poly_mul(poly(Var1, Terms1), poly(Var2, Terms2), Result) :- ( Var1 = Var2 -> term_mul(Terms1, Terms2, Terms), Result = poly(Var1, Terms) ; lt(Var1, Var2) -> mul_through(Terms1, poly(Var2, Terms2), Terms), Result = poly(Var1, Terms) ; mul_through(Terms2, poly(Var1, Terms1), Terms), Result = poly(Var2, Terms) ). poly_mul(poly(Var1, Terms1), const(C2), poly(Var1, Terms)) :- mul_through(Terms1, const(C2), Terms). poly_mul(const(C1), poly(Var2, Terms2), poly(Var2, Terms)) :- mul_through(Terms2, const(C1), Terms). poly_mul(const(C1), const(C2), const(C)) :- C is C1 * C2. #else #ifdef NUPROLOG_DECLS :- poly_mul(P1, P2, R) when P1 and P2. #endif #ifdef SICSTUS_DECLS :- block poly_mul(-, ?, ?), poly_mul(?, -, ?). #endif poly_mul(poly(Var,Terms1), poly(Var,Terms2), poly(Var,Terms)) :- !, term_mul(Terms1, Terms2, Terms). poly_mul(poly(Var1,Terms1), poly(Var2,Terms2), poly(Var1,Terms)) :- lt(Var1, Var2), !, mul_through(Terms1, poly(Var2,Terms2), Terms). poly_mul(P, poly(Var,Terms2), poly(Var,Terms)) :- !, mul_through(Terms2, P, Terms). poly_mul(poly(Var,Terms1), C, poly(Var,Terms)) :- !, mul_through(Terms1, C, Terms). poly_mul(C1, C2, C) :- C is C1 * C2. #endif #ifdef MERCURY term_mul([], _List2, []). term_mul([_Term1|_Terms1], [], []). term_mul([Term1|Terms1], [Term2|Terms2], Result) :- single_term_mul([Term2|Terms2], Term1, PartA), term_mul(Terms1, [Term2|Terms2], PartB), term_add(PartA, PartB, Result). #else #ifdef NUPROLOG_DECLS :- term_mul(L1, L2, R) when L1 and L2. #endif #ifdef SICSTUS_DECLS :- block term_mul(-, ?, ?), term_mul(?, -, ?). #endif term_mul([], _, []) :- !. term_mul(_, [], []) :- !. term_mul([Term|Terms1], Terms2, Terms) :- single_term_mul(Terms2, Term, PartA), term_mul(Terms1, Terms2, PartB), term_add(PartA, PartB, Terms). #endif #ifdef MERCURY single_term_mul([], _Term, []). single_term_mul([term(E1,C1)|Terms1], term(E2,C2), [term(E,C)|Terms]) :- E is E1 + E2, poly_mul(C1, C2, C), single_term_mul(Terms1, term(E2,C2), Terms). #else #ifdef NUPROLOG_DECLS :- single_term_mul(L, T, R) when L and T. #endif #ifdef SICSTUS_DECLS :- block single_term_mul(-, ?, ?), single_term_mul(?, -, ?). #endif single_term_mul([], _, []) :- !. single_term_mul([term(E1,C1)|Terms1], term(E2,C2), [term(E,C)|Terms]) :- E is E1 + E2, poly_mul(C1, C2, C), single_term_mul(Terms1, term(E2,C2), Terms). #endif #ifdef MERCURY mul_through([], _Poly, []). mul_through([term(E,Term)|Terms], Poly, [term(E,NewTerm)|NewTerms]) :- poly_mul(Term, Poly, NewTerm), mul_through(Terms, Poly, NewTerms). #else #ifdef NUPROLOG_DECLS :- mul_through(L, P, R) when L and P. #endif #ifdef SICSTUS_DECLS :- block mul_through(-, ?, ?), mul_through(?, -, ?). #endif mul_through([], _, []) :- !. mul_through([term(E,Term)|Terms], Poly, [term(E,NewTerm)|NewTerms]) :- poly_mul(Term, Poly, NewTerm), mul_through(Terms, Poly, NewTerms). #endif #ifdef NUPROLOG_DECLS :- lt(V1, V2) when V1 and V2. #endif #ifdef SICSTUS_DECLS :- block lt(-, ?), lt(?, -). #endif lt(x, y). lt(y, z). lt(x, z). #ifdef NUPROLOG_DECLS :- even(N) when N. #endif #ifdef SICSTUS_DECLS :- block even(-). #endif even(N) :- M is N // 2, N1 is M * 2, N = N1.