% Similar to genT.pl, the programs in this file generate hypotheses for training examples, however, rather than using covering, each example is used as a seed, and then crossproduct



/*-------No Cross Product (simply go through each one) -------*/
% if put them together, then it becomes a big program. 

%OneTs=[[[enzymeState-]],[enzymeState-],[enzymeState-]]],
% test product


tno:- %numbersList(1,10,EIs), %
	%tell('tomato_crossProduct.txt'),
	PosEIs= [1,4,5,7,10,11], %[1,3,4,5,6,7,10,11,12],	%[1,3,4,5,6,7,8,9,10,11],[1,4,5,7,9]
	learnAll(PosEIs,FinalT),
	write('Final suggested hypothesis is '),write(FinalT),

/*	genAll(EIs,Ts,TotalNum),write('Total is '), write(TotalNum),nl,
	Ts=[OneTs|RestTs],
	n1(OneTs,[],[],InitialCountedResult),
	setsCrossProduct(RestTs,InitialCountedResult,AllH),	
	%sorteach(AllH,SortedHs),
	allScoring(AllH,AllScoredH),
	nl,sort(AllScoredH,SortedAllH),write('OK'),nl,print_list(SortedAllH),
	length(AllH,K), write('After'),write(K),
*/
	nl. %told.


norlate:-
	AspartateBioSynthesisPathway=[91,92,93,103],
	learnAll(AspartateBioSynthesisPathway,FinalT).

norlateTCA:-
	TCA_cycle=[91,92,105,108].

cnrMid:-
	TCA_cycle=[47,48,61,64],
	learnAll(TCA_cycle,FinalT).






learnAll(EIs,FinalTI):- 
	tell('candidateH_genAll.pl'),
	genAll_signedTIs(EIs,EITIs,TotalNum),
	told,
	consult('candidateH_genAll.pl'),
	%allSetsCrossProduct(EIsTs,[[]],Result),
	crossProductlyCombine_and_check(EITIs,[[]],Result),

	tell('tomato_AspartateCandidates.txt'),
	print_list(Result),
	length(Result,RNum),write('Total is '), write({TotalNum,RNum}),nl,told.



/*
	Ts=[OneTs|RestTs],
	n1(OneTs,[],[],InitialCountedResult),
	setsCrossProduct(RestTs,InitialCountedResult,AllH),
	%sorteach(AllH,SortedHs),
	allScoring(AllH,AllScoredH),
	nl,sort(AllScoredH,SortedAllH),nl,print_list(SortedAllH),
	length(AllH,K), write('After'),write(K),
	SortedAllH=[Score-FinalT0|_],
	nl,write(Score-FinalT0),nl,
	maplist(extractECNumState,FinalT0,FinalTI),
	nl.
*/


extractECNumState(Sign-Counter-{EC_Number,State},[enzyme_state-{EC_Number,State}]).


sorteach([],[]).
sorteach([Ele|Eles],[SortedEle|SortedEles]):-
	sorteach(Eles,SortedEles),
	sort(Ele,SortedEle).
	



% twoSetsProduct()
% cross product is simply recursively multiply two sets.

s:-
	T0=[[]],
	EsTs=[
		[	[[e1t1c1],[e1t1c2]], [[e1t2c2]]	], % one e1
		[ 	[[e2t1c1],[e2t1c2]], [[e2t2c2]]	]		% one e2
	],
	allSetsCrossProduct(EsTs,T0,Result),
	print_list(Result).

%allSetsCrossProduct([[[[e1t1c1],[e1t1c2]], [[e1t2c2]]], [[[e2t1c1],[e2t1c2]],[[e2t2c2]]]],[[]],Result).

allSetsCrossProduct([],Result,Result).
allSetsCrossProduct([Set|RestSets],ResultSoFar,Result):-
	twoSetsProduct(Set,ResultSoFar,[],NewResultSoFar),
	allSetsCrossProduct(RestSets,NewResultSoFar,Result).


