887 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			887 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
|   | /* | ||
|  | 
 | ||
|  | CEM | ||
|  | 
 | ||
|  | Copyright (c) 2011, Fabrizio Riguzzi | ||
|  | 
 | ||
|  | */ | ||
|  | %:- set_prolog_flag(unknown,error). | ||
|  | %:- set_prolog_flag(profiling,on). | ||
|  | %:- set_prolog_flag(debug,on). | ||
|  | :- set_prolog_flag(discontiguous_warnings,on). | ||
|  | :- set_prolog_flag(single_var_warnings,on). | ||
|  | :- set_prolog_flag(unknown,fail). | ||
|  | %:-source. | ||
|  | %:-yap_flag(gc_trace,very_verbose). | ||
|  | :- use_module(inference, | ||
|  | [find_deriv_inf1/3]). | ||
|  | %:-consult(inference). | ||
|  | :-use_module(library(rbtrees)). | ||
|  | :-use_module(library(random)). | ||
|  | :-use_module(library(avl)). | ||
|  | :-use_module(library(lists)). | ||
|  | 
 | ||
|  | %:-use_module(library(lpadsld)). | ||
|  | :-load_foreign_files(['cplint'],[],init_my_predicates). | ||
|  | 
 | ||
|  | :-dynamic setting/2,rule/5. | ||
|  | 
 | ||
|  | 
 | ||
|  | setting(depth,3). | ||
|  | setting(single_var,false). | ||
|  | 
 | ||
|  | setting(sample_size,1000).  | ||
|  | /* Total number of examples in case in which the models in the kb file contain | ||
|  | a prob(P). fact. In that case, one model corresponds to sample_size*P examples | ||
|  | */ | ||
|  | setting(equivalent_sample_size,100). | ||
|  | /* equivalent samaple size for computing the BD score of the network refinements | ||
|  | It is indicated with NPrime in the formulas on Heckerman, Geiger & Chickering | ||
|  | paper */ | ||
|  | setting(epsilon_em,0.1). | ||
|  | setting(epsilon_em_fraction,0.01). | ||
|  | /* if the difference in log likelihood in two successive em iteration is smaller | ||
|  | than epsilon_em, then em stops */ | ||
|  | setting(epsilon_sem,2). | ||
|  | setting(random_restarts_number,1). | ||
|  | /* number of random restarts of em */ | ||
|  | setting(verbosity,1). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | em(File):- | ||
|  |   generate_file_names(File,FileKB,FileOut,FileL,FileLPAD), | ||
|  |   reconsult(FileL), | ||
|  |   load_models(FileKB,DB), | ||
|  |   load_initial_model(FileLPAD,Model0),!, | ||
|  |   set(verbosity,3), | ||
|  |   statistics(cputime,[_,_]),   | ||
|  |   gen_ex(DB,[],DBE), | ||
|  |   compute_parameters_EM(Model0,Model,SuffStats,CLL,DBE), | ||
|  |   statistics(cputime,[_,CT]), | ||
|  |   CTS is CT/1000, | ||
|  |   format("Final CLL ~f~n",[CLL]), | ||
|  |   format("Execution time ~f~n",[CTS]), | ||
|  |   write_stats(user_output,SuffStats), | ||
|  |   listing(setting/2), | ||
|  |   format("Model:~n",[]), | ||
|  |   write_model(Model,user_output), | ||
|  |   open(FileOut,write,Stream), | ||
|  |   format(Stream,"/* Final CLL ~f~n",[CLL]), | ||
|  |   format(Stream,"Execution time ~f~n",[CTS]), | ||
|  |   tell(Stream), | ||
|  |   listing(setting/2), | ||
|  |   write_stats(Stream,SuffStats), | ||
|  |   format(Stream,"*/~n",[]), | ||
|  |   write_model(Model,Stream), | ||
|  |   told. | ||
|  | 
 | ||
|  | gen_ex([],DBE,DBE). | ||
|  | 
 | ||
|  | gen_ex([H|T],DB0,DB1):- | ||
|  |         get_ouptut_atoms(O), | ||
|  |   generate_goal(O,H,[],GL), | ||
|  |   append(DB0,GL,DB2), | ||
|  |   gen_ex(T,DB2,DB1). | ||
|  | 
 | ||
|  | 
 | ||
|  | cycle_head([],[],_NR,_S,_NH,_PG,_CSetList,_N):-!. | ||
|  | 
 | ||
|  | cycle_head([SSH0|T],[SSH1|T1],NR,S,NH,PG,CSetList,N):- | ||
|  |   extract_relevant_C_sets(NR,S,NH,CSetList,CSL1), | ||
|  |   (CSL1=[]-> | ||
|  |     SSH1 is SSH0 | ||
|  |   ;       | ||
|  |     build_formula(CSL1,Formula,[],Var), | ||
|  |     var2numbers(Var,0,NewVar), | ||
|  |     compute_prob(NewVar,Formula,Prob,0), | ||
|  |     SSH1 is SSH0 +Prob/PG*N | ||
|  |   ), | ||
|  |   NH1 is NH+1, | ||
|  |   cycle_head(T,T1,NR,S,NH1,PG,CSetList,N). | ||
|  | 
 | ||
|  | cycle_head_neg([],[],_NR,_S,_NH,_NA,_PG,_CSetList,_N):-!. | ||
|  | 
 | ||
