



%------ Leave-one-out -----------------
sepPosNeg([],[],[]).
sepPosNeg([TrainEx|TrainingEIs],[TrainEx|TrainPE],TrainNE):-
    ex(TrainEx,1),
    sepPosNeg(TrainingEIs,TrainPE,TrainNE).
sepPosNeg([TrainEx|TrainingEIs],TrainPE,[TrainEx|TrainNE]):-
    ex(TrainEx,0),
    sepPosNeg(TrainingEIs,TrainPE,TrainNE).

leave_one_out(FoldID,HSampleSize):-
    findall(Ex,ex(Ex,PosNegSign),AllExs),
    nth(FoldID,AllExs,TestEx),
    delete(AllExs,TestEx,TrainExs),
    sepPosNeg(TrainExs,TrainPos,TrainNeg), 

    statistics(cputime,[Total1,Previous]),
    generalise_oneTrainingSetF(TrainPos,TrainNeg,HSampleSize,Hs),
    statistics(cputime,[Total2,TimeTaken]), 
    remove_duplicates(Hs,Hs_noDuplicate),
    tell('h_metaBayes.pl'),portray_clause(sampledHs(Hs_noDuplicate)),told,
%    tell('h_metaBayes_superimposed.pl'),
%    superimpose_clauses(Hs_noDuplicate,ClausesWithFrequencists),
%    told,

    ex(TestEx,TargetLabel),
    get_acc_likelihood(Hs_noDuplicate,TestEx-TargetLabel,PA,LogLikelihood),

    length(Hs_noDuplicate,N),AveTimeTaken is TimeTaken/(N*1000),
    portray_clause(numSampledHs(N)),
    tell('onePA.pl'),
    write(PA),write(' '), 
    told,
    tell('oneLogLikehood.pl'),
    write(LogLikelihood),write(' '), 
    told,
    tell('oneTime.pl'),
    write(TimeTaken),write(' '), 
    told,
    write(result_oneSample(Problem_info,SampleSize,SameSizeRepeated,PA,LogLikelihood,AveTimeTaken)),writeln('.'),nl,!.


% ------ hold out: assuming training examples are in the form of ex(Ex,PosNegSign), while test examples are as test_examples(Ex,PosNegSign).
train_test(HSampleSize):-
    findall(Ex,ex(Ex,1),TrainPos),
    findall(Ex,ex(Ex,0),TrainNeg),
    write('%'),write({TrainPos,TrainNeg}),nl,
    statistics(cputime,[Total1,Previous]),
    %write('++++++++'),writeln(PLKB),
    %nth1(1,PLKB,PL),nth1(2,PLKB,KB),
    %write('++++++++'),writeln(PL),
    %write('++++++++'),writeln(KB),
    generalise_oneTrainingSetF(TrainPos,TrainNeg,HSampleSize,Hs),
    statistics(cputime,[Total2,TimeTaken]), 
    remove_duplicates(Hs,Hs_noDuplicate),
tell('hypothesises.pl'),portray_clause(sampledHs(Hs_noDuplicate)),told,

findall(TestEx-TargetLabel,test_examples(TestEx,TargetLabel),AllTest_withLabels),
maplist(get_acc_likelihood(Hs_noDuplicate),AllTest_withLabels,PAs,LogLikelihoods),
sumList(PAs,PA0),length(AllTest_withLabels,NumTestExs),PA is 100*PA0/NumTestExs,
sumList(LogLikelihoods,LogLikelihood),

length(Hs_noDuplicate,N),AveTimeTaken is TimeTaken/(N*1000),
portray_clause(numSampledHs(N)),
tell('onePA.pl'),
write(PA),write(' '), 
told,
tell('oneLogLikehood.pl'),
write(LogLikelihood),write(' '), 
told,
tell('oneTime.pl'),
write(AveTimeTaken),write(' '), 
told.


train_testF(SampleSize,SameSizeRepeated,HSampleSize):-
	write('%%%%%train_testF'),write({SampleSize,SameSizeRepeated}),nl,
	oneSampleF(SampleSize,SameSizeRepeated,TrainPos,TrainNeg),
	write('%'),write({TrainPos,TrainNeg}),nl,
    statistics(cputime,[Total1,Previous]),
		%write('++++++++'),writeln(PLKB),
		%nth1(1,PLKB,PL),nth1(2,PLKB,KB),
		%write('++++++++'),writeln(PL),
		%write('++++++++'),writeln(KB),
    generalise_oneTrainingSetF(TrainPos,TrainNeg,HSampleSize,Hs),
	statistics(cputime,[Total2,TimeTaken]), 
    remove_duplicates(Hs,Hs_noDuplicate),
tell('h_metaBayes.pl'),portray_clause(sampledHs(Hs_noDuplicate)),told,
tell('h_metaBayes_superimposed.pl'),
    superimpose_clauses(Hs_noDuplicate,ClausesWithFrequencists),
