
% rename them with prefix of utilities. -- to avoid redundant when MC-TopLog is applied to learning game strategies, where learning target is a mathematical function.
utilities_Add(X,Y,Z):- Z is X+Y.
utilities_minus(X,Y,Z):- Z is X-Y.



getBestSet0([Score-OneCandidate|EIsCandidates],BestScore,[]):-
	Score\==BestScore,!.
getBestSet0([BestScore-OneCandidate|EIsCandidates],BestScore,[BestScore-OneCandidate|BestCandidates]):-
	getBestSet0(EIsCandidates,BestScore,BestCandidates).


getBestSet([BestScore-OneCandidate|EIsCandidates],[BestScore-OneCandidate|BestCandidates]):-
	getBestSet0(EIsCandidates,BestScore,BestCandidates).




getBestSet0_removeScore([Score-OneCandidate|EIsCandidates],BestScore,[]):-
	Score\==BestScore,!.
getBestSet0_removeScore([BestScore-OneCandidate|EIsCandidates],BestScore,[OneCandidate|BestCandidates]):-
	getBestSet0_removeScore(EIsCandidates,BestScore,BestCandidates).

getBestSet_removeScore([BestScore-OneCandidate|EIsCandidates],[OneCandidate|BestCandidates]):-
	getBestSet0_removeScore(EIsCandidates,BestScore,BestCandidates).


getBestSet0_removeScoreEITI([Score-EITIs-OneCandidate|EIsCandidates],BestScore,[]):-
	Score\==BestScore,!.
getBestSet0_removeScoreEITI([BestScore-EITIs-OneCandidate|EIsCandidates],BestScore,[OneCandidate|BestCandidates]):-
	getBestSet0_removeScoreEITI(EIsCandidates,BestScore,BestCandidates).

getBestSet_removeScoreEITI([BestScore-EITIs-OneCandidate|EIsCandidates],[OneCandidate|BestCandidates]):-
	getBestSet0_removeScoreEITI(EIsCandidates,BestScore,BestCandidates).



forAll(P,Q):- \+ (P, \+Q).


/***************************** OUTPUT  THEORY****************************/
:- set_prolog_flag( toplevel_print_options, [max_depth(100)] ).


write_list_to_table([X]):- write(X). %,write('.').
write_list_to_table([X|List]):-
	write(X),write(' '),	%writeCla(X),nl,
	write_list_to_table(List).

% this is to write a clause? -- I can't remember
write_list([X]):- write(X). %,write('.').
write_list([X|List]):-
	write(X),write(','),	%writeCla(X),nl,
	write_list(List).

print_list([]).
print_list([X|List]):-
	portray_clause(X),	%writeCla(X),nl,
	print_list(List).

writeNumInColumn([]).
writeNumInColumn([X|List]):-
	write(X),nl,
	writeNumInColumn(List).


writeTheories([]).
writeTheories([X|List]):-
	write('**Another possible Hypothesis'),nl,
	writeTheory(X),nl,nl,nl,	%portray_clause(X),
	writeTheories(List).

writeTheory([]).
writeTheory([X|List]):-
	writeCla(X),nl,	%portray_clause(X),
	writeTheory(List).

writeCla([Head]):- !, write(Head),write('.').
writeCla([Head|Bodies]):-
	write(Head),write(':- '),
	writeBodies(Bodies).

writeBodies([End]):- !,write(End),write('.').
writeBodies([Body|Bodies]):-
	write(Body),write(','),
	writeBodies(Bodies).