|  | cycle_head_neg([SSH0|T],[SSH1|T1],NR,S,NH,NA,PG,CSetList,N):- | ||
|  |         extract_relevant_C_sets_neg(NR,S,NH,NA,CSetList,CSL1), | ||
|  |         (CSL1=[]-> | ||
|  |                 SSH1 is SSH0%+0.001 | ||
|  |         ;                        | ||
|  |                 build_formula(CSL1,Formula,[],Var), | ||
|  |                 var2numbers(Var,0,NewVar), | ||
|  |                 compute_prob(NewVar,Formula,Prob,0), | ||
|  |                 (Prob>1 ->write(cyc),write(Prob),write(NewVar),nl;true), | ||
|  |                 SSH1 is SSH0 +(1-Prob)/PG*N | ||
|  |         ), | ||
|  |         NH1 is NH+1, | ||
|  |         cycle_head_neg(T,T1,NR,S,NH1,NA,PG,CSetList,N). | ||
|  | 
 | ||
|  | extract_relevant_C_sets_neg(NR,S,NH,NA,CS,CS1):- | ||
|  |         neg_choice(0,NA,NH,NR,S,C), | ||
|  |         append(CS,C,CS1). | ||
|  | 
 | ||
|  | neg_choice(N,N,_NH,_NR,_S,[]):-!. | ||
|  | 
 | ||
|  | neg_choice(NH,NA,NH,NR,S,L):-!, | ||
|  |         N1 is NH+1, | ||
|  |         neg_choice(N1,NA,NH,NR,S,L). | ||
|  | 
 | ||
|  | neg_choice(N,NA,NH,NR,S,[[(N,NR,S)]|L]):- | ||
|  |         N1 is N+1, | ||
|  |         neg_choice(N1,NA,NH,NR,S,L). | ||
|  | 
 | ||
|  | extract_relevant_C_sets(_NR,_S,_NH,[],[]):-!. | ||
|  | 
 | ||
|  | extract_relevant_C_sets(NR,S,NH,[H|T],CS):- | ||
|  |   member((NH1,NR,S),H),!, | ||
|  |   extract_relevant_C_sets1(NR,S,NH,NH1,H,T,CS). | ||
|  | 
 | ||
|  | extract_relevant_C_sets(NR,S,NH,[H|T],[H1|CS]):- | ||
|  |   append(H,[(NH,NR,S)],H1),   | ||
|  |   extract_relevant_C_sets(NR,S,NH,T,CS). | ||
|  | 
 | ||
|  | extract_relevant_C_sets1(NR,S,NH,NH1,_H,T,CS):- | ||
|  |   NH1\=NH,!, | ||
|  |   extract_relevant_C_sets(NR,S,NH,T,CS). | ||
|  | 
 | ||
|  | extract_relevant_C_sets1(NR,S,NH,_NH1,H,T,[H|CS]):- | ||
|  |   extract_relevant_C_sets(NR,S,NH,T,CS). | ||
|  |      | ||
|  | 
 | ||
|  |    | ||
|  | /* EM start */ | ||
|  | compute_parameters_EM([],[],SuffStats,-1e200,_DB):-!, | ||
|  |   rb_new(SuffStats). | ||
|  | 
 | ||