told,

/*
group_bySize(Hs0,GroupedHs),
renormalise_blocks(GroupedHs,Hs),
portray_clause(updated(Hs)),


	dataList(test,pos,TestPos),dataList(test,neg,TestNeg),
	write('\n%%%%% Bayes prediction results: '),nl,
unCoverRecord_block(Hs,TestPos,FN),length(FN,FalseNegativeNum),
write(false_negative(SampleSize,SameSizeRepeated,FN)),writeln('.'),% False Negative 
unCoverRecord_block(Hs,TestNeg,TN),length(TN,TrueNegativeNum), 
write(true_negative(SampleSize,SameSizeRepeated,TN)),writeln('.'),nl,% True Negative 
*/
	dataList(test,pos,TestPos),dataList(test,neg,TestNeg),append(TestPos,TestNeg,AllTest_withLabels),

maplist(get_acc_likelihood(Hs_noDuplicate),AllTest_withLabels,PAs,LogLikelihoods),
sumList(PAs,PA0),length(AllTest_withLabels,NumTestExs),PA is 100*PA0/NumTestExs,
sumList(LogLikelihoods,LogLikelihood),


length(Hs_noDuplicate,N),AveTimeTaken is TimeTaken/(N*1000),
portray_clause(numSampledHs(N)),
tell('onePA.pl'),
write(PA),write(' '), 
told,
tell('oneLogLikehood.pl'),
write(LogLikelihood),write(' '), 
told,
tell('oneTime.pl'),
write(AveTimeTaken),write(' '), 
told,
	write(result_oneSample(Problem_info,SampleSize,SameSizeRepeated,PA,LogLikelihood,AveTimeTaken)),writeln('.'),nl,!.


get_acc_likelihood(Hs,Ex-TargetLabel,PA,LogLikelihood):-
    bayes_predict(Ex,Hs,[],Prediction),portray_clause(prediction(Ex-TargetLabel,Prediction)),
    predictive_accuracy0(TargetLabel,Prediction,PA),
    logLikelihood0(TargetLabel,Prediction,LogLikelihood).


predictive_accuracy0(TargetLabel,Prediction,Accuracy):-
        TargetLabel=1,!,
        (Prediction>0.5 -> 
            Accuracy=1;
            Accuracy=0
        ).
predictive_accuracy0(TargetLabel,Prediction,Accuracy):-
    (Prediction=<0.5 -> %%---*Prediction<0.5 -> 
        Accuracy=1;
        Accuracy=0
    ).


logLikelihood0(TargetLabel,Likelihood0,LogLikelihood):-
        %write(Likelihood0),
        (TargetLabel=1 ->
            Likelihood=Likelihood0;
            Likelihood is abs(1-Likelihood0)   % bug in ProbLog to have negative value -- could be due to number overflow
        ),
        (Likelihood==0.0->
            Likelihood2=0.00000000001;
            Likelihood2=Likelihood
        ),
        LogLikelihood is -log(Likelihood2).



unCoverRecord(Hs,[],[]).
unCoverRecord(Hs,[Ex|CheckList],NUnCoverList):-
    (set(prediction,bayes_predict)->
        bayes_predict(Ex,Hs,[],Prob);
        slp_predict(Ex,Hs,Prob)
    ),
    portray_clause(predicted_result(Ex,Prob)),
    (Prob>0.5->
        NUnCoverList=UnCoverList;
        NUnCoverList=[Ex|UnCoverList]
    ),
unCoverRecord(Hs,CheckList,UnCoverList).


tag_label(Label,Ex,Ex-Label).

dataList(test,pos,TestPos_withLabel):-
	set(test_size,TestSize),TestPosSize is TestSize//2,
	set(train_size,TrainSize),TrainPosSize is TrainSize//2,
	%write('%%%%%dataList'),write({TrainPosSize,TestPosSize}),nl,
    findall(Seq,ex(Seq,1),AllPos),
	StartIndex is TrainPosSize+1,EndIndex is StartIndex+TestPosSize-1,
	%write('%%%%%dataList%'),write({StartIndex,EndIndex}),nl,
	numbersList(StartIndex,EndIndex,TestPosIndexes),
    fetchbyIndex(AllPos,TestPosIndexes,TestPos),
    maplist(tag_label(1),TestPos,TestPos_withLabel).
dataList(test,neg,TestNeg_withLabel):- 
    set(test_size,TestSize),TestNegSize is TestSize//2,
    set(train_size,TrainSize),TrainNegSize is TrainSize//2,
    findall(Seq,ex(Seq,0),AllNeg),
    StartIndex is TrainNegSize+1,EndIndex is StartIndex+TestNegSize-1,
%   write('%'),write({StartIndex,EndIndex}),
    numbersList(StartIndex,EndIndex,TestNegIndexes),
    fetchbyIndex(AllNeg,TestNegIndexes,TestNeg),
    maplist(tag_label(0),TestNeg,TestNeg_withLabel).