showResults(TPos, TNeg, CPos, CNeg):-
  %format("~n~w~n", [Msg]),Msg, 
  TExamples is TPos+TNeg,  % Total examples
  %Observed
  TPredPos is CPos+CNeg,   % Total predicted positive examples
  PNegButPos is TPos-CPos, % Predicted negative but positive
  PNegAndNeg is TNeg-CNeg, % Predicted negative and is negative
  TPredNeg is TExamples-TPredPos, % Total predicted negative examples  
  % Expected
  ECPos is TPos*TPredPos/TExamples,
  ECNeg is TNeg*TPredPos/TExamples,
  EPNegButPos is TPos*TPredNeg/TExamples,
  EPNegAndNeg is TNeg*TPredNeg/TExamples,
  %Compute Chi2 statistic
  %chi2([CPos,CNeg,PNegButPos,PNegAndNeg], [ECPos, ECNeg,EPNegButPos, EPNegAndNeg], Chi2, Chi2Yates),
  %chi2_pvalue(Chi2Yates, PValueYates),
  %chi2_pvalue(Chi2, PValue),
  format("--------\\   /     Actual     |~n", []), % without [] the format/2 would fail
  format("Predicted\\ /Positive|Negative|Totals~n", []),
  format("----------|---------|--------|--------~n", []),
  format("  Positive|~t~g~20+|~t~g~9+|~t~g~9+~n", [CPos, CNeg, TPredPos]),
  %format("(expected)|~t~g~20+|~t~g~9+|~n", [ECPos, ECNeg]),
  format("----------|---------|--------|--------~n", []),
  format("  Negative|~t~g~20+|~t~g~9+|~t~g~9+~n", [PNegButPos, PNegAndNeg, TPredNeg]),
  %format("(expected)|~t~g~20+|~t~g~9+|~n", [EPNegButPos, EPNegAndNeg]),
  format("----------|---------|--------|--------~n", []),
  format("Totals    |~t~g~20+|~t~g~9+|~t~g~9+~2n", [TPos, TNeg, TExamples]),
  %format("Chi-square=~g p-value<=~w.~n Without Yates correction=~g p-value<=~w.~n", 
   %      [Chi2Yates, PValueYates, Chi2, PValue]),
  DefAcc is max(TPos, TNeg)*100/(TPos+TNeg),
  format("Default accuracy: ~4g%~n", [DefAcc]),
  ClassAcc is (CPos+(TNeg-CNeg))*100/(TPos+TNeg),
  format("Classifier accuracy: ~4g%~n", [ClassAcc]),
  Recall is CPos*100/(CPos+PNegButPos),
  format("Recall: ~4g% (i.e. % of correctly classified positive examples)~n", [Recall]),
  Precision is CPos*100/(CPos+CNeg),
  format("Precision: ~4g% (i.e. % of correctly predicted positive examples)~n", [Precision]).

%:- showResults(10,10,5,5).




/**************************** LIST ****************************/

% this allows binding goes back to the list. 
binding_membership(X,[X|Rest]).
binding_membership(X,[Y|Rest]):-
	binding_membership(X,Rest).
	
% last_ele(Seq,Pre,Last)
last_ele([X],[],X):-!.
last_ele([X|List],[X|Pre],Last):-
	last_ele(List,Pre,Last).


indexMapping(DataList,Index,Data):- nth(Index,DataList,Data).

sampling(SampleNum,All,Samples):-
	length(All,AllNum),
	randset(SampleNum,AllNum,SampleIndexes),
	maplist(fetch_oneSample(All),SampleIndexes,Samples).

fetch_oneSample(List,Index,Ele):-
	nth1(Index,List,Ele).


% find the Minimum Score, and seperate them those with this minimum score
%targetMin(List,MinSoFar,MinList,Rest):-
targetMin([],Min,Min,[],[]).
targetMin([{Score,UnCover,NewTSoFar,T}|List],MinSoFar,Min,NMinList,NRest):-	
	(Score>MinSoFar ->
		NMinSoFar=MinSoFar;
		NMinSoFar=Score
	),
	targetMin(List,NMinSoFar,Min,MinList,Rest),
	(Score==Min ->
		NMinList=[{Score,UnCover,NewTSoFar,T}|MinList],
		NRest=Rest;
		NMinList=MinList,
		NRest=[{Score,UnCover,NewTSoFar,T}|Rest]
	).	

minSet([],Min,Min,[]).
minSet([Score-TI|List],MinSoFar,Min,NMinList):-	
	(Score>MinSoFar ->
		NMinSoFar=MinSoFar;
		NMinSoFar=Score
	),
	minSet(List,NMinSoFar,Min,MinList),
	(Score==Min ->
		NMinList=[TI|MinList];
		NMinList=MinList
	).


sameList([Head|List]):-
	maplist(equal(Head),List).

equal(X,X).



