This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
vsc e5f4633c39 This commit was generated by cvs2svn to compensate for changes in r4,
which included commits to RCS files with non-trunk default branches.


git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@5 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
2001-04-09 19:54:03 +00:00

512 lines
16 KiB
Plaintext

/*
**********************************************************************
*
* CLP(R) Version 2.0 (Example Programs Release)
* (C) Copyright, March 1986, Monash University
*
**********************************************************************
*/
% use clpr -z 1e-20
/*
* RKF45 implementation in CLP(R): See [Harland & Michaylov].
*
* Assumes that the function is evaluated by a predicate of the form
*
* eval(T, Y, Yp), where T is the independent variable,
* Y the current vector of solutions,
* Yp the new vector derivative
*
* e.g. eval(T, [Y1,Y2], [T*T + Y1*Y1, T*T - Y2*Y2]).
*
* Note: machine epsilon is available as #zero (pre-defined constant).
*
* Separate "mode" from the rest - may help efficiency
*/
/*
* solve(Y, T, Tout, Incr, Relerr, Abserr)
* Predicate called by the user - if he wants to specify a mode, he calls
* solve/7 direct (only needed for single_step mode).
*
* Y - initial position vector
* T - starting point for independent variable
* Tout - last point at which output is desired
* Incr - default output increment
* Relerr - relative error tolerance
* Abserr - absolute error tolerance
*/
solve(Y, Tstart, Tend, Incr, Relerr, Abserr) :-
solve(Y, Tstart, Tend, Incr, Relerr, Abserr, normal).
/*
* Error checks
*/
solve(_, _, _, 0, _, _, normal) :-
printf("Increment must be non-zero for normal mode\n",[]).
solve(_, _, _, _, Relerr, _, _) :-
Relerr < 0,
printf("Relative error must be non-negative\n",[]).
solve(_, _, _, _, _, Abserr, _) :-
Abserr < 0,
printf("Relative error must be non-negative\n",[]).
solve(_, T, T, _, _, _, _) :-
printf("No interval\n",[]).
/*
* Everything seems ok, so proceed
*/
solve(Y, T, Tend, Incr, Relerr, Abserr, Mode) :-
set_yp(T, Y, Yp), % Nfe = Nfe + 1
output(T, Y),
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, 1, 0)). % Work out the rest
% Nfe = 1
% Kop = 0
/*
* Commence main iteration
*/
solve1(user(_, T, Tend, Incr, _, _, _), work(_, _, Nfe, _, _)) :-
abs(T - Tend) < Incr / 4,
printf("\nIteration finished\n------------------\n",[]),
printf(" %d derivative evaluations\n",[Nfe]).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, reset(Mode, relerr)), _) :-
remin(Remin),
Relerr < 2* #zero + Remin,
printf("Warned you to reset it larger than %f\n", [Relerr]).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, reset(Mode, relerr)),
work(Yp, H, Nfe, Kop, Tout)) :-
remin(Remin),
Relerr >= 2* #zero + Remin,
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout)).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, reset(Mode, abserr, Oerr)), _) :-
Abserr <= Oerr,
printf("Abserr must be increased - not set to %f\n", [Abserr]).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, reset(Mode, abserr, Oerr)),
work(Yp, H, Nfe, Kop, Tout)) :-
Abserr > Oerr,
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout)).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), work(Yp, Nfe, Kop)) :-
% First time - need to set H
set_tout(T, Tend, Incr, Tout), % Next output point
set_hinit(T, Tout-T, Y, Yp, Relerr, Abserr, H),
set_kop(Kop, H, Tout-T, Newkop),
stop_or_iter(user(Y, T, Tend, Incr, Relerr, Abserr, normal),
work(Yp, H, Nfe, Newkop, Tout)).
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
% H already set - continue on
work(Yp, H, Nfe, Kop, _)) :-
set_tout(T, Tend, Incr, Tout),
sign(Tout-T, S),
set_kop(Kop, S*H, Tout-T, Newkop),
stop_or_iter(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, S*H, Nfe, Newkop, Tout)).
/*
* Perform certain error checks
*/
stop_or_iter(User, work(Yp, H, Nfe, Kop, Tout)) :-
Kop >= 100,
check_out(User, work(Yp, H, Nfe, 0, Tout), output_excess).
stop_or_iter(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), Work) :-
remin(Remin),
Relerr < 2* #zero + Remin,
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), Work, relerr).
stop_or_iter(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout)) :-
Abs = abs(Tout-T),
Tabs = abs(T),
% Use Euler approximation
Abs <= 26* #zero*Tabs,
set_euler(Tout-T, Y, Yp, NewY),
% Nfe = Nfe + 1
set_yp(Tout, NewY, NewYp),
print_or_it(user(NewY, Tout, Tend, Incr, Relerr, Abserr,
mode(Mode, output)), work(NewYp, H, Nfe+1, Kop, Tout)).
stop_or_iter(User, Work) :-
% Go on with main loop .......
iter(User, Work).
iter(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout)) :-
set_modeh(Tout-T, H, NewH, Out),
iter1(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, Out, nofail)),
work(Yp, NewH, Nfe, Kop, Tout)).
iter1(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, Out, Hmode)),
work(Yp, H, Nfe, Kop, Tout)) :-
max_func_eval(Maxfunc),
Nfe >= Maxfunc,
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout), max_func).
iter1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout)) :-
fehl(Y, T, Yp, H, Sum, Abserr, Relerr, Errest, Ind),
stop_or_iter1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe+5, Kop, Tout), Sum, Errest, Ind).
stop_or_iter1(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, Out, Hmode)),
Work, _, _, vanished) :-
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), Work, vanished).
stop_or_iter1(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout), Sum, Esttol, okay) :-
Esttol > 1,
set_smin(Esttol, S),
check_h(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, S*H, Nfe, Kop, Tout)).
stop_or_iter1(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, Out, Hmode)),
work(Yp, H, Nfe, Kop, Tout), Sum, Esttol, okay) :-
Esttol <= 1,
% Nfe = Nfe+1
set_yp(T+H, Sum, NewYp),
set_hmax(Esttol, Hmode, T, H, NewH),
print_or_it(user(Sum, T+H, Tend, Incr, Relerr, Abserr,
mode(Mode, Out)), work(NewYp, NewH, Nfe+1, Kop, Tout)).
print_or_it(user(Y, T, Tend, Incr, Relerr, Abserr,
mode(normal,proceed)), Work) :-
iter(user(Y, T, Tend, Incr, Relerr, Abserr, normal), Work).
print_or_it(user(Y, T, Tend, Incr, Relerr, Abserr,
mode(normal, output)), Work) :-
output(T, Y),
solve1(user(Y, T, Tend, Incr, Relerr, Abserr, normal), Work).
print_or_it(user(Y, T, Tend, Incr, Relerr, Abserr,
mode(single_step, _)), Work) :-
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, single_step), Work).
check_h(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, _, _)),
work(Yp, H, Nfe, Kop, Tout)) :-
Habs = abs(H),
Tabs = abs(T),
Habs <= 26* #zero*Tabs,
printf("Tabs = %e , Habs = %e , #zero = %e \n",[Tabs,Habs,#zero]),
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode),
work(Yp, H, Nfe, Kop, Tout), step_small).
check_h(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode, Out, _)), Work) :-
iter1(user(Y, T, Tend, Incr, Relerr, Abserr, mode(Mode,proceed,hfail)),
Work).
/*
* check_out(user(Y, Tstart, Tend, Incr, Relerr, Abserr, Mode),
* work(Yp, H, Nfe, Kop, Tout), Flag)
* Checks the status variable Flag, and takes appropriate action.
* See if there is a user-defined procedure
*/
check_out(User, Work, Flag) :-
user_error(User, Work, Flag),
!.
% No user procedure, so use the default ones.
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, single_step),
Work, single_step) :-
printf("(single_step) T: %10.6f Y: %10.6f\n",[T,Y]),
solve(Y, T, Tend, Incr, Relerr, Abserr, single_step),!.
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), Work, relerr) :-
% Iflag = 3
remin(Remin),
Rer = 3* #zero + Remin,
printf("Relative error too small - reset to %f\n", [Rer]),
solve1(user(Y, T, Tend, Incr, Rer, Abserr, reset(Mode, relerr)), Work).
check_out(User, work(Yp, H, Nfe, Kop, Tout), max_func) :-
% Iflag = 4
max_func_eval(Max),
Nfe >= Max,
printf("Lots of function evaluations - %f needed so far\n",[Max]),
solve1(User, work(Yp, H, 0, Kop, Tout)).
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, Mode), Work, vanished) :-
% Iflag = 5
abmin(Absmin),
printf("Abserr reset to %f\n", [Absmin]),
solve1(user(Y, T, Tend, Incr, Relerr, 10*Abserr + Absmin,
reset(Mode, abserr, Abserr)), Work).
check_out(user(Y, T, Tend, Incr, Relerr, Abserr, normal), Work, step_small) :-
% Iflag = 6
printf("Relerr too small; reset to %f\n", [10*Relerr]),
solve1(user(Y, T, Tend, Incr, 10*Relerr, Abserr, normal), Work).
check_out(User, work(Yp, H, Nfe, Kop, Tout), output_excess) :-
% Iflag = 7
printf("Excessive output; this will be inefficient",[]),
solve1(User, work(Yp, H, Nfe, 0, Tout)).
check_out(_, _, stuffed) :-
% Iflag = 8
printf("Improper call - wrong number of arguments?\n").
check_out(_, _, missing) :-
printf("User-supplied predicate eval is missing or wrong\n"),
printf("Format is eval(T, Y, Yp),\n",[]),
printf("where T is the independent variable, ",[]),
printf("Y the vector, and Yp its derivative.",[]),
printf("Y and Yp are CLP lists - [Y1, Y2, Y3], [Yp1, Yp2, Yp3] etc.",[]).
check_out(_, _, Other) :-
printf("Damned if I know what''s wrong!\n",[]).
/*
* output(T, Y).
* output(user(Y, T, Tend, Incr, Relerr, Abserr), work(Yp, H, Nfe, Kop, Tout))
* Output predicate. If there is a user_output predicate (matching the above
* format), then it is used. Otherwise, T and Y are written to standard output.
*/
output(T, Y) :-
user_output(T, Y),
!.
output(T, Y) :-
printf("T: %10.6f Y: ",[T]),
write_list(Y).
write_list([L|List]) :-
printf(" %10.6f ",[L]),
write_list(List).
write_list([]) :-
nl.
/*
* Set routines - setting values of variables given certain conditions etc.
*/
set_yp(T, Y, Yp) :-
eval(T, Y, Yp).
set_yp(T, [Y], [Yp]) :-
% For one var case with no list functor
eval(T, Y, Yp).
set_hinit(T, Dt, Y, Yp, Relerr, Abserr, H) :-
H1 = abs(Dt),
set_maxtol(H1, Y, Yp, Relerr, Abserr, Maxtol),
set_h1(H1, T, Dt, Maxtol, H).
set_maxtol(H, [Y|Yrest], [Yp|Yprest], Relerr, Abserr, Maxtol) :-
Yabs = abs(Y),
Tol1 = Relerr*Yabs + Abserr,
Tol1 > 0,
Ypabs = abs(Yp),
set_maxh(Ypabs, H, Tol1, H1),
set_maxtol(H1, Yrest, Yprest, Relerr, Abserr, Tol2),
Maxtol = max(Tol1, Tol2).
set_maxtol(H, [Y|Yrest], [Yp|Yprest], Relerr, Abserr, Maxtol) :-
Yabs = abs(Y),
Relerr*Yabs + Abserr <= 0,
set_maxtol(H, Yrest, Yprest, Relerr, Abserr, Maxtol).
set_maxtol(_, [], [], _, _, 0).
set_maxh(0, H, _, H).
set_maxh(Ypabs, H, Tol, NewH) :-
Ypabs > 0,
NewH = min(H, pow(Tol/Ypabs, 1/5)). % From abs(Yp)*h**5 <= Tol
set_h1(H, T, Dt, Tol, 26* #zero*Max) :-
Tol <= 0,
Tabs = abs(T),
Dtabs = abs(Dt),
Max = max(Tabs, Dtabs).
set_h1(H, T, Dt, Tol, NewH) :-
Tol > 0,
Tabs = abs(T),
Dtabs = abs(Dt),
Max = max(Tabs, Dtabs),
NewH = max(H, 26* #zero*Max).
set_modeh(Dt, H, H, proceed) :-
Dtabs = abs(Dt),
Habs = abs(H),
Dtabs >= 2*Habs.
set_modeh(Dt, H, Dt/2, proceed) :-
Habs = abs(H),
Dtabs = abs(Dt),
Dtabs < 2*Habs,
Dtabs > Habs.
set_modeh(Dt, H, Dt, output) :-
Habs = abs(H),
Dtabs = abs(Dt),
Dtabs <= Habs.
set_kop(Kop, H, Dt, Kop+1) :-
Habs = abs(H),
Dabs = abs(Dt),
Habs >= 2*Dabs.
set_kop(Kop, H, Dt, Kop) :-
Habs = abs(H),
Dabs = abs(Dt),
Habs < 2*Dabs.
set_smin(Esttol, 0.9/(pow(Esttol, 1/5)) ) :-
Esttol < 59049.
set_smin(Esttol, 0.1) :-
Esttol >= 59049.
set_hmax(Esttol, Hmode, T, H, Sign*H1) :-
set_smax(Esttol, Hmode, S),
Habs = abs(H),
Tabs = abs(T),
H1 = max(S*Habs, 26* #zero*Tabs),
sign(H, Sign).
set_smax(Esttol, nofail, 5) :-
Esttol <= 0.0001889568.
set_smax(Esttol, nofail, 0.9/(pow(Esttol, 1/5)) ) :-
Esttol > 0.0001889568.
set_smax(Esttol, hfail, 1) :-
Esttol <= 0.0001889568.
set_smax(Esttol, hfail, S) :-
Esttol > 0.0001889568,
S = min(0.9/(pow(Esttol, 1/5)), 1).
set_euler(Dt, [Y|Yrest], [Yp|Yprest], [NewY|NewYrest]) :-
NewY = Y + Dt*Yp,
set_euler(Dt, Yrest, Yprest, NewYrest).
set_euler(_, [], [], []).
/*
* set_tout(T, Tend, Incr, Tout)
* Tout is the next output point, T the current value, Tend the final point
* and Incr the set increment.
*
* If there is a user-supplied predicate user_tout, then it is used.
* Otherwise, we add Incr to T and proceed.
* Note that Incr may be negative.
*/
set_tout(T, Tend, Incr, Tout) :-
user_tout(T, Tend, Incr, Tout),
!.
set_tout(T, Tend, Incr, Tend) :-
Abs = abs(Tend - (T + Incr)),
Abs < Incr.
set_tout(T, Tend, Incr, T + Incr) :-
Abs = abs(Tend - (T + Incr)),
Abs >= Incr.
/*
* fehl(Y, T, Yp, H, Sum, Abserr, Relerr, Errest, Errind)
* Predicate to perform the evaluation of Fehlberg formulae
*
* Sum is the new estimate for Y
* Abserr is the absolute error.
* Relerr is the relative error.
* Errest is the Fehlberg estimate of the error.
* Errind indicates whether Abs is too small or not.
* If so, Errind is set to "vanished". Otherwise, it is "okay".
*/
fehl(Y, T, Yp, H, S, Abs, Rel, Err, Ind) :-
Ch1 = H/4,
Ch2 = H*3/32,
Ch3 = H/2197,
Ch4 = H/4104,
Ch5 = H/20520,
Ch6 = H/7618050,
fehl1(Y, T, Yp, H, ch(Ch1, Ch2, Ch3, Ch4, Ch5, Ch6),
S, Abs, Rel, Err, Ind).
fehl1(Y, T, Yp, H, ch(Ch1, Ch2, Ch3, Ch4, Ch5, Ch6), S, Abs, Rel, Err, Ind) :-
% calculate each of the Fi .....
set_f1(Y, Yp, Ch1, P1), set_yp(T+Ch1, P1, F1),
set_f2(Y, Yp, Ch2, F1, P2), set_yp(T+ 3*H/8, P2, F2),
set_f3(Y, Yp, Ch3, F1, F2, P3), set_yp(T + 12*H/13, P3, F3),
set_f4(Y, Yp, Ch4, F1, F2, F3, P4), set_yp(T + H, P4, F4),
set_f5(Y, Yp, Ch5, F1, F2, F3, F4, P5), set_yp(T + H/2, P5, F5),
% .. then the Y estimate ....
set_sum(Y, Yp, Ch6, F2, F3, F4, F5, S),
% .. and finally the error
set_err(Y, Yp, Abs, Rel, S, f(F2, F3, F4, F5), H, 0, Err, Ind).
set_f1([Y|Yr], [Yp|Ypr], Ch, [P|Pr]) :-
P = Y + Ch*Yp,
set_f1(Yr, Ypr, Ch, Pr).
set_f1([], [], _, []).
set_f2([Y|Yr], [Yp|Ypr], Ch, [F1|F1r], [P|Pr]) :-
P = Y + Ch*(Yp + 3*F1),
set_f2(Yr, Ypr, Ch, F1r, Pr).
set_f2([], [], _, [], []).
set_f3([Y|Yr], [Yp|Ypr], Ch, [F1|F1r], [F2|F2r], [P|Pr]) :-
P = Y + Ch*(1932*Yp + (7296*F2 - 7200*F1)),
set_f3(Yr, Ypr, Ch, F1r, F2r, Pr).
set_f3([], [], _, [], [], []).
set_f4([Y|Yr], [Yp|Ypr], Ch, [F1|F1r], [F2|F2r], [F3|F3r], [P|Pr]) :-
P = Y + Ch*((8341*Yp - 845*F3) + (29440*F2 - 32832*F1)),
set_f4(Yr, Ypr, Ch, F1r, F2r, F3r, Pr).
set_f4([], [], _, [], [], [], []).
set_f5([Y|Yr], [Yp|Ypr], Ch, [F1|F1r], [F2|F2r], [F3|F3r], [F4|F4r], [P|Pr]) :-
P = Y + Ch*((0-6080*Yp + (9295*F3 - 5643*F4)) + (41040*F1-28352*F2)),
set_f5(Yr, Ypr, Ch, F1r, F2r, F3r, F4r, Pr).
set_f5([], [], _, [], [], [], [], []).
set_sum([Y|Yr], [Yp|Ypr], Ch, [F2|F2r], [F3|F3r], [F4|F4r], [F5|F5r], [S|Sr]) :-
S = Y + Ch*((902880*Yp + (3855735*F3 - 1371249*F4)) + (3953664*F2 +
277020*F5)),
set_sum(Yr, Ypr, Ch, F2r, F3r, F4r, F5r, Sr).
set_sum([], [], _, [], [], [], [], []).
set_err([Y|Yr], Yp, Abs, Rel, [S|Sr], f(F2, F3, F4, F5), H, Oerr, Err, Ind) :-
Yabs = abs(Y),
Sabs = abs(S),
Et = Yabs + Sabs + Abs,
check_err(Et, [Y|Yr], Yp, [S|Sr], f(F2, F3, F4, F5),
Abs, Rel, H, Oerr, Err, Ind).
set_err([], [], _, Rel, [], _, H, Err, Habs*Err*(2/Rel)/752400, okay) :-
Habs = abs(H).
check_err(Et, Y, Yp, S, _, _, _, _, _, _, vanished) :-
Et <= 0.
check_err(Et, [Y|Yr], [Yp|Ypr], [S|Sr], f([F2|R2], [F3|R3], [F4|R4], [F5|R5]),
Abs, Rel, H, Oerr, Err, Ind) :-
Et > 0,
Ee = abs( (0-2090*Yp + (21970*F3 - 15048*F4)) + (22528*F2 - 27360*F5)),
Nerr = max(Oerr, Ee/Et),
set_err(Yr, Ypr, Abs, Rel, Sr, f(R2, R3, R4, R5), H, Nerr, Err, Ind).
% Low level stuff - primitives etc.
sign(V, 1) :-
V >= 0.
sign(V, 0-1) :-
V < 0.
% Magic numbers
remin(0.000000000001). % 1.0e-012 - from FM&M.
abmin(0.000000001). % 1.0e-009 - from FM&M.
max_func_eval(3000). % Also from FF&M.
eval(T, [Y1, Y2, Y3, Y4], [Y3, Y4, 0-Y1/R, 0-Y2/R]) :-
R1 = Y1*Y1 + Y2*Y2,
R = R1*pow(R1, 0.5)/((#p/4)*(#p/4)).
user_output(T, [Y1, Y2, Y3, Y4]) :-
printf("Point %10.5f : %10.5f %10.5f\n",[T,Y1,Y2]).
user_error(user(Y, T, Tend, Incr, Rer, Abs),
work(Yp, H, Nfe, Kop, Tout), max_func) :-
printf("Too hard for me - try something more accurate\n",[]).
user_error(user(Y, T, Tend, Incr, Rer, Abs),
work(Yp, H, Nfe, Kop, Tout), output_excess) :-
printf("Outputs too often - try another method\n",[]).
user_error(user(Y, T, Tend, Incr, Rer, Abs),
work(Yp, H, Nfe, Kop, Tout), step_small) :-
printf("Can''t achieve required accuracy\n",[]).
go:- Ecc = 0.25, solve([1-Ecc, 0, 0, (#p/4)*pow((1+Ecc)/(1-Ecc), 0.5)],
0, 3, 0.5, 0.000000001, 0).
% Output:
%
% Point 0.00000 : 0.75000 0.00000
% Point 0.50000 : 0.61977 0.47779
% Point 1.00000 : 0.29442 0.81218
% Point 1.50000 : -0.10518 0.95804
% Point 2.00000 : -0.49030 0.93987
% Point 2.50000 : -0.81394 0.79959
% Point 3.00000 : -1.05403 0.57571
%
% Iteration finished
% ------------------
% 439 derivative evaluations
?- printf("\n>>> Sample goal: go/0\n", []).