|  | compute_parameters_EM(Model0,Model1,SuffStats1,CLL1,DB):- | ||
|  |   setting(verbosity,Ver), | ||
|  |   (Ver>0-> | ||
|  |     format("EM computation ~nInitial model:~n",[]), | ||
|  |     write_model(Model0,user_output), | ||
|  |     flush_output | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   (Ver>2-> | ||
|  |     format("Initial EM Iteration ~n",[]), | ||
|  |     flush_output | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   randomize(Model0,ModelR), | ||
|  |   em_iteration(ModelR,Model,SuffStats,CLL,DB), | ||
|  |   (Ver>2-> | ||
|  |     format("CLL ~f~n",[CLL]) | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   flush_output, | ||
|  |   setting(random_restarts_number,N), | ||
|  |   random_restarts(N,Model,SuffStats,CLL,Model1,SuffStats1,CLL1,DB), | ||
|  |   (Ver>0-> | ||
|  |     format("Final CLL ~f~n",[CLL1]), | ||
|  |     flush_output | ||
|  |   ; | ||
|  |     true | ||
|  |   ). | ||
|  |    | ||
|  | random_restarts(1,Model,SS,CLL,Model,SS,CLL,_DB):-!. | ||
|  | 
 | ||
|  | random_restarts(N,Model0,SS0,CLL0,Model1,SS1,CLL1,DB):- | ||
|  |   setting(verbosity,Ver), | ||
|  |   (Ver>2-> | ||
|  |     setting(random_restarts_number,NMax), | ||
|  |     Num is NMax-N+1, | ||
|  |     format("Restart number ~d~n",[Num]), | ||
|  |     flush_output | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   randomize(Model0,ModelR), | ||
|  |   em_iteration(ModelR,ModelR1,SSR,CLLR,DB), | ||
|  |   setting(verbosity,Ver), | ||
|  |   (Ver>2-> | ||
|  |     format("CLL ~f~n",[CLLR]) | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   N1 is N-1, | ||
|  |   (CLLR>CLL0-> | ||
|  |     random_restarts(N1,ModelR1,SSR,CLLR,Model1,SS1,CLL1,DB) | ||
|  |   ; | ||
|  |     random_restarts(N1,Model0,SS0,CLL0,Model1,SS1,CLL1,DB) | ||
|  |   ). | ||
|  | 
 | ||
|  | randomize([],[]):-!. | ||
|  | 
 | ||
|  | randomize([rule(N,V,NH,HL,BL,LogF)|T],[rule(N,V,NH,HL1,BL,LogF)|T1]):- | ||
|  |   length(HL,L), | ||
|  |   Int is 1.0/L, | ||
|  |   randomize_head(Int,HL,0,HL1), | ||
|  |   randomize(T,T1). | ||
|  | 
 | ||
|  | randomize_head(_Int,['':_],P,['':PNull1]):-!, | ||
|  |   PNull is 1.0-P, | ||
|  |   (PNull>=0.0-> | ||
|  |     PNull1 =PNull | ||
|  |   ; | ||
|  |     PNull1=0.0 | ||
|  |   ). | ||
|  |    | ||
|  | randomize_head(Int,[H:_|T],P,[H:PH1|NT]):- | ||
|  |   PMax is 1.0-P, | ||
|  |   random(0,PMax,PH1), | ||
|  |   P1 is P+PH1,   | ||
|  |   randomize_head(Int,T,P1,NT). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | em_iteration(Model0,ModelPar,SuffStats1,CLL1,DB):- | ||
|  |   compute_CLL_stats(Model0,DB,CLL0,SuffStats0), | ||
|  | /*  setting(verbosity,Ver), | ||
|  |   (Ver>2-> | ||
|  |     format("EM Iteration numer ~d~nCLL ~f~n",[N,CLL0]), | ||
|  |     write_stats(user_output,SuffStats0) | ||
|  |   ; | ||
|  |     true | ||
|  |   ),*/ | ||
|  |   cycle_EM(Model0,SuffStats0,CLL0,ModelPar,SuffStats1,CLL1,DB,1). | ||
|  |    | ||
|  | cycle_EM(Model0,SuffStats0,CLL0,ModelPar,SuffStats,CLL,DB,N):- | ||
|  |   m_step(Model0,SuffStats0,Model1), | ||
|  |   compute_CLL_stats(Model1,DB,CLL1,SuffStats1), | ||
|  |   setting(verbosity,Ver), | ||
|  |   (Ver>2-> | ||
|  |     format("Iteration: ~d CLL ~f~n",[N,CLL1]) | ||
|  |   ; | ||
|  |     true | ||
|  |   ), | ||
|  |   flush_output, | ||
|  | %  write_stats(user_output,SuffStats1), | ||
|  | %  statistics, | ||
|  |   setting(epsilon_em,Epsilon_EM), | ||
|  |   setting(epsilon_em_fraction,Epsilon_EM_Frac), | ||
|  |   ((CLL1-CLL0<Epsilon_EM;(CLL1-CLL0)< - CLL0*Epsilon_EM_Frac)-> | ||
|  |     ModelPar=Model1, | ||
|  |     SuffStats=SuffStats1, | ||
|  |     CLL=CLL1,! | ||
|  |   ; | ||
|  |     N1 is N+1,!, | ||
|  |     cycle_EM(Model1,SuffStats1,CLL1,ModelPar,SuffStats,CLL,DB,N1) | ||
|  |   ). | ||
|  | 
 | ||
|  | write_stats(S,SS):- | ||
|  |   rb_visit(SS,Pairs), | ||
|  |   format(S,"Suff stats~n",[]), | ||
|  |   write_stats_list(S,Pairs). | ||
|  | 
 | ||
|  | write_stats_list(S,[]):-nl(S),nl(S),!. | ||
|  | 
 | ||
|  | write_stats_list(S,[R-d(D,N,I)|T]):- | ||
|  |   format(S,"~d,~p,~f,~d~n",[R,D,N,I]), | ||
|  |   write_stats_list(S,T). | ||
|  | 
 | ||
|  | m_step([],_SS,[]):-!. | ||
|  | 
 | ||
|  | m_step([rule(N,V,NH,HL,BL,LogF)|T],SS,[rule(N,V,NH,HL1,BL,LogF)|T1]):- | ||
|  |   (rb_lookup(N,d(Distr,_NBT,_NI),SS)-> | ||
|  |     sum_list(Distr,NBT), | ||
|  |     update_head(HL,Distr,NBT,HL1) | ||
|  |   ; | ||
|  |     HL1=HL | ||
|  |   ), | ||
|  |   m_step(T,SS,T1). | ||
|  | 
 | ||
|  | update_head([],[],_N,[]).   | ||
|  | 
 | ||
|  | update_head([H:_P|T],[PU|TP],N,[H:P|T1]):- | ||
|  |   P is PU/N, | ||
|  |   update_head(T,TP,N,T1). | ||
|  | 
 | ||
|  | 
 | ||
|  | /* EM end */     | ||
|  |    | ||
|  |    | ||
|  | /* Start of computation of log likelihood and sufficient stats */ | ||
|  | compute_CLL_stats(Model,DB,CLL,SuffStats1):- | ||
|  |   assert_model(Model), | ||
|  |   compute_CLL_stats_examples(DB,CLL,SuffStats1), | ||
|  |   retract_model. | ||
|  | 
 | ||
|  | assert_model([]):-!. | ||
|  | 
 | ||
|  | assert_model([rule(N,V,NH,HL,BL,_LogF)|T]):- | ||
|  |   assert_rules(HL,0,HL,BL,NH,N,V), | ||
|  |   assertz(rule_by_num(N,V,NH,HL,BL)), | ||
|  |   assert_model(T). | ||
|  | 
 | ||
|  | retract_model:- | ||
|  |   retractall(rule_by_num(_,_,_,_,_)), | ||
|  |   retractall(rule(_,_,_,_,_,_,_,_)). | ||
|  | 
 | ||
|  | assert_rules([],_Pos,_HL,_BL,_Nh,_N,_V1):-!. | ||
|  | 
 | ||
|  | assert_rules(['':_P],_Pos,_HL,_BL,_Nh,_N,_V1):-!. | ||
|  | 
 | ||
|  | assert_rules([H:P|T],Pos,HL,BL,NH,N,V1):- | ||
|  |         assertz(rule(H,P,Pos,N,V1,NH,HL,BL)), | ||
|  |         Pos1 is Pos+1, | ||
|  |         assert_rules(T,Pos1,HL,BL,NH,N,V1). | ||
|  | 
 | ||
|  | compute_CLL_stats_examples(DB,CLL,SuffStats1):- | ||
|  |   rb_new(SuffStats0), | ||
|  |   compute_CLL_stats_cplint(DB,0,CLL,SuffStats0,SuffStats1). | ||
|  | 
 | ||
|  | get_ouptut_atoms(O):- | ||
|  |   findall((A/Ar),output((A/Ar)),O). | ||
|  | 
 | ||
|  | generate_goal([],_H,G,G):-!. | ||
|  | 
 | ||
|  | generate_goal([P/A|T],H,G0,G1):- | ||
|  |   functor(Pred,P,A), | ||
|  |   Pred=..[P|Rest], | ||
|  |   Pred1=..[P,H|Rest], | ||
|  |   findall(Pred1,call(Pred1),L), | ||
|  |   findall(\+ Pred1,call(neg(Pred1)),LN), | ||
|  |   append(G0,L,G2), | ||
|  |   append(G2,LN,G3), | ||
|  |   generate_goal(T,H,G3,G1). | ||
|  |    | ||
|  | compute_CLL_stats_cplint([],CLL,CLL,S,S):-!. | ||
|  | 
 | ||
|  | compute_CLL_stats_cplint([\+ H|T],CLL0,CLL1,Stats0,Stats1):-!, | ||
|  |         setting(verbosity,V), | ||
|  |         (V>3-> | ||
|  |                 write(user_error,(\+ H)),nl(user_error),flush_output | ||
|  |         ; | ||
|  |                 true | ||
|  |         ), | ||
|  |         s([H],CL,CSetList,PG),!, | ||
|  |         (PG=:=1.0-> | ||
|  |                 CLL2=CLL0, | ||
|  |                 Stats2=Stats0    | ||
|  |         ; | ||
|  |                 (prob(H,P)-> | ||
|  |                         setting(sample_size,NTot), | ||
|  |                         N is P*NTot | ||
|  |                 ; | ||
|  |                         N=1 | ||
|  |                 ), | ||
|  |                 PG1 is 1-PG, | ||
|  |                 CLL2 is CLL0+log(PG1)*N, | ||
|  |                 collect_stats_cplint_neg(CL,PG1,CSetList,N,Stats0,Stats2) | ||
|  |         ), | ||
|  |         compute_CLL_stats_cplint(T,CLL2,CLL1,Stats2,Stats1). | ||
|  | 
 | ||
|  | compute_CLL_stats_cplint([H|T],CLL0,CLL1,Stats0,Stats1):- | ||
|  |         setting(verbosity,V), | ||
|  |         (V>3-> | ||
|  |                 write(user_error,H),nl(user_error),flush_output | ||
|  |         ; | ||
|  |                 true | ||
|  |         ), | ||
|  |   s([H],CL,CSetList,PG),!, | ||
|  |   (PG=0.0-> | ||
|  |     CLL2=CLL0, | ||
|  |     Stats2=Stats0   | ||
|  |   ; | ||
|  |     (prob(H,P)-> | ||
|  |       setting(sample_size,NTot), | ||
|  |       N is P*NTot | ||
|  |     ; | ||
|  |       N=1 | ||
|  |     ), | ||
|  |     CLL2 is CLL0+log(PG)*N, | ||
|  |     collect_stats_cplint(CL,PG,CSetList,N,Stats0,Stats2) | ||
|  |   ), | ||
|  |   compute_CLL_stats_cplint(T,CLL2,CLL1,Stats2,Stats1). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | s(GoalsList,GroundLpad,CSets,Prob):- | ||
|  |   solve(GoalsList,GroundLpad,CSets,Prob). | ||
|  | 
 | ||
|  | solve(GoalsList,GroundLpad,LDup,Prob):- | ||
|  |         setting(depth,D), | ||
|  |         findall(Deriv,inference:find_deriv_inf1(GoalsList,D,Deriv),LDup), | ||
|  |         (LDup=[]-> | ||
|  |                 Prob=0.0, | ||
|  |                 GroundLpad=[] | ||
|  |         ; | ||
|  |                 append(LDup,L0), | ||
|  |                 remove_head(L0,L1), | ||
|  |                 remove_duplicates(L1,L2), | ||
|  |                 build_ground_lpad(L2,GroundLpad), | ||
|  |                 build_formula(LDup,Formula,[],Var), | ||
|  |                 var2numbers(Var,0,NewVar), | ||
|  |                 compute_prob(NewVar,Formula,Prob,0), | ||
|  |                 true | ||
|  |         ). | ||
|  | 
 | ||
|  | collect_stats_cplint([],_PG,_CSetList,_N,Stats,Stats):-!.   | ||
|  | 
 | ||
|  | collect_stats_cplint([(R,S,Head,_Body)|T],PG,CSetList,N,Stats0,Stats1):- | ||
|  |   (rb_lookup(R,d(Distr0,N1,NInst1),Stats0)-> | ||
|  |     cycle_head(Distr0,Distr,R,S,0,PG,CSetList,N), | ||
|  |     N2 is N+N1, | ||
|  |     rb_update(Stats0,R,d(Distr,N2,NInst1),Stats2) | ||
|  |   ; | ||
|  |     length(Head,LH), | ||
|  |     list0(0,LH,Distr0), | ||
|  |     cycle_head(Distr0,Distr,R,S,0,PG,CSetList,N), | ||
|  |     rb_insert(Stats0,R,d(Distr,N,1),Stats2) | ||
|  |   ), | ||
|  |   collect_stats_cplint(T,PG,CSetList,N,Stats2,Stats1). | ||
|  | 
 | ||
|  | collect_stats_cplint_neg([],_PG,_CSetList,_N,Stats,Stats):-!. | ||
|  | 
 | ||
|  | collect_stats_cplint_neg([(R,S,Head,_Body)|T],PG,CSetList,N,Stats0,Stats1):- | ||
|  |         length(Head,NA), | ||
|  |         (rb_lookup(R,d(Distr0,N1,NInst1),Stats0)-> | ||
|  |                 cycle_head_neg(Distr0,Distr,R,S,0,NA,PG,CSetList,N), | ||
|  |                 N2 is N+N1, | ||
|  |                 rb_update(Stats0,R,d(Distr,N2,NInst1),Stats2) | ||
|  |         ; | ||
|  |                 length(Head,LH), | ||
|  |                 list0(0,LH,Distr0), | ||
|  |                 cycle_head_neg(Distr0,Distr,R,S,0,NA,PG,CSetList,N), | ||
|  |                 rb_insert(Stats0,R,d(Distr,N,1),Stats2) | ||
|  |         ), | ||
|  |         collect_stats_cplint_neg(T,PG,CSetList,N,Stats2,Stats1). | ||
|  | 
 | ||
|  | /* build_formula(LC,Formula,VarIn,VarOut) takes as input a set of C sets | ||
|  | LC and a list of Variables VarIn and returns the formula and a new list | ||
|  | of variables VarOut  | ||
|  | Formula is of the form [Term1,...,Termn] | ||
|  | Termi is of the form [Factor1,...,Factorm] | ||
|  | Factorj is of the form (Var,Value) where Var is the index of | ||
|  | the multivalued variable Var and Value is the index of the value | ||
|  | */ | ||
|  | build_formula([],[],Var,Var,C,C). | ||
|  | 
 | ||
|  | build_formula([D|TD],[F|TF],VarIn,VarOut,C0,C1):- | ||
|  |         length(D,NC), | ||
|  |         C2 is C0+NC, | ||
|  |         build_term(D,F,VarIn,Var1), | ||
|  |         build_formula(TD,TF,Var1,VarOut,C2,C1). | ||
|  | 
 | ||
|  | build_formula([],[],Var,Var). | ||
|  | 
 | ||
|  | build_formula([D|TD],[F|TF],VarIn,VarOut):- | ||
|  |         build_term(D,F,VarIn,Var1), | ||
|  |         build_formula(TD,TF,Var1,VarOut). | ||
|  | 
 | ||
|  | build_term([],[],Var,Var). | ||
|  | 
 | ||
|  | build_term([(_,pruned,_)|TC],TF,VarIn,VarOut):-!, | ||
|  |         build_term(TC,TF,VarIn,VarOut). | ||
|  | 
 | ||
|  | build_term([(N,R,S)|TC],[[NVar,N]|TF],VarIn,VarOut):- | ||
|  |         (nth0_eq(0,NVar,VarIn,(R,S))-> | ||
|  |                 Var1=VarIn | ||
|  |         ; | ||
|  |                 append(VarIn,[(R,S)],Var1), | ||
|  |                 length(VarIn,NVar) | ||
|  |         ), | ||
|  |         build_term(TC,TF,Var1,VarOut). | ||
|  | 
 | ||
|  | /* nth0_eq(PosIn,PosOut,List,El) takes as input a List, | ||
|  | an element El and an initial position PosIn and returns in PosOut | ||
|  | the position in the List that contains an element exactly equal to El | ||
|  | */ | ||
|  | nth0_eq(N,N,[H|_T],El):- | ||
|  |         H==El,!. | ||
|  | 
 | ||
|  | nth0_eq(NIn,NOut,[_H|T],El):- | ||
|  |         N1 is NIn+1, | ||
|  |         nth0_eq(N1,NOut,T,El). | ||
|  | 
 | ||
|  | /* var2numbers converts a list of couples (Rule,Substitution) into a list | ||
|  | of triples (N,NumberOfHeadsAtoms,ListOfProbabilities), where N is an integer  | ||
|  | starting from 0 */ | ||
|  | var2numbers([],_N,[]). | ||
|  | 
 | ||
|  | var2numbers([(R,S)|T],N,[[N,ValNumber,Probs]|TNV]):- | ||
|  |         find_probs(R,S,Probs), | ||
|  |         length(Probs,ValNumber), | ||
|  |         N1 is N+1, | ||
|  |         var2numbers(T,N1,TNV). | ||
|  | 
 | ||
|  | find_probs(R,S,Probs):- | ||
|  |         rule_by_num(R,S,_N,Head,_Body), | ||
|  |         get_probs(Head,Probs). | ||
|  | 
 | ||
|  | get_probs(uniform(_A:1/Num,_P,_Number),ListP):- | ||
|  |         Prob is 1/Num, | ||
|  |         list_el(Num,Prob,ListP). | ||
|  | 
 | ||
|  | get_probs([],[]). | ||
|  | 
 | ||
|  | get_probs([_H:P|T],[P1|T1]):- | ||
|  |         P1 is P, | ||
|  |         get_probs(T,T1). | ||
|  | 
 | ||
|  | list_el(0,_P,[]):-!. | ||
|  | 
 | ||
|  | list_el(N,P,[P|T]):- | ||
|  |         N1 is N-1, | ||
|  |         list_el(N1,P,T). | ||
|  |      | ||
|  | sum(_NS,[],[],[]):-!.   | ||
|  | 
 | ||
|  | sum(NS,[H0|T0],[H1|T1],[H2|T2]):- | ||
|  |   H2 is H0+H1*NS, | ||
|  |   sum(NS,T0,T1,T2).   | ||
|  |    | ||
|  | times(_NS,[],[]):-!.   | ||
|  | 
 | ||
|  | times(NS,[H0|T0],[H1|T1]):- | ||
|  |   H1 is H0*NS, | ||
|  |   times(NS,T0,T1).   | ||
|  | 
 | ||
|  | /* End of computation of log likelihood and sufficient stats */ | ||
|  | 
 | ||
|  | /* Utility predicates */ | ||
|  | generate_file_names(File,FileKB,FileOut,FileL,FileLPAD):- | ||
|  |     generate_file_name(File,".kb",FileKB), | ||
|  |     generate_file_name(File,".rules",FileOut), | ||
|  |     generate_file_name(File,".cpl",FileLPAD), | ||
|  |     generate_file_name(File,".l",FileL). | ||
|  |          | ||
|  | generate_file_name(File,Ext,FileExt):- | ||
|  |     name(File,FileString), | ||
|  |     append(FileString,Ext,FileStringExt), | ||
|  |     name(FileExt,FileStringExt). | ||
|  | 
 | ||
|  |      | ||
|  | set(Parameter,Value):- | ||
|  |   retract(setting(Parameter,_)), | ||
|  |   assert(setting(Parameter,Value)). | ||
|  | 
 | ||
|  | load_initial_model(File,Model):- | ||
|  |   open(File,read,S), | ||
|  |   read_clauses(S,C), | ||
|  |   close(S), | ||
|  |   process_clauses(C,1,_N,[],Model). | ||
|  | 
 | ||
|  | process_clauses([(end_of_file,[])],N,N,Model,Model). | ||
|  | 
 | ||
|  | process_clauses([((H:-B),_V)|T],N,N2,Model0,Model1):- | ||
|  |         H=(db(A)),!, | ||
|  |   assert((A:-B)), | ||
|  |   process_clauses(T,N,N2,Model0,Model1). | ||
|  | 
 | ||
|  | process_clauses([((H:-B),V)|T],N,N2,Model0,[rule(N,V1,NH,HL,BL,0)|Model1]):- | ||
|  |   H=(_;_),!, | ||
|  |   list2or(HL1,H), | ||
|  |   process_head(HL1,HL,VI), | ||
|  |   list2and(BL0,B), | ||
|  |   add_int_atom(BL0,BL,VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   N1 is N+1, | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  | %  assertz(rule(N,V,NH,HL,BL)), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  | 
 | ||
|  | process_clauses([((H:-B),V)|T],N,N2,Model0,[rule(N,V1,NH,HL,BL,0)|Model1]):- | ||
|  |   H=(_:_),!, | ||
|  |   list2or(HL1,H), | ||
|  |   process_head(HL1,HL,VI), | ||
|  |   list2and(BL0,B), | ||
|  |   add_int_atom(BL0,BL,VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  |   N1 is N+1, | ||
|  | %  assertz(rule(N,V1,NH,HL,BL)), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  |    | ||
|  | process_clauses([((H:-B),V)|T],N,N2,Model0,[rule(N,V1,NH,HL,BL,0)|Model1]):-!, | ||
|  |   process_head([H:1.0],HL,VI), | ||
|  |   list2and(BL0,B), | ||
|  |   add_int_atom(BL0,BL,VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  |   N1 is N+1, | ||
|  | %  assertz(rule(N,V1,NH,HL,BL)), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  | 
 | ||
|  | process_clauses([(H,V)|T],N,N2,Model0,[rule(N,V1,NH,HL,[],0)|Model1]):- | ||
|  |   H=(_;_),!, | ||
|  |   list2or(HL1,H), | ||
|  |   process_head(HL1,HL,_VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  |   N1 is N+1, | ||
|  | %  assertz(rule(N,V,NH,HL,[])), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  | 
 | ||
|  | process_clauses([(H,V)|T],N,N2,Model0,[rule(N,V1,NH,HL,[],0)|Model1]):- | ||
|  |   H=(_:_),!, | ||
|  |   list2or(HL1,H), | ||
|  |   process_head(HL1,HL,_VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  |   N1 is N+1, | ||
|  | %  assertz(rule(N,V,NH,HL,[])), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  |    | ||
|  | process_clauses([(H,V)|T],N,N2,Model0,[rule(N,V1,NH,HL,[],0)|Model1]):- | ||
|  |   process_head([H:1.0],HL,_VI), | ||
|  |   length(HL,LH), | ||
|  |   listN(0,LH,NH), | ||
|  |   (setting(single_var,true)-> | ||
|  |     V1=[] | ||
|  |   ; | ||
|  |     V1=V | ||
|  |   ), | ||
|  |   N1 is N+1, | ||
|  | %  assertz(rule(N,V,NH,HL,[])), | ||
|  |   process_clauses(T,N1,N2,Model0,Model1). | ||
|  | 
 | ||
|  | 
 | ||
|  | /* if the annotation in the head are not ground, the null atom is not added | ||
|  | and the eventual formulas are not evaluated */ | ||
|  |    | ||
|  | process_head([H:P|T],NHL,VI):-!, | ||
|  |     process_head_prob([H:P|T],0.0,NHL,VI). | ||
|  | 
 | ||
|  | process_head(HL,NHL,VI):- | ||
|  |     process_head_random(HL,0.0,NHL,VI). | ||
|  | 
 | ||
|  | process_head_random([],P,['':PNull1],_VI):- | ||
|  |   PNull is 1.0-P, | ||
|  |   (PNull>=0.0-> | ||
|  |     PNull1 =PNull | ||
|  |   ; | ||
|  |     PNull1=0.0 | ||
|  |   ). | ||
|  |    | ||
|  | process_head_random([H|T],P,[H1:PH1|NT],VI):- | ||
|  |   add_int_atom([H],[H1],VI), | ||
|  |   PMax is 1.0-P, | ||
|  |   random(0,PMax,PH1), | ||
|  |   P1 is P+PH1,   | ||
|  |   process_head_random(T,P1,NT,VI). | ||
|  | 
 | ||
|  |      | ||
|  | process_head_prob([H:PH],P,[H1:PH1,'':PNull1],VI):- | ||
|  |   add_int_atom([H],[H1],VI), | ||
|  |   PH1 is PH, | ||
|  |   PNull is 1.0-P-PH1, | ||
|  |   (PNull>=0.0-> | ||
|  |     PNull1 =PNull | ||
|  |   ; | ||
|  |     PNull1=0.0 | ||
|  |   ). | ||
|  |    | ||
|  | process_head_prob([H:PH|T],P,[H1:PH1|NT],VI):- | ||
|  |   add_int_atom([H],[H1],VI), | ||
|  |   PH1 is PH, | ||
|  |   P1 is P+PH1, | ||
|  |   process_head_prob(T,P1,NT,VI). | ||
|  | 
 | ||
|  | 
 | ||
|  | add_int_atom([],[],_VI). | ||
|  | 
 | ||
|  | add_int_atom([\+ H|T],[\+ H|T1],VI):- | ||
|  |     inference:builtin(H),!, | ||
|  |   add_int_atom(T,T1,VI). | ||
|  | 
 | ||
|  | add_int_atom([\+ H|T],[\+ H1|T1],VI):-!, | ||
|  |   H=..[F|Args], | ||
|  |   H1=..[F,VI|Args], | ||
|  |   add_int_atom(T,T1,VI). | ||
|  | 
 | ||
|  | add_int_atom([H|T],[H|T1],VI):- | ||
|  |   inference:builtin(H),!, | ||
|  |   add_int_atom(T,T1,VI). | ||
|  | 
 | ||
|  | add_int_atom([H|T],[H1|T1],VI):- | ||
|  |   H=..[F|Args], | ||
|  |   H1=..[F,VI|Args], | ||
|  |   add_int_atom(T,T1,VI). | ||
|  | 
 | ||
|  | /* predicates for reading in the program clauses */ | ||
|  | read_clauses(S,Clauses):- | ||
|  |     read_clauses_ground_body(S,Clauses). | ||
|  | 
 | ||
|  | 
 | ||
|  | read_clauses_ground_body(S,[(Cl,V)|Out]):- | ||
|  |   read_term(S,Cl,[variable_names(V)]), | ||
|  |   (Cl=end_of_file-> | ||
|  |     Out=[] | ||
|  |   ; | ||
|  |     read_clauses_ground_body(S,Out) | ||
|  |   ). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    | ||
|  | listN(N,N,[]):-!. | ||
|  | 
 | ||
|  | listN(NIn,N,[NIn|T]):- | ||
|  |   N1 is NIn+1, | ||
|  |   listN(N1,N,T). | ||
|  | 
 | ||
|  | list0(N,N,[]):-!. | ||
|  | 
 | ||
|  | list0(NIn,N,[0|T]):- | ||
|  |   N1 is NIn+1, | ||
|  |   list0(N1,N,T). | ||
|  | 
 | ||
|  | /* end of predicates for parsing an input file containing a program */ | ||
|  | 
 | ||
|  | 
 | ||
|  | load_models(File,ModulesList):- | ||
|  |     open(File,read,Stream), | ||
|  |     read_models(Stream,ModulesList), | ||
|  |     close(Stream). | ||
|  |      | ||
|  | read_models(Stream,[Name1|Names]):- | ||
|  |     read(Stream,begin(model(Name))),!, | ||
|  |     (number(Name)-> | ||
|  |         name(Name,NameStr), | ||
|  |         append("i",NameStr,Name1Str), | ||
|  |         name(Name1,Name1Str) | ||
|  |     ; | ||
|  |         Name1=Name | ||
|  |     ), | ||
|  |     read_all_atoms(Stream,Name1), | ||
|  |     read_models(Stream,Names). | ||
|  | 
 | ||
|  | read_models(_S,[]). | ||
|  | 
 | ||
|  | read_all_atoms(Stream,Name):- | ||
|  |     read(Stream,At), | ||
|  |     At \=end(model(_Name)),!, | ||
|  |     (At=neg(Atom)->     | ||
|  |       Atom=..[Pred|Args], | ||
|  |       Atom1=..[Pred,Name|Args], | ||
|  |       assertz(neg(Atom1)) | ||
|  |     ; | ||
|  |       At=..[Pred|Args], | ||
|  |       Atom1=..[Pred,Name|Args], | ||
|  |       assertz(Atom1) | ||
|  |     ), | ||
|  |     read_all_atoms(Stream,Name).     | ||
|  | 
 | ||
|  | read_all_atoms(_S,_N). | ||
|  | 
 | ||
|  | 
 | ||
|  | list2or([],true):-!. | ||
|  | 
 | ||
|  | list2or([X],X):- | ||
|  |     X\=;(_,_),!. | ||
|  | 
 | ||
|  | list2or([H|T],(H ; Ta)):-!, | ||
|  |     list2or(T,Ta). | ||
|  | 
 | ||
|  | list2and([],true):-!. | ||
|  | 
 | ||
|  | list2and([X],X):- | ||
|  |     X\=(_,_),!. | ||
|  | 
 | ||
|  | list2and([H|T],(H,Ta)):-!, | ||
|  |     list2and(T,Ta). | ||
|  |      | ||
|  | 
 | ||
|  | write_model([],_Stream):-!. | ||
|  | 
 | ||
|  | write_model([rule(_N,_V,_NH,HL,BL,_LogF)|Rest],Stream):- | ||
|  |   copy_term((HL,BL),(HL1,BL1)), | ||
|  |     numbervars((HL1,BL1),0,_M), | ||
|  |     write_disj_clause(Stream,(HL1:-BL1)), | ||
|  |     format(Stream,".~n~n",[]), | ||
|  |     write_model(Rest,Stream). | ||
|  | 
 | ||
|  | 
 | ||
|  | write_disj_clause(S,(H:-[])):-!, | ||
|  |   write_head(S,H). | ||
|  |      | ||
|  | write_disj_clause(S,(H:-B)):- | ||
|  |   write_head(S,H), | ||
|  |   write(S,' :-'), | ||
|  |   nl(S), | ||
|  |   write_body(S,B). | ||
|  |    | ||
|  | write_head(S,[A:1.0|_Rest]):-!, | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"~p",[A1]). | ||
|  |    | ||
|  | write_head(S,[A:P,'':_P]):-!, | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"~p:~f",[A1,P]). | ||
|  | 
 | ||
|  | write_head(S,[A:P|Rest]):- | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"~p:~f ; ",[A1,P]), | ||
|  |     write_head(S,Rest). | ||
|  | 
 | ||
|  | write_body(S,[\+ A]):-!, | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"\t\\+ ~p",[A1]). | ||
|  | 
 | ||
|  | write_body(S,[A]):-!, | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"\t~p",[A1]). | ||
|  |      | ||
|  | write_body(S,[\+ A|T]):-!, | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"\t\\+ ~p,~n",[A1]), | ||
|  |     write_body(S,T). | ||
|  | 
 | ||
|  | write_body(S,[A|T]):- | ||
|  |   remove_int_atom(A,A1), | ||
|  |     format(S,"\t~p,~n",[A1]), | ||
|  |     write_body(S,T). | ||
|  | 
 | ||
|  |      | ||
|  | remove_int_atom(A,A1):- | ||
|  |   A=..[F,_|T], | ||
|  |   A1=..[F|T]. | ||
|  | 
 | ||
|  | build_ground_lpad([],[]):-!. | ||
|  | 
 | ||
|  | build_ground_lpad([(R,S)|T],[(R,S,Head,Body)|T1]):- | ||
|  |   user:rule_by_num(R,S,_,Head,Body), | ||
|  |   build_ground_lpad(T,T1). | ||
|  | 
 | ||
|  | 
 | ||
|  | remove_head([],[]). | ||
|  | 
 | ||
|  | remove_head([(_N,R,S)|T],[(R,S)|T1]):- | ||
|  |   remove_head(T,T1). | ||
|  | 
 | ||
|  | 
 | ||
|  | append_all([],L,L):-!. | ||
|  | 
 | ||
|  | append_all([LIntH|IntT],IntIn,IntOut):- | ||
|  |   append(IntIn,LIntH,Int1), | ||
|  |   append_all(IntT,Int1,IntOut). | ||
|  | 
 |