% declaration to load rational solver
:- use_module(library(clpq)).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                       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 they will be 
                                                % ground 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
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 
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).
gp179b(X,Y) :- {X >= 0, X >= Y, Z = X - Y}, minimize( true, Z).
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

once(G) :- call(G),!.
erase(Key,Val) :-
	recorded(Key,Val,Ref),
	erase(Ref).
record(Key,Val) :-
	recorda(Key,Val,_).

minimize(G, E) :- 
                      get_min_value(G, E, M),
                      {E = M},
                      call(G).
  
get_min_value(G, E, _) :-
        apply_new_bound(E),
        once(G),
	minimize(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).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%