bracket_to_list((X,Rest),[X|ListRest]):-
	bracket_to_list(Rest,ListRest).

bracket_to_list(X,[X]). % base case -- However, the running results show that it is actually fine without the base case. 


/**************************** CROSS PRODUCT ****************************/
% Set is represented by a LIST of LISTS

cross_product(SetA,SetB,SetCombined):-
	findall(C,
		(member(A,SetA),
		member(B,SetB),
		combine(A,B,C)),
		SetCombined).



combine(A,B,C):-
	is_list(A),is_list(B),!,
	append(A,B,C).
combine(A,B,[B|A]):-
	is_list(A),!.
combine(A,B,[A|B]):-
	is_list(B),!.
combine(A,B,[A,B]). % A and B are not lists so that they can't be combined by append



eleExtract([],[]).
eleExtract([X-_|PreList],[X|List]):-
	eleExtract(PreList,List).
	
attachHead(Ele,List,[Ele|List]).

powersets([],[[]]).
powersets([Ele|List],Powersets):-
	powersets(List,PrePowersets),
	maplist(attachHead(Ele),PrePowersets,ElePrePowersets), % each is appended with Ele
	append(PrePowersets,ElePrePowersets,Powersets).




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% numbersList(+StartNum, +EndNum, -List)
%
% Given:
%   StartNum: an integer
%   EndNum: an integer >=StartNum
%
% Returns
%   List: a list with the integers from [StartNum ..EndNum]
%
% E.g.
%  numbersList(1, 5, [1,2,3,4,5]).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

numbersList(N, N, [N]):-!.
numbersList(CurN, N, [CurN|R]):-
  CurN1 is CurN+1,
  numbersList(CurN1, N, R).


multiplyList([],1).
multiplyList([X|List],Result):-
	multiplyList(List,PreResult),
	Result is X*PreResult.


sumList([],0).
sumList([X|List],Result):-
	sumList(List,PreResult),
	Result is X+PreResult.


permutateList(X,Y):-
	length(X,K),
	randseq(K,K,Indexes), % biggest K is accessible
	fetchbyIndex(X,Indexes,Y).

fetchbyIndex(X,Indexes,Y):-
	maplist(fetch(X),Indexes,Y).

fetch(List,N,Elem):- nth(N, List, Elem).



/*------------------ Find maximum and record the related record------------------*/

	
max([],Finalmax,Finalmax).
max([Ele|List],MaxSoFar,FinalMax):-
	(Ele>MaxSoFar ->
		NewMaxSoFar=Ele;
		NewMaxSoFar=MaxSoFar
	),
	max(List,NewMaxSoFar,FinalMax).

min([],Finalmin,Finalmin).
min([Ele|List],MinSoFar,Finalmin):-
	(Ele<minSoFar ->
		NewminSoFar=Ele;
		NewminSoFar=minSoFar
	),
	min(List,NewminSoFar,Finalmin).


/* haven't been tested
findMaxRecord([],-1000000).
findMaxRecord([Score-Record|Records],MaxScore-MaxRecord):-
	findMaxRecord(Records,PreMaxScore-PreMaxRecord),
	(Score > PreMaxScore ->
		MaxScore=Score, MaxRecord=Record;
		MaxScore=PreMaxScore, MaxRecord=PreMaxRecord
	).
*/



update_assertedNum_addOne(Atom):-
	Atom=.. [Predicate,Num],
	retract(Atom),
	NewNum is Num+1,
	NewAtom=.. [Predicate,NewNum],
	asserta(NewAtom).


/******************************SKOLEMIZATION***************************/
skoCla(Cla):-
	numbervars(Cla,0,_).

testSko(Cla):-
	Cla=[path(s(X),Y),edge(X,Z),path(Z,Y)],
	skoCla(Cla).






