1174 lines
27 KiB
Prolog
1174 lines
27 KiB
Prolog
/*
|
|
LPAD and CP-Logic reasoning suite
|
|
File lpadclpbn.pl
|
|
Goal oriented interpreter for LPADs based on SLDNF
|
|
Copyright (c) 2008, Fabrizio Riguzzi
|
|
Inference is performed translating the portion of the LPAD related to the goal
|
|
into CLP(BN)
|
|
*/
|
|
|
|
:- module(lpadclpbn, [p/1,
|
|
s/2,sc/3,s/6,sc/7,set/2,setting/2]).
|
|
|
|
|
|
:-dynamic rule/4,def_rule/2,setting/2.
|
|
|
|
:-use_module(library(lists)).
|
|
:-use_module(library(ugraphs)).
|
|
:-use_module(library(avl)).
|
|
:-use_module(library(clpbn)).
|
|
|
|
:-set_clpbn_flag(suppress_attribute_display,true).
|
|
|
|
:-set_clpbn_flag(bnt_model,propositional).
|
|
|
|
/* start of list of parameters that can be set by the user with
|
|
set(Parameter,Value) */
|
|
setting(epsilon_parsing,0.00001).
|
|
setting(save_dot,false).
|
|
setting(ground_body,true).
|
|
/* available values: true, false
|
|
if true, both the head and the body of each clause will be grounded, otherwise
|
|
only the head is grounded. In the case in which the body contains variables
|
|
not appearing in the head, the body represents an existential event */
|
|
|
|
setting(cpt_zero,0.0001).
|
|
|
|
/* end of list of parameters */
|
|
|
|
/* s(GoalsList,Prob) compute the probability of a list of goals
|
|
GoalsLis can have variables, s returns in backtracking all the solutions with
|
|
their corresponding probability */
|
|
s(GL,P):-
|
|
setof(Deriv,find_deriv(GL,Deriv),LDup),!,
|
|
append_all(LDup,[],L),
|
|
remove_head(L,L1),
|
|
remove_duplicates(L1,L2),
|
|
build_ground_lpad(L2,0,CL),
|
|
convert_to_clpbn(CL,GL,LV,P).
|
|
|
|
s(_GL,0.0).
|
|
/* sc(GoalsList,EvidenceList,Prob) compute the probability of a list of goals
|
|
GoalsList given EvidenceList. Both lists can have variables, sc returns in
|
|
backtracking all the solutions with their corresponding probability
|
|
Time1 is the time for performing resolution
|
|
Time2 is the time for performing bayesian inference */
|
|
sc(GL,GLC,P):-
|
|
(setof(Deriv,find_deriv(GLC,Deriv),LDupC)->
|
|
(setof(Deriv,find_deriv(GL,Deriv),LDup)->
|
|
append_all(LDup,[],L),
|
|
remove_head(L,L1),
|
|
append_all(LDupC,[],LC),
|
|
remove_head(LC,LC1),
|
|
append(L1,LC1,LD),
|
|
remove_duplicates(LD,LD1),
|
|
build_ground_lpad(LD1,0,CL),
|
|
convert_to_clpbn(CL,GL,LV,P,GLC)
|
|
;
|
|
P=0.0
|
|
)
|
|
;
|
|
P=undef
|
|
).
|
|
|
|
|
|
|
|
/* s(GoalsList,Prob,Time1,Time2) compute the probability of a list of goals
|
|
GoalsLis can have variables, s returns in backtracking all the solutions with
|
|
their corresponding probability
|
|
Time1 is the time for performing resolution
|
|
Time2 is the time for performing bayesian inference */
|
|
s(GL,P,Time1,Time2):-
|
|
statistics(cputime,[_,_]),
|
|
statistics(walltime,[_,_]),
|
|
(setof(Deriv,find_deriv(GL,Deriv),LDup)->
|
|
append_all(LDup,[],L),
|
|
remove_head(L,L1),
|
|
remove_duplicates(L1,L2),
|
|
build_ground_lpad(L2,0,CL),
|
|
convert_to_clpbn(CL,GL,LV,P),
|
|
statistics(cputime,[_,CT2]),
|
|
Time1 is CT2/1000,
|
|
statistics(walltime,[_,WT2]),
|
|
Time2 is WT2/1000
|
|
;
|
|
P=0.0,
|
|
statistics(cputime,[_,CT1]),
|
|
Time1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
Time2 is WT1/1000
|
|
).
|
|
|
|
s(GoalsList,Prob,CPUTime1,CPUTime2,WallTime1,WallTime2):-
|
|
solve(GoalsList,Prob,CPUTime1,CPUTime2,WallTime1,WallTime2).
|
|
|
|
|
|
solve(GL,P,CPUTime1,CPUTime2,WallTime1,WallTime2):-
|
|
statistics(cputime,[_,_]),
|
|
statistics(walltime,[_,_]),
|
|
(setof(Deriv,find_deriv(GL,Deriv),LDup)->
|
|
append_all(LDup,[],L),
|
|
remove_head(L,L1),
|
|
remove_duplicates(L1,L2),
|
|
statistics(cputime,[_,CT1]),
|
|
CPUTime1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
WallTime1 is WT1/1000,
|
|
print_mem,
|
|
build_ground_lpad(L2,0,CL),
|
|
convert_to_clpbn(CL,GL,LV,P),
|
|
statistics(cputime,[_,CT2]),
|
|
CPUTime2 is CT2/1000,
|
|
statistics(walltime,[_,WT2]),
|
|
WallTime2 is WT2/1000
|
|
;
|
|
print_mem,
|
|
P=0.0,
|
|
statistics(cputime,[_,CT1]),
|
|
CPUTime1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
WallTime1 is WT1/1000,
|
|
CPUTime2 =0.0,
|
|
statistics(walltime,[_,WT2]),
|
|
WallTime2 =0.0
|
|
),!,
|
|
format(user_error,"Memory after inference~n",[]),
|
|
print_mem.
|
|
|
|
/* sc(GoalsList,EvidenceList,Prob) compute the probability of a list of goals
|
|
GoalsList given EvidenceList. Both lists can have variables, sc returns in
|
|
backtracking all the solutions with their corresponding probability */
|
|
|
|
sc(GL,GLC,P,CPUTime1,CPUTime2,WallTime1,WallTime2):-
|
|
statistics(cputime,[_,_]),
|
|
statistics(walltime,[_,_]),
|
|
(setof(Deriv,find_deriv(GLC,Deriv),LDupC)->
|
|
(setof(Deriv,find_deriv(GL,Deriv),LDup)->
|
|
append_all(LDup,[],L),
|
|
remove_head(L,L1),
|
|
append_all(LDupC,[],LC),
|
|
remove_head(LC,LC1),
|
|
append(L1,LC1,LD),
|
|
remove_duplicates(LD,LD1),
|
|
statistics(cputime,[_,CT1]),
|
|
CPUTime1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
WallTime1 is WT1/1000,
|
|
print_mem,
|
|
build_ground_lpad(LD1,0,CL),
|
|
convert_to_clpbn(CL,GL,LV,P,GLC),
|
|
statistics(cputime,[_,CT2]),
|
|
CPUTime2 is CT2/1000,
|
|
statistics(walltime,[_,WT2]),
|
|
WallTime2 is WT2/1000
|
|
;
|
|
P=0.0,
|
|
print_mem,
|
|
format(user_error,"Porb 0~n",[]),
|
|
statistics(cputime,[_,CT1]),
|
|
CPUTime1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
WallTime1 is WT1/1000,
|
|
CPUTime2 =0.0,
|
|
WallTime2 =0.0
|
|
)
|
|
;
|
|
P=undef,
|
|
print_mem,
|
|
statistics(cputime,[_,CT1]),
|
|
CPUTime1 is CT1/1000,
|
|
statistics(walltime,[_,WT1]),
|
|
WallTime1 is WT1/1000,
|
|
CPUTime2 =0.0,
|
|
WallTime2 =0.0,
|
|
print_mem,
|
|
format(user_error,"Undef~n",[])
|
|
),
|
|
format(user_error,"Memory after inference~n",[]),
|
|
print_mem.
|
|
|
|
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).
|
|
|
|
process_goals([],[],[]).
|
|
|
|
process_goals([H|T],[HG|TG],[HV|TV]):-
|
|
H=..[F,HV|Rest],
|
|
HG=..[F|Rest],
|
|
process_goals(T,TG,TV).
|
|
|
|
build_ground_lpad([],_N,[]).
|
|
|
|
build_ground_lpad([(R,S)|T],N,[(N1,Head1,Body1)|T1]):-
|
|
rule(R,S,_,Head,Body),
|
|
N1 is N+1,
|
|
merge_identical(Head,Head1),
|
|
remove_built_ins(Body,Body1),
|
|
build_ground_lpad(T,N1,T1).
|
|
|
|
remove_built_ins([],[]):-!.
|
|
|
|
remove_built_ins([\+H|T],T1):-
|
|
builtin(H),!,
|
|
remove_built_ins(T,T1).
|
|
|
|
remove_built_ins([H|T],T1):-
|
|
builtin(H),!,
|
|
remove_built_ins(T,T1).
|
|
|
|
remove_built_ins([H|T],[H|T1]):-
|
|
remove_built_ins(T,T1).
|
|
|
|
merge_identical([],[]):-!.
|
|
|
|
merge_identical([A:P|T],[A:P1|Head]):-
|
|
find_identical(A,P,T,P1,T1),
|
|
merge_identical(T1,Head).
|
|
|
|
find_identical(_A,P,[],P,[]):-!.
|
|
|
|
find_identical(A,P0,[A:P|T],P1,T1):-!,
|
|
P2 is P0+P,
|
|
find_identical(A,P2,T,P1,T1).
|
|
|
|
find_identical(A,P0,[H:P|T],P1,[H:P|T1]):-
|
|
find_identical(A,P0,T,P1,T1).
|
|
|
|
convert_to_clpbn(CL,GL,LV,P,GLC):-
|
|
find_ground_atoms(CL,[],GAD),
|
|
remove_duplicates(GAD,GANull),
|
|
delete(GANull,'',GA),
|
|
atom_vars(GA,[],AV,AVL),
|
|
choice_vars(CL,[],CV,CVL),
|
|
add_rule_tables(CL,CVL,AV),
|
|
add_atoms_tables(AVL,GA,CL,CV,AV),
|
|
add_ev(GLC,AV),
|
|
get_prob(GL,AV,AVL,CVL,P).
|
|
|
|
add_ev([],_AV).
|
|
|
|
add_ev([\+ H|T],AV):-!,
|
|
avl_lookup(H,V,AV),
|
|
clpbn:put_atts(V,evidence(0)),
|
|
add_ev(T,AV).
|
|
|
|
add_ev([H|T],AV):-
|
|
avl_lookup(H,V,AV),
|
|
clpbn:put_atts(V,evidence(1)),
|
|
add_ev(T,AV).
|
|
|
|
convert_to_clpbn(CL,GL,LV,P):-
|
|
find_ground_atoms(CL,[],GAD),
|
|
remove_duplicates(GAD,GANull),
|
|
delete(GANull,'',GA),
|
|
atom_vars(GA,[],AV,AVL),
|
|
choice_vars(CL,[],CV,CVL),
|
|
add_rule_tables(CL,CVL,AV),
|
|
add_atoms_tables(AVL,GA,CL,CV,AV),
|
|
get_prob(GL,AV,AVL,CVL,P).
|
|
|
|
get_prob(GL,AV,AVL,CVL,P):-
|
|
build_table_conj(GL,Table),
|
|
find_atoms_body(GL,Atoms),
|
|
lookup_gvars(GL,AV,Parents,[],_Signs),
|
|
{G=goal with p([f,t],Table, Parents)},
|
|
append(AVL,CVL,Vars),
|
|
append(Vars,[G],Vars1),
|
|
clpbn:clpbn_run_solver([G], Vars1,_State),
|
|
clpbn_display:get_atts(G, [posterior(Vs,Vals,[_P0,P],AllDiffs)]).
|
|
|
|
lookup_gvars([],_AV,[],S,S).
|
|
|
|
lookup_gvars([\+ H|T],AV,[HV|T1],Sign0,Sign2):- !,
|
|
avl_lookup(H,HV,AV),
|
|
clpbn:get_atts(HV, [key(K)]),
|
|
avl_insert(K,f,Sign0,Sign1),
|
|
lookup_gvars(T,AV,T1,Sign1,Sign2).
|
|
|
|
lookup_gvars([H|T],AV,[HV|T1],Sign0,Sign2):-
|
|
avl_lookup(H,HV,AV),
|
|
clpbn:get_atts(HV, [key(K)]),
|
|
avl_insert(K,t,Sign0,Sign1),
|
|
lookup_gvars(T,AV,T1,Sign1,Sign2).
|
|
|
|
add_atoms_tables([],[],_CL,_CV,_AV).
|
|
|
|
add_atoms_tables([H|T],[HA|TA],CL,CV,AV):-
|
|
find_rules_with_atom(HA,CL,R),
|
|
parents(R,CV,Par),
|
|
build_table_atoms(HA,R,Table),
|
|
{H = HA with p([f,t],Table,Par)},
|
|
add_atoms_tables(T,TA,CL,CV,AV).
|
|
|
|
build_table_conj(R,Table):-
|
|
build_col_conj(R,t,f,[],Row1),
|
|
build_col_conj(R,t,t,Row1,Table).
|
|
|
|
build_col_conj([],Tr,Final,Row0,Row1):-
|
|
(Tr=Final->
|
|
append(Row0,[1.0],Row1)
|
|
;
|
|
setting(cpt_zero,Zero),
|
|
append(Row0,[Zero],Row1)
|
|
).
|
|
|
|
build_col_conj([\+H|RP],Tr,Final,Row0,Row2):-!,
|
|
build_col_conj(RP,Tr,Final,Row0,Row1),
|
|
build_col_conj(RP,f,Final,Row1,Row2).
|
|
|
|
build_col_conj([H|RP],Tr,Final,Row0,Row2):-
|
|
build_col_conj(RP,f,Final,Row0,Row1),
|
|
build_col_conj(RP,Tr,Final,Row1,Row2).
|
|
|
|
build_table_atoms(H,R,Table):-
|
|
build_col(H,R,f,f,[],Row1),
|
|
build_col(H,R,t,f,Row1,Table).
|
|
|
|
build_col(A,[],Tr,Found,Row0,Row1):-
|
|
(Tr=Found->
|
|
append(Row0,[1.0],Row1)
|
|
;
|
|
setting(cpt_zero,Zero),
|
|
append(Row0,[Zero],Row1)
|
|
).
|
|
|
|
build_col(A,[(N,H)|RP],Tr,Found,Row0,Row1):-
|
|
build_col_cycle(A,H,RP,Tr,Found,Row0,Row1).
|
|
|
|
build_col_cycle(_A,[],_RP,_Tr,_Found,Row,Row).
|
|
|
|
build_col_cycle(A,[A:P|T],RP,Tr,Found,Row0,Row2):-!,
|
|
build_col(A,RP,Tr,t,Row0,Row1),
|
|
build_col_cycle(A,T,RP,Tr,Found,Row1,Row2).
|
|
|
|
build_col_cycle(A,[_|T],RP,Tr,Found,Row0,Row2):-
|
|
build_col(A,RP,Tr,Found,Row0,Row1),
|
|
build_col_cycle(A,T,RP,Tr,Found,Row1,Row2).
|
|
|
|
parents([],_CV,[]).
|
|
|
|
parents([(N,_H)|T],CV,[V|T1]):-
|
|
avl_lookup(N,V,CV),
|
|
parents(T,CV,T1).
|
|
|
|
find_rules_with_atom(_A,[],[]).
|
|
|
|
find_rules_with_atom(A,[(N,Head,Body)|T],[(N,Head)|R]):-
|
|
member(A:P,Head),!,
|
|
find_rules_with_atom(A,T,R).
|
|
|
|
find_rules_with_atom(A,[_H|T],R):-
|
|
find_rules_with_atom(A,T,R).
|
|
|
|
add_rule_tables([],[],_AV).
|
|
|
|
add_rule_tables([(N,Head,Body)|T],[CV|TCV],AV):-
|
|
find_atoms_head(Head,Atoms,Probs),
|
|
get_parents(Body,AV,Par),
|
|
build_table(Probs,Body,Table),
|
|
{CV=ch(N) with p(Atoms,Table,Par)},
|
|
add_rule_tables(T,TCV,AV).
|
|
|
|
build_table([P],L,Row):-!,
|
|
build_col(L,t,P,1.0,Row).
|
|
|
|
build_table([HP|TP],L,Tab):-
|
|
setting(cpt_zero,Zero),
|
|
build_col(L,t,HP,Zero,Row),
|
|
append(Row,Row1,Tab),
|
|
build_table(TP,L,Row1).
|
|
|
|
build_col([],t,HP,_PNull,[HP]):-!.
|
|
|
|
build_col([],f,_HP,PNull,[PNull]):-!.
|
|
|
|
|
|
build_col([\+ H|T],Truth,P,PNull,Row):-!,
|
|
build_col(T,Truth,P,PNull,Row1),
|
|
append(Row1,Row2,Row),
|
|
build_col(T,f,P,PNull,Row2).
|
|
|
|
build_col([_H|T],Truth,P,PNull,Row):-
|
|
build_col(T,f,P,PNull,Row1),
|
|
append(Row1,Row2,Row),
|
|
build_col(T,Truth,P,PNull,Row2).
|
|
|
|
get_parents([],_AV,[]).
|
|
|
|
get_parents([\+ H|T],AV,[V|T1]):-!,
|
|
avl_lookup(H,V,AV),
|
|
get_parents(T,AV,T1).
|
|
|
|
get_parents([H|T],AV,[V|T1]):-!,
|
|
avl_lookup(H,V,AV),
|
|
get_parents(T,AV,T1).
|
|
|
|
choice_vars([],Tr,Tr,[]).
|
|
|
|
choice_vars([(N,_H,_B)|T],Tr0,Tr1,[NV|T1]):-
|
|
avl_insert(N,NV,Tr0,Tr2),
|
|
choice_vars(T,Tr2,Tr1,T1).
|
|
|
|
atom_vars([],Tr,Tr,[]).
|
|
|
|
atom_vars([H|T],Tr0,Tr1,[VH|VT]):-
|
|
avl_insert(H,VH,Tr0,Tr2),
|
|
atom_vars(T,Tr2,Tr1,VT).
|
|
|
|
find_ground_atoms([],GA,GA).
|
|
|
|
find_ground_atoms([(_N,Head,Body)|T],GA0,GA1):-
|
|
find_atoms_head(Head,AtH,_P),
|
|
append(GA0,AtH,GA2),
|
|
find_atoms_body(Body,AtB),
|
|
append(GA2,AtB,GA3),
|
|
find_ground_atoms(T,GA3,GA1).
|
|
|
|
find_atoms_body([],[]).
|
|
|
|
find_atoms_body([\+H|T],[H|T1]):-!,
|
|
find_atoms_body(T,T1).
|
|
|
|
find_atoms_body([H|T],[H|T1]):-
|
|
find_atoms_body(T,T1).
|
|
|
|
|
|
find_atoms_head([],[],[]).
|
|
|
|
find_atoms_head([H:P|T],[H|TA],[P|TP]):-
|
|
find_atoms_head(T,TA,TP).
|
|
|
|
print_mem:-
|
|
statistics(global_stack,[GS,GSF]),
|
|
statistics(local_stack,[LS,LSF]),
|
|
statistics(heap,[HP,HPF]),
|
|
statistics(trail,[TU,TF]),
|
|
format(user_error,"~nGloabal stack used ~d execution stack free: ~d~n",[GS,GSF]),
|
|
format(user_error,"Local stack used ~d execution stack free: ~d~n",[LS,LSF]),
|
|
format(user_error,"Heap used ~d heap free: ~d~n",[HP,HPF]),
|
|
format(user_error,"Trail used ~d Trail free: ~d~n",[TU,TF]).
|
|
|
|
find_deriv(GoalsList,Deriv):-
|
|
solve(GoalsList,[],DerivDup),
|
|
remove_duplicates(DerivDup,Deriv).
|
|
/* duplicate can appear in the C set because two different unistantiated clauses may become the
|
|
same clause when instantiated */
|
|
|
|
|
|
|
|
/* solve(GoalsList,CIn,COut) takes a list of goals and an input C set
|
|
and returns an output C set
|
|
The C set is a list of triple (N,R,S) where
|
|
- N is the index of the head atom used, starting from 0
|
|
- R is the index of the non ground rule used, starting from 1
|
|
- S is the substitution of rule R, in the form of a list whose elements
|
|
are of the form 'VarName'=value
|
|
*/
|
|
solve([],C,C):-!.
|
|
|
|
solve([bagof(V,EV^G,L)|T],CIn,COut):-!,
|
|
list2and(GL,G),
|
|
bagof((V,C),EV^solve(GL,CIn,C),LD),
|
|
length(LD,N),
|
|
build_initial_graph(N,GrIn),
|
|
build_graph(LD,0,GrIn,Gr),
|
|
clique(Gr,Clique),
|
|
build_Cset(LD,Clique,L,[],C1),
|
|
remove_duplicates_eq(C1,C2),
|
|
solve(T,C2,COut).
|
|
|
|
solve([bagof(V,G,L)|T],CIn,COut):-!,
|
|
list2and(GL,G),
|
|
bagof((V,C),solve(GL,CIn,C),LD),
|
|
length(LD,N),
|
|
build_initial_graph(N,GrIn),
|
|
build_graph(LD,0,GrIn,Gr),
|
|
clique(Gr,Clique),
|
|
build_Cset(LD,Clique,L,[],C1),
|
|
remove_duplicates_eq(C1,C2),
|
|
solve(T,C2,COut).
|
|
|
|
|
|
solve([setof(V,EV^G,L)|T],CIn,COut):-!,
|
|
list2and(GL,G),
|
|
setof((V,C),EV^solve(GL,CIn,C),LD),
|
|
length(LD,N),
|
|
build_initial_graph(N,GrIn),
|
|
build_graph(LD,0,GrIn,Gr),
|
|
clique(Gr,Clique),
|
|
build_Cset(LD,Clique,L1,[],C1),
|
|
remove_duplicates(L1,L),
|
|
solve(T,C1,COut).
|
|
|
|
solve([setof(V,G,L)|T],CIn,COut):-!,
|
|
list2and(GL,G),
|
|
setof((V,C),solve(GL,CIn,C),LD),
|
|
length(LD,N),
|
|
build_initial_graph(N,GrIn),
|
|
build_graph(LD,0,GrIn,Gr),
|
|
clique(Gr,Clique),
|
|
build_Cset(LD,Clique,L1,[],C1),
|
|
remove_duplicates(L1,L),
|
|
solve(T,C1,COut).
|
|
|
|
solve([\+ H |T],CIn,COut):-!,
|
|
list2and(HL,H),
|
|
(setof(D,find_deriv(HL,D),LDup)->
|
|
rem_dup_lists(LDup,[],L),
|
|
choose_clauses(CIn,L,C1),
|
|
solve(T,C1,COut)
|
|
;
|
|
solve(T,CIn,COut)
|
|
).
|
|
|
|
solve([H|T],CIn,COut):-
|
|
builtin(H),!,
|
|
call(H),
|
|
solve(T,CIn,COut).
|
|
|
|
solve([H|T],CIn,COut):-
|
|
def_rule(H,B),
|
|
append(B,T,NG),
|
|
solve(NG,CIn,COut).
|
|
|
|
solve([H|T],CIn,COut):-
|
|
find_rule(H,(R,S,N),B,CIn),
|
|
solve_pres(R,S,N,B,T,CIn,COut).
|
|
|
|
solve_pres(R,S,N,B,T,CIn,COut):-
|
|
member_eq((N,R,S),CIn),!,
|
|
append(B,T,NG),
|
|
solve(NG,CIn,COut).
|
|
|
|
solve_pres(R,S,N,B,T,CIn,COut):-
|
|
append(CIn,[(N,R,S)],C1),
|
|
append(B,T,NG),
|
|
solve(NG,C1,COut).
|
|
|
|
build_initial_graph(N,G):-
|
|
listN(0,N,Vert),
|
|
add_vertices([],Vert,G).
|
|
|
|
|
|
build_graph([],_N,G,G).
|
|
|
|
build_graph([(_V,C)|T],N,GIn,GOut):-
|
|
N1 is N+1,
|
|
compatible(C,T,N,N1,GIn,G1),
|
|
build_graph(T,N1,G1,GOut).
|
|
|
|
compatible(_C,[],_N,_N1,G,G).
|
|
|
|
compatible(C,[(_V,H)|T],N,N1,GIn,GOut):-
|
|
(compatible(C,H)->
|
|
add_edges(GIn,[N-N1,N1-N],G1)
|
|
;
|
|
G1=GIn
|
|
),
|
|
N2 is N1 +1,
|
|
compatible(C,T,N,N2,G1,GOut).
|
|
|
|
compatible([],_C).
|
|
|
|
compatible([(N,R,S)|T],C):-
|
|
not_present_with_a_different_head(N,R,S,C),
|
|
compatible(T,C).
|
|
|
|
not_present_with_a_different_head(_N,_R,_S,[]).
|
|
|
|
not_present_with_a_different_head(N,R,S,[(N,R,S)|T]):-!,
|
|
not_present_with_a_different_head(N,R,S,T).
|
|
|
|
not_present_with_a_different_head(N,R,S,[(_N1,R,S1)|T]):-
|
|
S\=S1,!,
|
|
not_present_with_a_different_head(N,R,S,T).
|
|
|
|
not_present_with_a_different_head(N,R,S,[(_N1,R1,_S1)|T]):-
|
|
R\=R1,
|
|
not_present_with_a_different_head(N,R,S,T).
|
|
|
|
|
|
|
|
build_Cset(_LD,[],[],C,C).
|
|
|
|
build_Cset(LD,[H|T],[V|L],CIn,COut):-
|
|
nth0(H,LD,(V,C)),
|
|
append(C,CIn,C1),
|
|
build_Cset(LD,T,L,C1,COut).
|
|
|
|
|
|
/* find_rule(G,(R,S,N),Body,C) takes a goal G and the current C set and
|
|
returns the index R of a disjunctive rule resolving with G together with
|
|
the index N of the resolving head, the substitution S and the Body of the
|
|
rule */
|
|
find_rule(H,(R,S,N),Body,C):-
|
|
rule(R,S,_,Head,Body),
|
|
member_head(H,Head,0,N),
|
|
not_already_present_with_a_different_head(N,R,S,C).
|
|
|
|
find_rule(H,(R,S,Number),Body,C):-
|
|
rule(R,S,_,uniform(H:1/_Num,_P,Number),Body),
|
|
not_already_present_with_a_different_head(Number,R,S,C).
|
|
|
|
not_already_present_with_a_different_head(_N,_R,_S,[]).
|
|
|
|
not_already_present_with_a_different_head(N,R,S,[(N1,R,S1)|T]):-
|
|
not_different(N,N1,S,S1),!,
|
|
not_already_present_with_a_different_head(N,R,S,T).
|
|
|
|
not_already_present_with_a_different_head(N,R,S,[(_N1,R1,_S1)|T]):-
|
|
R\==R1,
|
|
not_already_present_with_a_different_head(N,R,S,T).
|
|
|
|
not_different(_N,_N1,S,S1):-
|
|
S\=S1,!.
|
|
|
|
not_different(N,N1,S,S1):-
|
|
N\=N1,!,
|
|
dif(S,S1).
|
|
|
|
not_different(N,N,S,S).
|
|
|
|
|
|
member_head(H,[(H:_P)|_T],N,N).
|
|
|
|
member_head(H,[(_H:_P)|T],NIn,NOut):-
|
|
N1 is NIn+1,
|
|
member_head(H,T,N1,NOut).
|
|
|
|
/* choose_clauses(CIn,LC,COut) takes as input the current C set and
|
|
the set of C sets for a negative goal and returns a new C set that
|
|
excludes all the derivations for the negative goals */
|
|
choose_clauses(C,[],C).
|
|
|
|
choose_clauses(CIn,[D|T],COut):-
|
|
member((N,R,S),D),
|
|
already_present_with_a_different_head(N,R,S,CIn),!,
|
|
choose_a_head(N,R,S,CIn,C1),
|
|
choose_clauses(C1,T,COut).
|
|
|
|
|
|
choose_clauses(CIn,[D|T],COut):-
|
|
member((N,R,S),D),
|
|
new_head(N,R,S,N1),
|
|
\+ already_present(N1,R,S,CIn),
|
|
impose_dif_cons(R,S,CIn),
|
|
choose_clauses([(N1,R,S)|CIn],T,COut).
|
|
|
|
impose_dif_cons(_R,_S,[]):-!.
|
|
|
|
impose_dif_cons(R,S,[(_NH,R,SH)|T]):-!,
|
|
dif(S,SH),
|
|
impose_dif_cons(R,S,T).
|
|
|
|
impose_dif_cons(R,S,[_H|T]):-
|
|
impose_dif_cons(R,S,T).
|
|
|
|
/* instantiation_present_with_the_same_head(N,R,S,C)
|
|
takes rule R with substitution S and selected head N and a C set
|
|
and asserts dif constraints for all the clauses in C of which RS
|
|
is an instantitation and have the same head selected */
|
|
instantiation_present_with_the_same_head(_N,_R,_S,[]).
|
|
|
|
instantiation_present_with_the_same_head(N,R,S,[(NH,R,SH)|T]):-
|
|
\+ \+ S=SH,!,
|
|
dif_head_or_subs(N,R,S,NH,SH,T).
|
|
|
|
instantiation_present_with_the_same_head(N,R,S,[_H|T]):-
|
|
instantiation_present_with_the_same_head(N,R,S,T).
|
|
|
|
dif_head_or_subs(N,R,S,NH,_SH,T):-
|
|
dif(N,NH),
|
|
instantiation_present_with_the_same_head(N,R,S,T).
|
|
|
|
dif_head_or_subs(N,R,S,N,SH,T):-
|
|
dif(S,SH),
|
|
instantiation_present_with_the_same_head(N,R,S,T).
|
|
|
|
/* case 1 of Select: a more general rule is present in C with
|
|
a different head, instantiate it */
|
|
choose_a_head(N,R,S,[(NH,R,SH)|T],[(NH,R,SH)|T]):-
|
|
S=SH,
|
|
dif(N,NH).
|
|
|
|
/* case 2 of Select: a more general rule is present in C with
|
|
a different head, ensure that they do not generate the same
|
|
ground clause */
|
|
choose_a_head(N,R,S,[(NH,R,SH)|T],[(NH,R,S),(NH,R,SH)|T]):-
|
|
\+ \+ S=SH, S\==SH,
|
|
dif(N,NH),
|
|
dif(S,SH).
|
|
|
|
choose_a_head(N,R,S,[H|T],[H|T1]):-
|
|
choose_a_head(N,R,S,T,T1).
|
|
|
|
/* select a head different from N for rule R with
|
|
substitution S, return it in N1 */
|
|
new_head(N,R,S,N1):-
|
|
rule(R,S,Numbers,Head,_Body),
|
|
Head\=uniform(_,_,_),!,
|
|
nth0(N, Numbers, _Elem, Rest),
|
|
member(N1,Rest).
|
|
|
|
new_head(N,R,S,N1):-
|
|
rule(R,S,Numbers,uniform(_A:1/Tot,_L,_Number),_Body),
|
|
listN(0,Tot,Numbers),
|
|
nth0(N, Numbers, _Elem, Rest),
|
|
member(N1,Rest).
|
|
|
|
already_present_with_a_different_head(N,R,S,[(NH,R,SH)|_T]):-
|
|
\+ \+ S=SH,NH \= N.
|
|
|
|
already_present_with_a_different_head(N,R,S,[_H|T]):-
|
|
already_present_with_a_different_head(N,R,S,T).
|
|
|
|
|
|
/* checks that a rule R with head N and selection S is already
|
|
present in C (or a generalization of it is in C) */
|
|
already_present(N,R,S,[(N,R,SH)|_T]):-
|
|
S=SH.
|
|
|
|
already_present(N,R,S,[_H|T]):-
|
|
already_present(N,R,S,T).
|
|
|
|
/* rem_dup_lists removes the C sets that are a superset of
|
|
another C sets further on in the list of C sets */
|
|
/* rem_dup_lists removes the C sets that are a superset of
|
|
another C sets further on in the list of C sets */
|
|
rem_dup_lists([],L,L).
|
|
|
|
rem_dup_lists([H|T],L0,L):-
|
|
(member_subset(H,T);member_subset(H,L0)),!,
|
|
rem_dup_lists(T,L0,L).
|
|
|
|
rem_dup_lists([H|T],L0,L):-
|
|
rem_dup_lists(T,[H|L0],L).
|
|
|
|
member_subset(E,[H|_T]):-
|
|
subset_my(H,E),!.
|
|
|
|
member_subset(E,[_H|T]):-
|
|
member_subset(E,T).
|
|
|
|
|
|
|
|
/* predicates for building the formula to be converted into a BDD */
|
|
|
|
/* 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).
|
|
|
|
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([(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(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).
|
|
|
|
/* end of predicates for building the formula to be converted into a BDD */list_el(0,_P,[]):-!.
|
|
|
|
|
|
/* start of predicates for parsing an input file containing a program */
|
|
|
|
/* p(File) parses the file File.cpl. It can be called more than once without
|
|
exiting yap */
|
|
p(File):-
|
|
parse(File).
|
|
|
|
parse(File):-
|
|
atom_concat(File,'.cpl',FilePl),
|
|
open(FilePl,read,S),
|
|
read_clauses(S,C),
|
|
close(S),
|
|
retractall(rule(_,_,_,_,_)),
|
|
retractall(def_rule(_,_)),
|
|
process_clauses(C,1).
|
|
|
|
process_clauses([(end_of_file,[])],_N).
|
|
|
|
process_clauses([((H:-B),V)|T],N):-
|
|
H=uniform(A,P,L),!,
|
|
list2and(BL,B),
|
|
process_body(BL,V,V1),
|
|
remove_vars([P],V1,V2),
|
|
append(BL,[length(L,Tot),nth0(Number,L,P)],BL1),
|
|
append(V2,['Tot'=Tot],V3),
|
|
assertz(rule(N,V3,_NH,uniform(A:1/Tot,L,Number),BL1)),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([((H:-B),V)|T],N):-
|
|
H=(_;_),!,
|
|
list2or(HL1,H),
|
|
process_head(HL1,HL),
|
|
list2and(BL,B),
|
|
process_body(BL,V,V1),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V1,NH,HL,BL)),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([((H:-B),V)|T],N):-
|
|
H=(_:_),!,
|
|
list2or(HL1,H),
|
|
process_head(HL1,HL),
|
|
list2and(BL,B),
|
|
process_body(BL,V,V1),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V1,NH,HL,BL)),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([((H:-B),V)|T],N):-!,
|
|
process_head([H:1.0],HL),
|
|
list2and(BL,B),
|
|
process_body(BL,V,V1),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V1,NH,HL,BL)),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([(H,V)|T],N):-
|
|
H=(_;_),!,
|
|
list2or(HL1,H),
|
|
process_head(HL1,HL),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V,NH,HL,[])),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([(H,V)|T],N):-
|
|
H=(_:_),!,
|
|
list2or(HL1,H),
|
|
process_head(HL1,HL),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V,NH,HL,[])),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
process_clauses([(H,V)|T],N):-
|
|
process_head([H:1.0],HL),
|
|
length(HL,LH),
|
|
listN(0,LH,NH),
|
|
assertz(rule(N,V,NH,HL,[])),
|
|
N1 is N+1,
|
|
process_clauses(T,N1).
|
|
|
|
/* if the annotation in the head are not ground, the null atom is not added
|
|
and the eventual formulas are not evaluated */
|
|
|
|
process_head(HL,NHL):-
|
|
(ground_prob(HL)->
|
|
process_head_ground(HL,0.0,NHL)
|
|
;
|
|
NHL=HL
|
|
).
|
|
|
|
ground_prob([]).
|
|
|
|
ground_prob([_H:PH|T]):-
|
|
ground(PH),
|
|
ground_prob(T).
|
|
|
|
process_head_ground([H:PH],P,[H:PH1,'':PNull1]):-!,
|
|
PH1 is PH,
|
|
PNull is 1.0-P-PH1,
|
|
(PNull>=0.0->
|
|
PNull1 =PNull
|
|
;
|
|
PNull1=0.0
|
|
).
|
|
|
|
process_head_ground([H:PH|T],P,[H:PH1|NT]):-
|
|
PH1 is PH,
|
|
P1 is P+PH1,
|
|
process_head_ground(T,P1,NT).
|
|
|
|
/* setof must have a goal of the form B^G where B is a term containing the existential variables */
|
|
process_body([],V,V).
|
|
|
|
process_body([setof(A,B^_G,_L)|T],VIn,VOut):-!,
|
|
get_var(A,VA),
|
|
get_var(B,VB),
|
|
remove_vars(VA,VIn,V1),
|
|
remove_vars(VB,V1,V2),
|
|
process_body(T,V2,VOut).
|
|
|
|
process_body([setof(A,_G,_L)|T],VIn,VOut):-!,
|
|
get_var(A,VA),
|
|
remove_vars(VA,VIn,V1),
|
|
process_body(T,V1,VOut).
|
|
|
|
process_body([bagof(A,B^_G,_L)|T],VIn,VOut):-!,
|
|
get_var(A,VA),
|
|
get_var(B,VB),
|
|
remove_vars(VA,VIn,V1),
|
|
remove_vars(VB,V1,V2),
|
|
process_body(T,V2,VOut).
|
|
|
|
process_body([bagof(A,_G,_L)|T],VIn,VOut):-!,
|
|
get_var(A,VA),
|
|
remove_vars(VA,VIn,V1),
|
|
process_body(T,V1,VOut).
|
|
|
|
process_body([_H|T],VIn,VOut):-!,
|
|
process_body(T,VIn,VOut).
|
|
|
|
get_var_list([],[]).
|
|
|
|
get_var_list([H|T],[H|T1]):-
|
|
var(H),!,
|
|
get_var_list(T,T1).
|
|
|
|
get_var_list([H|T],VarOut):-!,
|
|
get_var(H,Var),
|
|
append(Var,T1,VarOut),
|
|
get_var_list(T,T1).
|
|
|
|
get_var(A,[A]):-
|
|
var(A),!.
|
|
|
|
get_var(A,V):-
|
|
A=..[_F|Args],
|
|
get_var_list(Args,V).
|
|
|
|
remove_vars([],V,V).
|
|
|
|
remove_vars([H|T],VIn,VOut):-
|
|
delete_var(H,VIn,V1),
|
|
remove_vars(T,V1,VOut).
|
|
|
|
delete_var(_H,[],[]).
|
|
|
|
delete_var(V,[VN=Var|T],[VN=Var|T1]):-
|
|
V\==Var,!,
|
|
delete_var(V,T,T1).
|
|
|
|
delete_var(_V,[_H|T],T).
|
|
|
|
/* predicates for reading in the program clauses */
|
|
read_clauses(S,Clauses):-
|
|
(setting(ground_body,true)->
|
|
read_clauses_ground_body(S,Clauses)
|
|
;
|
|
read_clauses_exist_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)
|
|
).
|
|
|
|
|
|
read_clauses_exist_body(S,[(Cl,V)|Out]):-
|
|
read_term(S,Cl,[variable_names(VN)]),
|
|
extract_vars_cl(Cl,VN,V),
|
|
(Cl=end_of_file->
|
|
Out=[]
|
|
;
|
|
read_clauses_exist_body(S,Out)
|
|
).
|
|
|
|
|
|
extract_vars_cl(end_of_file,[]).
|
|
|
|
extract_vars_cl(Cl,VN,Couples):-
|
|
(Cl=(H:-_B)->
|
|
true
|
|
;
|
|
H=Cl
|
|
),
|
|
extract_vars(H,[],V),
|
|
pair(VN,V,Couples).
|
|
|
|
|
|
pair(_VN,[],[]).
|
|
|
|
pair([VN= _V|TVN],[V|TV],[VN=V|T]):-
|
|
pair(TVN,TV,T).
|
|
|
|
|
|
extract_vars(Var,V0,V):-
|
|
var(Var),!,
|
|
(member_eq(Var,V0)->
|
|
V=V0
|
|
;
|
|
append(V0,[Var],V)
|
|
).
|
|
|
|
extract_vars(Term,V0,V):-
|
|
Term=..[_F|Args],
|
|
extract_vars_list(Args,V0,V).
|
|
|
|
|
|
extract_vars_list([],V,V).
|
|
|
|
extract_vars_list([Term|T],V0,V):-
|
|
extract_vars(Term,V0,V1),
|
|
extract_vars_list(T,V1,V).
|
|
|
|
|
|
listN(N,N,[]):-!.
|
|
|
|
listN(NIn,N,[NIn|T]):-
|
|
N1 is NIn+1,
|
|
listN(N1,N,T).
|
|
/* end of predicates for parsing an input file containing a program */
|
|
|
|
/* start of utility predicates */
|
|
list2or([X],X):-
|
|
X\=;(_,_),!.
|
|
|
|
list2or([H|T],(H ; Ta)):-!,
|
|
list2or(T,Ta).
|
|
|
|
list2and([X],X):-
|
|
X\=(_,_),!.
|
|
|
|
list2and([H|T],(H,Ta)):-!,
|
|
list2and(T,Ta).
|
|
|
|
member_eq(A,[H|_T]):-
|
|
A==H,!.
|
|
|
|
member_eq(A,[_H|T]):-
|
|
member_eq(A,T).
|
|
|
|
subset_my([],_).
|
|
|
|
subset_my([H|T],L):-
|
|
member_eq(H,L),
|
|
subset_my(T,L).
|
|
|
|
remove_duplicates_eq([],[]).
|
|
|
|
remove_duplicates_eq([H|T],T1):-
|
|
member_eq(H,T),!,
|
|
remove_duplicates_eq(T,T1).
|
|
|
|
remove_duplicates_eq([H|T],[H|T1]):-
|
|
remove_duplicates_eq(T,T1).
|
|
|
|
builtin(_A is _B).
|
|
builtin(_A > _B).
|
|
builtin(_A < _B).
|
|
builtin(_A >= _B).
|
|
builtin(_A =< _B).
|
|
builtin(_A =:= _B).
|
|
builtin(_A =\= _B).
|
|
builtin(true).
|
|
builtin(false).
|
|
builtin(_A = _B).
|
|
builtin(_A==_B).
|
|
builtin(_A\=_B).
|
|
builtin(_A\==_B).
|
|
builtin(length(_L,_N)).
|
|
builtin(member(_El,_L)).
|
|
builtin(average(_L,_Av)).
|
|
builtin(max_list(_L,_Max)).
|
|
builtin(min_list(_L,_Max)).
|
|
builtin(nth0(_,_,_)).
|
|
builtin(nth(_,_,_)).
|
|
average(L,Av):-
|
|
sum_list(L,Sum),
|
|
length(L,N),
|
|
Av is Sum/N.
|
|
|
|
clique(Graph,Clique):-
|
|
vertices(Graph,Candidates),
|
|
extend_cycle(Graph,Candidates,[],[],Clique).
|
|
|
|
extend_cycle(G,[H|T],Not,CS,CSOut):-
|
|
neighbours(H, G, Neigh),
|
|
intersection(Neigh,T,NewCand),
|
|
intersection(Neigh,Not,NewNot),
|
|
extend(G,NewCand,NewNot,[H|CS],CSOut).
|
|
|
|
extend_cycle(G,[H|T],Not,CS,CSOut):-
|
|
extend_cycle(G,T,[H|Not],CS,CSOut).
|
|
|
|
extend(_G,[],[],CompSub,CompSub):-!.
|
|
|
|
extend(G,Cand,Not,CS,CSOut):-
|
|
extend_cycle(G,Cand,Not,CS,CSOut).
|
|
|
|
/* set(Par,Value) can be used to set the value of a parameter */
|
|
set(Parameter,Value):-
|
|
retract(setting(Parameter,_)),
|
|
assert(setting(Parameter,Value)).
|
|
|
|
/* end of utility predicates */
|