oneSample(SampleSize,SameSizeRepeated,TrainPos,TrainNeg):-
	set(sampleSizes,Sizes),last_ele(Sizes,Rest,MaxSize),Distance is MaxSize//2,
%	write('##########'),write(Sizes),write(','),write(MaxSize),write(','),write(Distance),nl,
	StartIndex is ((SameSizeRepeated-1)*Distance+1),
	EndIndex is (StartIndex+(SampleSize//2-1)),
%	write('##########'),write(SameSizeRepeated),write(','),write(StartIndex),write(','),write(EndIndex),nl,
	numbersList(StartIndex,EndIndex,Indexes),
findall(Seq,ex(Seq,1),AllPos),
fetchbyIndex(AllPos,Indexes,TrainPos),
findall(Seq,ex(Seq,0),AllNeg),
fetchbyIndex(AllNeg,Indexes,TrainNeg).


oneSampleF(SampleSize,SameSizeRepeated,TrainPos,TrainNeg):- %Size>=4
	write('%%%%%oneSampleF'),write({SampleSize,SameSizeRepeated}),nl,
%trace,
	set(sampleSizes,Sizes),last_ele(Sizes,Rest,MaxSize),Distance is MaxSize//2,
%	write('##########oneSampleF'),write(Sizes),write(','),write(MaxSize),write(','),write(Distance),nl,
	StartIndex is ((SameSizeRepeated-1)*Distance+1),
	EndIndex is (StartIndex+(SampleSize//2-1)),
%	write('%%%%%%%%%oneSampleF'),write(SameSizeRepeated),write(','),write(StartIndex),write(','),write(EndIndex),nl,
	numbersList(StartIndex,EndIndex,Indexes),
%write('##########'),writeln(Indexes),
findall(Seq,ex(Seq,1),AllPos),
fetchbyIndex(AllPos,Indexes,TrainPos),
findall(Seq,ex(Seq,0),AllNeg),
fetchbyIndex(AllNeg,Indexes,TrainNeg).
%write('********'),write(AllNeg),write(Indexes),writeln(TrainNeg).





group_bySize([],[]).
group_bySize([hyp(Prob,Hyp)|Hs],GroupedHs):-
    group_bySize(Hs,PreGroupedHs),
    length(Hyp,Size),
    (append(Pre,[Size-SameSizeHs|Post],PreGroupedHs)->
        append(Pre,[Size-[hyp(1,Hyp)|SameSizeHs]|Post],GroupedHs);
        GroupedHs=[Size-[hyp(1,Hyp)]|PreGroupedHs]
).


renormalise_blocks(GroupedHs,RenormalisedGroupedHs):-
    maplist(getBlockPrior,GroupedHs,BlockPriors,PrioredGroupedHs),
    sumList(BlockPriors,RenormalisedConstant),
    maplist(renormalise_blocks0(RenormalisedConstant),PrioredGroupedHs,RenormalisedGroupedHs).


/*
knownBlockPrior(3,1/200):-!.
knownBlockPrior(4,4/200):-!.
knownBlockPrior(5,14/200):-!.
knownBlockPrior(6,27/200):-!.
knownBlockPrior(7,50/200):-!.
knownBlockPrior(8,47/200):-!.
knownBlockPrior(9,47/200):-!.
knownBlockPrior(10,10/200):-!.
knownBlockPrior(X,0).
*/

knownBlockPrior(HSize,BlockPrior):-
	%BlockPrior is 1/(HSize*HSize).
	BlockPrior is 1/(2^HSize). % Exponential

%knownBlockPrior(HSize,1).

getBlockPrior(HSize-Hs,BlockPrior,BlockPrior-Hs):-
    knownBlockPrior(HSize,BlockPrior).

renormalise_blocks0(RenormalisedConstant,BlockPrior0-Hs,BlockPrior-Hs):-
    BlockPrior is BlockPrior0/RenormalisedConstant.
    


bayes_blockPredict(X,BK,BlockPrioredHs,Prob):-
    maplist(bayes_blockPredict0(X-BK),BlockPrioredHs,WeightedPrediction),
    sumList(WeightedPrediction,Prob). %the weigth need to renormalised, otherwise

bayes_blockPredict0(X-BK,BlockPrior-Hs0,BlockPrior*Prob):-
remove_duplicates(Hs0,Hs),
    bayes_predict(X,Hs,BK,Prob).


unCoverRecord_block(Hs,[],[]).
unCoverRecord_block(Hs,[Ex|CheckList],NUnCoverList):-
bk(0,BK),
	bayes_blockPredict(Ex,BK,Hs,Prob),portray_clause(predicted_result(Ex,Prob)),
	(Prob>0.5->
		NUnCoverList=UnCoverList;
		NUnCoverList=[Ex|UnCoverList]
	),
	unCoverRecord_block(Hs,CheckList,UnCoverList).