/*************** REDUNDANCY CHECK ********************/
testRedu:-
	%TSoFar=[[ancestor(A,C),parent(A,B),ancestor(B,C)],[ancestor(A,B),parent(A,B)],[parent(ffabc,fabc)]],	
		%[[odd(s(s(s(A))))]], %[[even(s(s(B))),even(B)],[even(0)]],
	%addT(TSoFar),	

	%T= [[odd(s(s(A))),odd1(A)],[odd(s(B)),even1(B)],[even(s(C)),odd1(C)],[odd(s(0))]],
	%[[ancestor(A,C),parent(A,B),ancestor(B,C)],[ancestor(A,B),parent(A,B)],[parent(fabc,c)]],	

	asserta((p(X):-q(X)),Ref),
	checkTheoryRedundant(T,PreRedT,PreRemT),
	removeRedundant(T,TRefs,NonReT,NonReTRefs), write(NonReT),nl,
	removeT(NonReTRefs). 


testRef:-
	T=[[p(a)],[q(b)]],
	addT(T,Refs),
	p(Y),q(Z), write(Y),write(Z),nl,
	removeT(Refs),
	((p(N),q(M)) ->
		write('still there');
		write('successfully removed')
	).

/*
% removeRedundant(T,TRefs,NonReT,NonReTRefs)--you can combine {H,Ref}, but it require all the other to cater for this format while Ref is useless else where.
removeRedundant([],[],[],[]).
removeRedundant([H|Hs],[HRef|HsRefs],NonReHs,NonReHsRefs):-
	erase(HRef),
	copy_term(H,H1),
	redundantCheck(H1,Sign),Sign==redundant,!,
	removeRedundant(Hs,HsRefs,NonReHs,NonReHsRefs).
removeRedundant([H|Hs],[HRef|HsRefs],[H|NonReHs],[NewHRef|NonReHsRefs]):-
	length(H,K),
	assertaH(K,H,NewHRef), % assertzH(K,H,NewHRef) with ref it doesn't make difference here.
	removeRedundant(Hs,HsRefs,NonReHs,NonReHsRefs).
*/

% Ref-ClaIndex
removeRedundant([],[]).
removeRedundant([Ref-ClaI|T],NonReT):-
	erase(Ref),
	claInterpreter(ClaI,Cla),
	copy_term(Cla,Cla1),
	redundantCheck(Cla1,Sign),Sign==redundant,!,
	removeRedundant(T,NonReT).
removeRedundant([Ref-ClaI|T],[NewRef-ClaI|NonReT]):-
	claInterpreter(ClaI,Cla),
	length(Cla,K),
	assertaH(K,Cla,NewRef), % assertzH(K,H,NewHRef) with ref it doesn't make difference here.
	removeRedundant(T,NonReT).

% assume the input of Cla is a denial
reduce_clause(Cla,NonRedundantCla):-
	turn_into_var(Cla,VarCla),
	remove_redundantLit(VarCla,Cla,[],NonRedundantCla).

remove_redundantLit(VarCla,[],NonRedundantCla,NonRedundantCla).
remove_redundantLit(VarCla,[ReducingLit|Post],Pre,NonRedundantCla):-
	append(Pre,Post,ReducingCla),
	(derive_empty(ReducingCla,VarCla)->
		remove_redundantLit(VarCla,Post,Pre,NonRedundantCla); % redundant, so not to put it back in Pre
		remove_redundantLit(VarCla,Post,[ReducingLit|Pre],NonRedundantCla)
	).

% see whether empty could be derived where each goal could be proved
derive_empty(ReducingCla,VarCla0):-
	copy_term(VarCla0,VarCla),
	check_membership(ReducingCla,VarCla).	%maplist(check_membership(ReducingCla),VarCla) -- not to use maplist because I want to keep the binding among clauses

check_membership(ReducingCla,[]).
check_membership(ReducingCla,[VarLit|VarCla]):-
	member(VarLit,ReducingCla),
	check_membership(ReducingCla,VarCla).
	
	
:- dynamic var_cla/1.

turn_into_var(Cla,VarCla):-
	maplist(variablise_arguments,Cla,VarCla0),
	tell('rewrite_clause.pl'), 	% get rid of 'S' by writing to the file and then consult it
	write(var_cla(VarCla0)),write('.'),
	told,
	consult(rewrite_clause),
	var_cla(VarCla), 
	retract(var_cla(VarCla)). 

variablise_arguments(Lit,VarLit):-
	Lit=.. [Predicate|Args],
	maplist(variablise_oneArgument,Args,VarArgs),
	VarLit=.. [Predicate|VarArgs].

