% declaration to load rational solver
:- use_module(library(r)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 5.1 Simple Modelling %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% River crossing program p168.
river(W, S, R, P) :- T $= W/R, P $= S*T.
gp169a(P) :-
S $= 1, W $= 24, R $= 1.5, river(W, S, R, P).
gp169b(P) :-
S $= 1, W $= 24, 1 $<= R, R $<= 1.3, P $<= 20, river(W, S, R, P).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 5.2 Modelling Choice %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Simple family database p169.
father(jim,edward).
father(jim,maggy).
father(edward,peter).
father(edward,helen).
father(edward,kitty).
father(bill,fi).
mother(maggy,fi).
mother(fi,lillian).
age(maggy,A) :- A $= 63.
age(helen,A) :- A $= 37.
age(kitty,A) :- A $= 35.
age(fi,A) :- A $= 43.
age(lillian,A) :- A $= 22.
age(jim,A) :- A $= 85.
age(edward,A) :- A $= 60.
age(peter,A) :- A $= 33.
age(bill,A) :- A $= 65.
% database goals
gp170a(X) :- father(edward,X).
gp170b(X) :- mother(X,fi).
% family relationships program p170.
parent(X,Y):-father(X,Y).
parent(X,Y):-mother(X,Y).
sibling(X,Y):-parent(Z,X), parent(Z,Y), X \= Y. % safe since both X and Y will
% be fixed when reached.
cousin(X,Y):-parent(Z,X), sibling(Z,T), parent(T,Y).
older(X,Y) :- AX $>= AY, age(X,AX), age(Y,AY).
% goals on family relationships
gp170c(X) :- cousin(peter, X).
gp170d(Y) :- cousin(fi,Y), older(Y,fi).
% payoff for a call p173
buy_call_payoff(S, C, E, P) :- 0 $<= S, S $<= E / 100, P $= -C.
buy_call_payoff(S, C, E, P) :- S $>= E / 100, P $= 100 * S - E - C.
% payoff for a call option buting or selling p173
call_option(B,S,C,E,P) :-
0 $<= S, S $<= E / 100, P $= -C * B.
call_option(B,S,C,E,P) :-
S $>= E / 100, P $= (100 * S - E - C) * B.
% payoff for a put option buting or selling p173
put_option(B,S,C,E,P) :-
0 $<= S, S $<= E/100, P $= (E - 100 * S - C) * B.
put_option(B,S,C,E,P) :-
S $>= E / 100, P $= - C * B.
% goal for call option p173
gp173(P) :- call_option(1, 7, 200, 300, P).
% butterfly strike p174.
butterfly(S, P) :-
P $= P1 + 2*P2 + P3,
Buy $= 1, Sell $= -1,
call_option(Buy, S, 100, 500, P1),
call_option(Sell, S, 200, 300, P2),
call_option(Buy, S, 400, 100, P3).
% goal for butterfly strike
% the constraint output appears to be wrong here?
gp174(P,S) :-
P $>= 0, butterfly(S,P).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 5.3 Iteration %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% mortgage program p175.
mortgage(P,T,_I,_R,B) :- T $= 0, B $= P.
mortgage(P,T,I,R,B) :- T $>= 1,
NP $= P + P * I - R,
NT $= T - 1,
mortgage(NP,NT,I,R,B).
% reversed mortgage program p178.
rmortgage(P,T,I,R,B) :- T $>= 1,
NP $= P + P * I - R,
NT $= T - 1,
rmortgage(NP,NT,I,R,B).
rmortgage(P,T,_I,_R,B) :- T $= 0, B $= P.
% mortgage goals (be warned about the lack of simplification of answer!)
gp178(P) :- mortgage(P, 3, 10/100, 150, 0).
gp179(P,R,B) :- mortgage(P, 10, 10/100, R, B).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 5.4 Optimization %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% simple program for minimization p179.
p(X,_Y) :- X$=1.
p(_X,Y) :- Y$=1.
% minimization goals
gp179a(X,Y) :- X $>= 0, Y $>= 0, Z $= X + Y, minimize(p(X,Y), Z).
% this goal (gp179b) gives the wrong answer for a reason I dont understand
gp179b(X,Y) :- X $>= 0, X $>= Y, Z $= X - Y, minimize( true, Z).
% this goal (gp180) gives the wrong answer because a problem in rmin
gp180(S,P) :- L $= -P, minimize( butterfly(S,P), L).
% straddle program p180.
straddle(S, C, E, P) :- Buy = 1, C = C1 + C2, P = P1 + P2,
call_option(Buy, S, C1, E, P1),
put_option(Buy, S, C2, E, P2).
best_straddle(C, E, P) :- minimize(straddle(_S, C, E, P), -P).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 5.7 Practical Exercises %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Practical Exercise 5.7
flight(melbourne, sydney, 1000).
flight(melbourne, perth, 4000).
flight(perth, singapore, 5000).
flight(sydney, singapore, 8500).
flight(melbourne, cairns, 4000).
flight(sydney, cairns, 3200).
flight(cairns, singapore, 4900).
flight(singapore, london, 10000).
flight(perth, bahrain, 8000).
flight(bahrain, london, 6500).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%% stuff for minimization see chapter 9 %%%%%%%%%%%%%%%%%%%
% modified to use internal database
minimize(G, E) :-
get_min_value(G, E, M),
E $= M,
call(G).
get_min_value(G, E, _) :-
apply_new_bound(E),
once(G),
rmin(E), %% additional call to ensure ground result
record_better_bound(E),
fail.
get_min_value(_, _, M) :- erase(bestbound,M).
apply_new_bound(_).
apply_new_bound(E) :-
erase(currentbound,B),
record(bestbound,B),
E $< B,
apply_new_bound(E).
record_better_bound(E) :-
(erase(bestbound,_) -> true ; true),
record(currentbound,E).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%