 
certainty(not(A), Cert) :- !, 
	certainty(A, Cert1), 
	complement(Cert1, Cert),
	cwrite(A,Cert).
certainty(true, Cert):- 
	highest_certainty(Cert), !. 
certainty((A, B), Cert):- !,
	findall( Cert1, 
	         ( amember(X, (A, B)), certainty(X, Cert1) ), 
		 CertList ),
	comb_fn_serial(CertList, Cert),
	cwrite((A,B), Cert).

certainty(A, Cert):- 
	findall(Cert3,  
	        (cclause(A, B, Cert1),
		 certainty(B, Cert2),
		 comb_fn_rule([Cert1, Cert2],Cert3)), 
		CertList),
	comb_fn_parallel(CertList, Cert),
	cwrite(A,Cert).

cassert(Clause,Certainty) :- 
	assert(Clause,Ref), 
	assert(cert(Ref,Certainty)). 

cclause(Head,Body,Certainty) :- 
	clause(Head,Body,Ref), 
	cert(Ref,Certainty).



serial_indep([A], B) :- !, A=B.
%serial_indep([ ], 1).
serial_indep([A | B], Cert) :- 
	serial_indep(B, BB), 
	Cert is A * BB.

parallel_indep([],1).
parallel_indep([A|B], Cert) :-
	parallel_indep(B, Cert1),
	Cert is (1-A) * Cert1.

%parallel_indep(Args, Cert) :- parallel_indep(Args, 1, Cert).
%parallel_indep([ ], Int, Cert) :- Cert is 1 - Int.
%parallel_indep([A | B], Int, Cert) :-
%	Int1 is Int * (1 - A),
%	parallel_indep(B, Int1, Cert).



serial_inc(Args, Cert) :- minimal(Args, Cert).
parallel_inc(Args, Cert) :- maximal(Args, Cert).

minimal([M],M).
minimal([A|B],M) :- 
	minimal(B,M1),
	(A > M1,!,M=M1;M=A).

maximal([M],M).
maximal([A|B],M) :- 
	minimal(B,M1),
	(A < M1,!,M=M1;M=A).


serial_maxdis(Args, Cert) :-
	length(Args, N),
	add(Args, Sum),
	Sum1 is Sum  -  N + 1,
	maximal([0,Sum1], Cert).
parallel_maxdis(Args, Cert) :- 
	add(Args, Sum), 
	minimal([1,Sum],Cert). 

add([ ],0).
add([A |  B], Sum):- add(B, Sum1), Sum is A + Sum1.

rule_simple([ClauseCert, BodyCert], C) :- C is ClauseCert * BodyCert.



comb_fn_serial(A,B) :-
	serial_method(M),
	(M=indep,!,serial_indep(A,B) ;
	             (M=inc,!,serial_inc(A,B) ; serial_maxdis(A,B) )).

comb_fn_parallel(A,B) :-
	parallel_method(M),
	(M=indep,!,parallel_indep(A,B) ;
	             (M=inc,!,parallel_inc(A,B) ; parallel_maxdis(A,B))).

comb_fn_rule(A,B) :- rule_simple(A,B).




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Utility
not(X) :- X,!,fail.
not(_).

amember(X,(X,_)).
amember(X,(_,Y)) :- !,amember(X,Y).
amember(X,X).



cwrite(A,C) :- nl, write('Certainty of '), write(A), write(' = '), write(C).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Database

:- dynamic malaria/0, dysentery/0, recently_in_third_world/0,recently_in_jungle/0.
:- dynamic recently_in_guatemala/0, high_fever/0, took_pills/0.
:- dynamic parallel_method/1, serial_method/1. 

:- dynamic cert/2, highest_certainty/1 .

assert_rules1 :- 
 	retractall(cert(_,_)),
	cassert((malaria :- high_fever,recently_in_jungle,not(took_pills)),0.85),
 	cassert((malaria :- dysentery), 0.3),
	cassert((dysentery :- recently_in_third_world), 0.6),
	cassert((recently_in_third_world :- recently_in_guatemala), 1),
	cassert((recently_in_jungle :- recently_in_guatemala), 0.9),
	cassert((recently_in_guatemala), 1),
	cassert((high_fever), 0.95),
	cassert((took_pills), 0.2).


test(Ser, Par,C) :-
	retractall(parallel_method(_)),
	retractall(serial_method(_)),
  	retractall(highest_certainty(_)),
	assert(parallel_method(Par)),
	assert(serial_method(Ser)),
	assert(highest_certainty(1)),
	nl,nl,write('Serial method: '), write(Ser), write('  Parallel method: '),
	write(Par),
 	certainty(malaria,C).


testall :-
	test(inc,inc,_),
	test( inc,dis ,_),
	test( inc, indep ,_),
	test(dis , inc,_),
	test(dis , dis,_),
	test(dis ,indep ,_),
	test(indep , inc,_),
	test(indep ,dis ,_),
	test(indep ,indep ,_).

complement(A,B) :- B is 1-A.
	




 