% only rewrite
variablise_oneArgument(Constant,Var):-
	atom_chars(Constant,[s|Rest]),!,
	atom_chars(Var,['S'|Rest]).
variablise_oneArgument(Constant,Constant).

% % test [ruleL(s,a,s2),ruleL(s2,a,s),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)]
% test [ruleL(s,b,s2),ruleL(s2,b,s),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)]
% test [ruleL(s,b,s1),ruleR(s1,s2,b),ruleR(s2,s,b),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)]
rc1:- Denial= [ruleL(s,b,s2),ruleL(s2,b,s),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)],
	%turn_into_var(Denial,VarCla),write(VarCla),nl.
	reduce_clause(Denial,NonRedundantCla),
	reverse(NonRedundantCla,NonRedundantCla1),
	write(NonRedundantCla1),nl.

rc2:- Denial= [ruleL(s,a,s2),ruleL(s2,a,s),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)],
	%turn_into_var(Denial,VarCla),write(VarCla),nl.
	reduce_clause(Denial,NonRedundantCla),
	reverse(NonRedundantCla,NonRedundantCla1),
	write(NonRedundantCla1),nl.

rc3:- Denial=[ruleL(s,b,s1),ruleR(s1,s2,b),ruleR(s2,s,b),ruleL(s,b,s),ruleR(s,s,b),ruleL(s,b,s),rule0(s)],
	%turn_into_var(Denial,VarCla),write(VarCla),nl.
	reduce_clause(Denial,NonRedundantCla),
	reverse(NonRedundantCla,NonRedundantCla1),
	write(NonRedundantCla1),nl.


rc4:- Denial=[rule0(s),ruleR(s3,s,b),ruleL(s,a,s3),ruleL(s1,a,s),ruleR(s,s1,b)],
	%turn_into_var(Denial,VarCla),write(VarCla),nl.
	reduce_clause(Denial,NonRedundantCla),
	reverse(NonRedundantCla,NonRedundantCla1),
	write(NonRedundantCla1),nl.





% not able to handle the more general case -> s:- np,noun
	
%checkTheoryRedundant(TSoFar,RedundantTSoFar,RemainedTSoFar)
checkTheoryRedundant([],[],[]).
checkTheoryRedundant([Ref-ClaI|T],RedT,RemT):-
	checkTheoryRedundant(T,PreRedT,PreRemT),
	write('^^^^'),write(Ref-ClaI),%listing,nl,
	erase(Ref), % take out
	write('^^^^'),%listing,nl,
	claInterpreter(ClaI,Cla0),copy_term(Cla0,Cla),
	redundantCheck(Cla,Sign),
	length(Cla0,K),
	assertaH(K,Cla0,NewRef), % put back
	(Sign==redundant->
		RedT=[NewRef-ClaI|PreRedT],RemT=PreRemT;
		RedT=PreRedT,RemT=[NewRef-ClaI|PreRemT]
	).

% this check for a single clause
redundantCheck([Head|Bodies],Sign):-
	skoCla([Head|Bodies]),%write('trace*** after skolemise'), write([Head|Bodies]),nl,%listing,nl,
	addFacts(Bodies,Refs),
	set(evDepth,EvDepth),
	(depth_bound_call(user:Head, EvDepth)-> 	% in case of path1:-path. path:- path1.
		Sign=redundant;
		Sign=non_redundant
	),
	removeT(Refs).%,write(Refs),write('trace*** check removing facts'),%listing.



/*************** ASSERT AND RETRACT ********************/
% remove previous added, and its tranformed
% diff between Facts and Cla - if it is facts, not need to transfrom--don't add two version, otherwise redundant -- more redundant H.

removeLearned([]).
removeLearned([RefCla-ClaI|RefT]):-
	removeLearned(RefT), write(RefCla-ClaI),nl,
	erase(RefCla), 
	(ClaI=[OneFact]-> % no transformed version to remove
		Foo=1;
		addedTCla(ClaI,RefTCla),
		erase(RefTCla),
		retract(addedTCla(ClaI,RefTCla)) % any chance to be added again? it will be avoided by knownClaI
	).