twoSetsProduct([],Set2,Result,Result).
twoSetsProduct([Ele1|Set1],Set2,ResultSoFar,Result):-
	maplist(combine(Ele1),Set2,NewEles),
	append(NewEles,ResultSoFar,NewResultSoFar),
	twoSetsProduct(Set1,Set2,NewResultSoFar,Result).



combine(Ele1,Ele2,NewEle):-
	append(Ele1,Ele2,NewEle).
%,!.
%combine(Ele1,Ele2,NewEle):- % Ele2 is a list, while Ele1 is not.
%	append([Ele1],Ele2,NewEle),!.
%combine(Ele1,Ele2,[Ele1,Ele2]).

	
% the input is a list of EI-TIs
crossProductlyCombine_and_check([],FinalHs,FinalHs).
crossProductlyCombine_and_check([EI-TIs|EIs],Hs_sofar,FinalHs):-
	findall(NewH_sofar,
	( member(TI,TIs), 
	candidateH0(EI,TI,OneEIT),
		member(H_sofar,Hs_sofar),combineCheck(OneEIT,H_sofar,NewH_sofar)
	),
	NewHs_sofar),
	crossProductlyCombine_and_check(EIs,NewHs_sofar,FinalHs).
	

myAppend([],List2,List2).
myAppend([Ele|List1],List2,[Ele|Result]):-
	myAppend(List1,List2,Result).	

combineCheck([],H,H).
combineCheck([OneEIFact|OneEIT],H_sofar,H):-
	insertFact_to_Hsofar_noRedundant(OneEIFact,H_sofar,NewH_sofar),
	combineCheck(OneEIT,NewH_sofar,H).




% add one clause to T
insertFact_to_Hsofar_noRedundant(OneEIFact,H_sofar,H_sofar):-	
	OneEIFact=[rs-{ReactionID,LimitingType,State,Time}], 
	member([rs-{ReactionID,LimitingType2,State2,Time}],H_sofar),!, % get it
	State2==State.

/*	((State2==State)-> %, LimitingType2==LimitingType
			Foo=1;
			write(OneEIFact), write('to be Added to'),write(H_sofar),fail
	).		% require them the same; not to added -- ensure no redundant
*/

insertFact_to_Hsofar_noRedundant(OneEIFact,H_sofar,[OneEIFact|H_sofar]).





/* Even simple by using forAll(P,Q):- \+ (P, \+Q).
numbersList(1,10,PosEIs),
	forAll(member(EI,PosEIs),g(EI,T)),	*/


as:-
	tell('H_for_ALLexs.txt'),
        statistics(cputime,[Total1,Previous]),

	set(depthLimit,DepthLimit),
	%numbersList(1,5,EIs),
	EIs=[1,2,3,5,7,9,10],
	continueEs(DepthLimit,EIs,RecordAll),
	
	length(RecordAll,K),
	nl,write('The total number of hypotheses is'), write(K),nl,
	
	statistics(cputime,[Total2,Now]),
	TimeTaken is Now-Previous,
	write('Total Time Taken is '), %write(TimeTaken),
	told.




continueEs(DepthLimit,EIs,RecordAll):-	
	findall(Tr,
		(
		 oneByone(DepthLimit,EIs,[],Tr),%write('OneTr'),write(Tr),nl,write('PreRemove'),listing,removeRefT(Tr),write('AfterRemove'),listing,
			%consistentCheck(Tr,FinalT),
		 nl
		%tInterpreter(Tr,T)
		%,write('*** One theory'),nl,
		%write(Tr),nl,	% track the ID of clauses in B
		%print_list(T),nl,nl
	 
		),
		RecordAll).


oneByone(_,[],Tr,Tr).
oneByone(DepthLimit,[EI|EIs],TrSoFar,Tr):-
	continueGenEx(DepthLimit,EI,TrSoFar,NewTrSoFar),
	%noRedundantAdd(OneTr,TrSoFar,NewTrSoFar), % check integrity constraint; 
	oneByone(DepthLimit,EIs,NewTrSoFar,Tr).