% can't simply call addTI, because the need to access the Cla to transform	
addLearned([],RefT,RefT).
addLearned([ClaI|TI],PreT,[Ref-ClaI|T]):-
	addLearned(TI,PreT,T),
	claInterpreter(ClaI,Cla),%nl,write(ClaI),write(' interpreted as '), write(Cla),nl,
	length(Cla,K),
	assertaH(K,Cla,Ref),

	(ClaI=[OneFact]-> % no transformed version to remove
		Foo=1;
	% add associated ClaI, and transformed version
	asserta(knownBI(ClaI)),
	trTransform(Cla,TCla),
	assertaH(K,TCla,RefTCla),
	asserta(addedTCla(ClaI,RefTCla))
	). 


% interpret each Clause in TI, and assert
% append newly added one with 
% addTI(Adding,Added,NewAdded)
/*
addTI([],T,T).
addTI([ClaI|TI],PreT,T):-
	claInterpreter(ClaI,Cla),
	length(Cla,K),
	assertaH(K,Cla,Ref),
	addTI(TI,[Ref-ClaI|PreT],T).
*/

/*
addTI([],T,T).
addTI([ClaI|TI],PreT,[Ref-ClaI|T]):-
	addTI(TI,PreT,T),
	claInterpreter(ClaI,Cla),%nl,write(ClaI),write(' interpreted as '), write(Cla),nl,
	length(Cla,K),
	assertzH(K,Cla,Ref).
%Replaced by addLearned
*/
addTI([],T,T):-!.
addTI([ClaI|TI],PreT,RefT):-
	addTI(TI,PreT,PreRefT),!,
	claInterpreter(ClaI,Cla),%nl,write(ClaI),write(' interpreted as '), write(Cla),nl,
	(Cla\==[]->
		length(Cla,K),
		assertzH(K,Cla,Ref),
		RefT=[Ref-ClaI|PreRefT];
		RefT=PreRefT
	).


	
	%addTI(TSoFar,[],RefTSoFar),
	%addTI(T,RefTSoFar,RefAllT),%write('???Problem here'),%write(RefAllT),nl,

% why 3 parameters? two for Reference. 
% a list to be added, previous depends on the later one. 
% noot only check redundancy, but also check consistentcy. 
% maplist(addClaCheck,Clas,NewClas)
% why not forward, but backward? 
% better to seperate this from adding -- otherwise, if inconsistence, you need to remove those already asserted. 

% addTI_redundencyCheck(T,TSoFar,RefTSoFar,RefAllT),
addTI_redundencyCheck([],TSoFar,T,T).
addTI_redundencyCheck([ClaI|TI],TSoFar,PreT,RefT):-
	reactionStateContradictionCheck(ClaI,TSoFar), % if they are not the same as before, then fail here --> should have an option to skipp 
	claInterpreter(ClaI,Cla),%nl,write(ClaI),write(' interpreted as '), write(Cla),nl,
	(Cla\==[]->
		length(Cla,K),
		assertzH(K,Cla,Ref),
		RefT=[Ref-ClaI|PreRefT];
		RefT=PreRefT
	),
	addTI_redundencyCheck(TI,TSoFar,PreT,PreRefT).




removeRefT([],[]).
removeRefT([Ref-ClaI|RefT],[ClaI|TI]):-
	removeRefT(RefT,TI),
	erase(Ref).

%--------------Only Ref-------------------
addT(Clas,Refs):- addFacts(Clas,Refs).

/*addT([],[]).
addT([H|T],[Ref|Refs]):-
	length(H,K),
	assertzH(K,H,Ref),
	addT(T,Refs).*/
removeT([]).
removeT([Ref|Refs]):-
	removeT(Refs),
	erase(Ref).

%--------------FACTS (no need to compute length)-------------------
addFacts([],[]).
addFacts([F1|Facts],[Ref|Refs]):-
	asserta(F1,Ref),
	addFacts(Facts,Refs).


assertaH(1,[Fact],Ref):-
	asserta(Fact,Ref).
assertaH(2,[Head,Body],Ref):-
	asserta((Head:-Body),Ref).
assertaH(3,[Head,Body1,Body2],Ref):-
	asserta((Head:-Body1,Body2),Ref).
assertaH(4,[Head,Body1,Body2,Body3],Ref):-
	asserta((Head:-Body1,Body2,Body3),Ref).
assertaH(5,[Head,Body1,Body2,Body3,Body4],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4),Ref).
assertaH(6,[Head,Body1,Body2,Body3,Body4,Body5],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4,Body5),Ref).
assertaH(7,[Head,Body1,Body2,Body3,Body4,Body5,Body6],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4,Body5,Body6),Ref).
assertaH(8,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7),Ref).
assertaH(9,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8),Ref).
assertaH(10,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8,Body9],Ref):-
	asserta((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8,Body9),Ref).



assertzH(1,[Fact],Ref):-
	assertz(Fact,Ref).
assertzH(2,[Head,Body],Ref):-
	assertz((Head:-Body),Ref).
assertzH(3,[Head,Body1,Body2],Ref):-
	assertz((Head:-Body1,Body2),Ref).
assertzH(4,[Head,Body1,Body2,Body3],Ref):-
	assertz((Head:-Body1,Body2,Body3),Ref).
assertzH(5,[Head,Body1,Body2,Body3,Body4],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4),Ref).
assertzH(6,[Head,Body1,Body2,Body3,Body4,Body5],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4,Body5),Ref).
assertzH(7,[Head,Body1,Body2,Body3,Body4,Body5,Body6],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4,Body5,Body6),Ref).
assertzH(8,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7),Ref).
assertzH(9,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8),Ref).
assertzH(10,[Head,Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8,Body9],Ref):-
	assertz((Head:-Body1,Body2,Body3,Body4,Body5,Body6,Body7,Body8,Body9),Ref).


letter_to_number('1',1).
letter_to_number('2',2).
letter_to_number('3',3).
letter_to_number('4',4).
letter_to_number('5',5).
letter_to_number('6',6).
letter_to_number('7',7).
letter_to_number('8',8).
letter_to_number('9',9).
letter_to_number('10',10).
letter_to_number('11',11).
letter_to_number('12',12).
letter_to_number('13',13).
letter_to_number('14',14).
letter_to_number('15',15).
letter_to_number('16',16).
letter_to_number('17',17).
letter_to_number('18',18).
letter_to_number('19',19).
letter_to_number('20',20).
letter_to_number('21',21).
letter_to_number('22',22).
letter_to_number('23',23).
letter_to_number('24',24).
letter_to_number('25',25).
letter_to_number('26',26).
letter_to_number('27',27).
letter_to_number('28',28).
letter_to_number('29',29).
letter_to_number('30',30).
letter_to_number('31',31).
letter_to_number('32',32).
letter_to_number('33',33).
letter_to_number('34',34).
letter_to_number('35',35).
letter_to_number('36',36).
letter_to_number('37',37).
letter_to_number('38',38).
letter_to_number('39',39).
letter_to_number('40',40).
letter_to_number('41',41).
letter_to_number('42',42).
letter_to_number('43',43).
letter_to_number('44',44).
letter_to_number('45',45).
letter_to_number('46',46).
letter_to_number('47',47).
letter_to_number('48',48).
letter_to_number('49',49).
letter_to_number('50',50).

/*********************** PIANO NUMBER MAPPING ************************/
% numMap(integer,pianoNum)
numMap(0,0):- !. % to avoid -1,-2...
numMap(D,s(P)):-
	D > 0,
	D0 is D-1,
	numMap(D0,P).

numMap_inverse(0,0).
numMap_inverse(s(PeanoNum),Num):-
	numMap_inverse(PeanoNum,PreNum),
	Num is PreNum+1.

antiInstantiate(0,X).
antiInstantiate(s(GroundPeanoIndex),s(NonGroundPeanoIndex)):-
	antiInstantiate(GroundPeanoIndex,NonGroundPeanoIndex).

/*********************** STATISTICS ************************/
% multiply each element, then sum them together

average(NumList,Average):-
	sum(NumList,Sum),
	length(NumList,K),
	Average is Sum/K.

sum([],0).
sum([X|List],Sum):-
	sum(List,PreSum),
	Sum is PreSum+X.
	