%1. add. Ref is included in Tr
noRedundantAdd([],TrSoFar,TrSoFar).
noRedundantAdd([ClauseIndex|OneTr],TrSoFar,NewTrSoFar):-
	hInterpreter(ClauseIndex,Clause),
	%(partialMem(ClauseIndex,TrSoFar,Sign),!;
	redundantCheck(Clause,Sign)
	,%),
	(Sign==redundant->
		write('Redundant HERE'),%listing,nl,
		UpdatedTrSoFar=TrSoFar;
		length(Clause,K),assertaH(K,Clause,Ref),
		UpdatedTrSoFar=[Ref-ClauseIndex|TrSoFar]
	),
	noRedundantAdd(OneTr,UpdatedTrSoFar,NewTrSoFar).

partialMem(ClauseIndex,[],nonRedundant).
partialMem(ClauseIndex,[Ref-ClauseIndex|TrSoFar],redundant):- !.
partialMem(ClauseIndex,[Ref-ClauseIndex2|TrSoFar],Sign):-
		partialMem(ClauseIndex,TrSoFar,Sign).



%2. check, after adding one. intergrety, if violate, then cancel and stop; while if not, then continue



% if violate the integrity constraint, then removeT(Ref),fail. (force it to fail)




/*------- Cross Product-------*/
setsCrossProduct([],Result,Result).
setsCrossProduct([Set|RestSets],ResultSoFar,Result):-
	nn(Set,ResultSoFar,[],NewResultSoFar),
	setsCrossProduct(RestSets,NewResultSoFar,Result).

%nn(SetA,[],[],CountedResult):-!,n1(SetA,[],[],CountedResult). 
nn(SetA,[],Result,Result).
nn(SetA,[Ele|SetB],ResultSoFar,Result):-
	n1(SetA,Ele,ResultSoFar,NewResultSoFar),
	nn(SetA,SetB,NewResultSoFar,Result).
	

n1([],_,Result,Result).
n1([Ele1|Set],Ele0,ResultSoFar,Result):-
	% It can be simple append(Ele1,Ele0,NewEle), but here we discard those inconsistent and count those repeated
	(add_to_countedResult(Ele1,Ele0,NewEle)-> 
		NewSoFar=[NewEle|ResultSoFar];
		NewSoFar=ResultSoFar
	),
	n1(Set,Ele0,NewSoFar,Result).


add_to_countedResult([],CountedResult,CountedResult).
add_to_countedResult([Fact|T],CountedResultSoFar,CountedResult):-
	insertOneFact(Fact,CountedResultSoFar,NewSoFar), 
	add_to_countedResult(T,NewSoFar,CountedResult).
	

insertOneFact(Fact,CountedResultSoFar,NewSoFar):-
	Fact=[enzyme_state-{Sign,EC_Number,State}],
	append(Pre,[Sign-Counter-{EC_Number,StateStored}|Post],CountedResultSoFar),!,
	State==StateStored,
	NewCounter is Counter+1,
	append(Pre,Post,NewSoFar0),
	NewSoFar=[Sign-NewCounter-{EC_Number,StateStored}|NewSoFar0].


insertOneFact(Fact,CountedResultSoFar,[Sign-1-{EC_Number,State}|CountedResultSoFar]):-
	Fact=[enzyme_state-{Sign,EC_Number,State}].


allScoring([],[]).
allScoring([H|AllH],[Score-H|AllScoredH]):-
	allScoring(AllH,AllScoredH),
	%oneHScoring(H,Score).
	oneHScoring_ignoreNoChange(H,Score).


oneHScoring([],0).
oneHScoring([Ele|H],Score):-
	oneHScoring(H,ScoredSoFar),
	Ele=Sign-NewCounter-{EC_Number,StateStored},
	Score is ScoredSoFar+Sign.
	

oneHScoring_ignoreNoChange([],0).
oneHScoring_ignoreNoChange([Ele|H],Score):-
	oneHScoring_ignoreNoChange(H,ScoredSoFar),
	Ele=Sign-NewCounter-{EC_Number,State},
	(State==no_change->
		Score=ScoredSoFar;
		Score is ScoredSoFar+Sign
	).
		