% Sum=(X-x)(X-x), 
% STD=sqrt(Sum)
std(DataList,Mean,STD):-
	deviation(DataList,Mean,Sum0),
	length(DataList,K),
	Sum is Sum0/K,
	STD is sqrt(Sum).

deviation([],_,0).
deviation([X|Rest],XMean,Sum):-
	deviation(Rest,XMean,NSum),
	Diff is (X-XMean)*(X-XMean),
	Sum is NSum+Diff.


%%%%%%%%%%%%%   Weighted
mean([],0).
mean([{Weight,X}|Rest],Mean):-
	mean(Rest,MeanSoFar),
	Mean is (MeanSoFar+Weight*X).

% Sum=weight*(X-x)(X-x), 
% STD=sqrt(Sum)
weightStd(DataList,Mean,STD):-
	weightDeviation(DataList,Mean,Sum),
	STD is sqrt(Sum).



% Sum=weight*(X-x)(X-x)
weightDeviation([],_,0).
weightDeviation([{Weight,X}|Rest],XMean,Sum):-
	weightDeviation(Rest,XMean,NSum),
	Diff is Weight*(X-XMean)*(X-XMean),
	Sum is NSum+Diff.

% '0.54601' to 0.54601
% whether -- it depends on the point
% what about number e -- forget about it for the moment



lettersToNum(NumLetters,Num):-
	name(NumLetters,NumCodes),
	(NumCodes=[45|Rest]->
		negativeNum(NumCodes,Num);
		(append(IntegersNumCodes,[101,45|BeiShu0],NumCodes)->
			normalLettersToNum(IntegersNumCodes,IntegerNum),
			codeToNum(BeiShu0,BeiShu),
			Num is IntegerNum*(0.1^BeiShu);
			normalLettersToNum(NumCodes,Num)
		)
	).

negativeNum([NegativeSign|NumCodes],NegNum):-
	normalLettersToNum(NumCodes,Num),
	NegNum is -Num.

normalLettersToNum(NumCodes,Num):-
	sepPointOne(NumCodes,Integers,Points),
	integerTranslate(Integers,BeiShu,IntegerNum),
	pointsTranslate(Points,0.1,PointNum),
	Num is IntegerNum+PointNum.


integerTranslate([I],1,INum):- codeToNum(I,INum).
integerTranslate([I|Integers],BeiShu,IntegerNum):-
	integerTranslate(Integers,PreBeiShu,PreIntegerNum),
	BeiShu is 10*PreBeiShu,
	codeToNum(I,INum),
	IntegerNum is PreIntegerNum+INum*BeiShu.


pointsTranslate([],BeiShu,0).
pointsTranslate([I|Integers],BeiShu,IntegerNum):-
	PreBeiShu is BeiShu*0.1,
	pointsTranslate(Integers,PreBeiShu,PreIntegerNum),
	codeToNum(I,INum),
	IntegerNum is PreIntegerNum+INum*BeiShu.


sepPointOne([46|Points],[],Points).
sepPointOne([OneCode|NumCodes],[OneCode|Integers],Points):-
	sepPointOne(NumCodes,Integers,Points).
	
codeToNum(I,INum):-
	INum is I-48.



groupSameValue([],[]).
groupSameValue([Score-Candidate|Rest],GroupResult):-
	groupSameValue(Rest,PreGroupResult),
	(append(Pre,[Score-SameScoreCandidates|Post],PreGroupResult)->
		 append(Pre,[Score-[Candidate|SameScoreCandidates]|Post],GroupResult);
		 GroupResult=[Score-[Candidate]|PreGroupResult]
	).

/*********************** editing the input files ************************/
add_arguments_to_literal(AddingArgs,Literal,ArgumentedLiteral):-
	Literal=.. [Predicate|Args],
	(Predicate='$' ->
		Args=[Term],
		Term=.. [RealPredicate|Args0],
		atomic_concat([Predicate,RealPredicate],PrefixPredicate),
		append(AddingArgs,Args0,NewArgs),
		ArgumentedLiteral=.. [PrefixPredicate|NewArgs];
		append(AddingArgs,Args,NewArgs),
		ArgumentedLiteral=.. [Predicate|NewArgs]
	).
