2012-12-17 14:50:12 +00:00
|
|
|
:- module(bnt,
|
|
|
|
[do_bnt/3,
|
|
|
|
create_bnt_graph/2,
|
|
|
|
check_if_bnt_done/1
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module(library('clpbn/display'),
|
|
|
|
[clpbn_bind_vals/3]).
|
|
|
|
|
|
|
|
:- use_module(library('clpbn/dists'),
|
|
|
|
[get_dist_domain_size/2,
|
|
|
|
get_dist_domain/2,
|
|
|
|
get_dist_params/2
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module(library('clpbn/discrete_utils'),
|
|
|
|
[reorder_CPT/5]).
|
|
|
|
|
|
|
|
:- use_module(library(matlab),
|
|
|
|
[start_matlab/1,
|
|
|
|
close_matlab/0,
|
|
|
|
matlab_on/0,
|
|
|
|
matlab_eval_string/1,
|
|
|
|
matlab_eval_string/2,
|
|
|
|
matlab_matrix/4,
|
|
|
|
matlab_vector/2,
|
|
|
|
matlab_sequence/3,
|
|
|
|
matlab_initialized_cells/4,
|
|
|
|
matlab_get_variable/2,
|
|
|
|
matlab_call/2
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module(library(dgraphs),
|
|
|
|
[dgraph_new/1,
|
|
|
|
dgraph_add_vertices/3,
|
|
|
|
dgraph_add_edges/3,
|
|
|
|
dgraph_top_sort/2,
|
|
|
|
dgraph_vertices/2,
|
|
|
|
dgraph_edges/2
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module(library(lists),
|
|
|
|
[append/3,
|
|
|
|
member/2,nth/3
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module(library(ordsets),
|
|
|
|
[ord_insert/3]).
|
2009-02-16 12:23:29 +00:00
|
|
|
|
|
|
|
:- yap_flag(write_strings,on).
|
|
|
|
|
|
|
|
% syntactic sugar for matlab_call.
|
|
|
|
:- op(800,yfx,<--).
|
|
|
|
|
|
|
|
G <-- Y :-
|
|
|
|
matlab_call(Y,G).
|
|
|
|
|
|
|
|
:- attribute bnt_id/1.
|
|
|
|
|
|
|
|
:- dynamic bnt/1.
|
|
|
|
|
|
|
|
:- dynamic bnt_solver/1, bnt_path/1, bnt_model/1.
|
|
|
|
|
|
|
|
% belprop
|
|
|
|
bnt_solver(jtree).
|
|
|
|
% likelihood_weighting
|
|
|
|
|
|
|
|
bnt_path("$HOME/Yap/CLPBN/FullBNT-1.0.4/BNT").
|
|
|
|
|
|
|
|
|
|
|
|
%
|
|
|
|
% What BNT are we using:
|
|
|
|
% a propositional one
|
|
|
|
% a tied parameter one.
|
|
|
|
%
|
|
|
|
%bnt_model(propositional).
|
|
|
|
bnt_model(tied).
|
|
|
|
%bnt_model(dbn).
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
|
|
|
|
BNT uses:
|
|
|
|
bnet
|
|
|
|
dag
|
|
|
|
discrete_nodes: which nodes are discrete (all by now),
|
|
|
|
node_sizes
|
|
|
|
engine
|
|
|
|
evidence
|
|
|
|
marg
|
|
|
|
|
|
|
|
*****************************************/
|
|
|
|
|
|
|
|
|
|
|
|
check_if_bnt_done(Var) :-
|
|
|
|
get_atts(Var, [map(_)]).
|
|
|
|
|
|
|
|
do_bnt([], _, _) :- !.
|
|
|
|
do_bnt(QueryVars, AllVars, AllDiffs) :-
|
|
|
|
create_bnt_graph(AllVars, _, SortedVertices, NumberedVertices, Size),
|
|
|
|
set_inference,
|
|
|
|
add_evidence(SortedVertices, Size, NumberedVertices),
|
|
|
|
marginalize(QueryVars, SortedVertices, NumberedVertices, Ps),
|
|
|
|
clpbn_bind_vals(QueryVars, Ps, AllDiffs).
|
2012-12-20 23:19:10 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
create_bnt_graph(AllVars, Representatives) :-
|
|
|
|
create_bnt_graph(AllVars, Representatives, _, _, _).
|
|
|
|
|
|
|
|
create_bnt_graph(AllVars, Representatives, SortedVertices, NumberedVertices, Size) :-
|
|
|
|
init_matlab,
|
|
|
|
sort_nodes(AllVars, SortedVertices),
|
|
|
|
number_graph(SortedVertices, NumberedVertices, 0, Size),
|
|
|
|
bnt_model(ModelType),
|
|
|
|
init_bnet(ModelType, SortedVertices, NumberedVertices, Size, Representatives).
|
|
|
|
|
|
|
|
|
|
|
|
% make sure MATLAB works.
|
|
|
|
|
|
|
|
init_matlab :-
|
|
|
|
bnt(on), !.
|
|
|
|
init_matlab :-
|
|
|
|
start_matlab,
|
|
|
|
bnt_path(Path),
|
|
|
|
append("cd ",Path,Command),
|
|
|
|
% atom_concat('cd ', Path, Command),
|
|
|
|
matlab_eval_string(Command),
|
|
|
|
matlab_eval_string('addpath(genpathKPM(pwd))',_),
|
|
|
|
assert(bnt(on)).
|
|
|
|
|
|
|
|
|
|
|
|
start_matlab :-
|
|
|
|
matlab_on, !.
|
|
|
|
start_matlab :-
|
|
|
|
start_matlab('matlab -nojvm -nosplash').
|
|
|
|
|
|
|
|
sort_nodes(AllVars, SortedVertices) :-
|
|
|
|
bnt_model(tied), !,
|
|
|
|
extract_tied(AllVars, SortedVertices).
|
|
|
|
sort_nodes(AllVars, SortedVertices) :-
|
|
|
|
bnt_model(propositional), !,
|
|
|
|
extract_graph(AllVars, Graph),
|
|
|
|
dgraph_top_sort(Graph, SortedVertices).
|
|
|
|
|
|
|
|
extract_tied(AllVars, SortedVars) :-
|
|
|
|
extract_kvars(AllVars,KVars),
|
|
|
|
keysort(KVars,SVars),
|
|
|
|
split_tied_vars(SVars,TVars, Vertices),
|
|
|
|
tied_graph(TVars,TGraph,Vertices),
|
|
|
|
dgraph_top_sort(TGraph, Sort),
|
|
|
|
distribute_tied_variables(Sort, TVars, 1, SortedVars).
|
|
|
|
|
|
|
|
extract_kvars([],[]).
|
|
|
|
extract_kvars([V|AllVars],[N-i(V,Parents)|KVars]) :-
|
|
|
|
clpbn:get_atts(V, [dist(N,Parents)]),
|
|
|
|
extract_kvars(AllVars,KVars).
|
|
|
|
|
|
|
|
split_tied_vars([],[],[]).
|
2012-12-17 17:57:00 +00:00
|
|
|
split_tied_vars([N-i(V,Par)|More],[N-g(Vs,Ns,Es)|TVars],[N|LNs]) :-
|
2009-02-16 12:23:29 +00:00
|
|
|
get_pars(Par,N,V,NPs,[],Es0,Es),
|
|
|
|
get_tied(More,N,Vs,[V],Ns,NPs,Es,Es0,SVars),
|
|
|
|
split_tied_vars(SVars,TVars,LNs).
|
|
|
|
|
|
|
|
get_pars([],_,_,NPs,NPs,Es,Es).
|
|
|
|
get_pars([V|Par],N,V0,NPs,NPs0,Es,Es0) :-
|
|
|
|
clpbn:get_atts(V, [dist(N,_)]), !,
|
|
|
|
get_pars(Par,N,V0,NPs,NPs0,Es,[V-V0|Es0]).
|
|
|
|
get_pars([V|Par],N,V0,NPs,NPs0,Es,Es0) :-
|
|
|
|
clpbn:get_atts(V, [dist(M,_)]),
|
|
|
|
ord_insert(NPs0,M,NPsI),
|
|
|
|
get_pars(Par,N,V0,NPs,NPsI,Es,Es0).
|
|
|
|
|
|
|
|
get_tied([N-i(V,Par)|More],N,Vs,Vs0,Ns,NPs,Es,Es0,SVars) :- !,
|
|
|
|
get_pars(Par,N,V,NPsI,NPs,EsI,Es0),
|
|
|
|
get_tied(More,N,Vs,[V|Vs0],Ns,NPsI,Es,EsI,SVars).
|
|
|
|
get_tied(More,_,Vs,Vs,Ns,Ns,Es,Es,More).
|
|
|
|
|
|
|
|
tied_graph(TVars,Graph,Vertices) :-
|
|
|
|
dgraph_new(Graph0),
|
|
|
|
dgraph_add_vertices(Graph0, Vertices, Graph1),
|
|
|
|
get_tied_edges(TVars,Edges),
|
|
|
|
dgraph_add_edges(Graph1, Edges, Graph).
|
|
|
|
|
|
|
|
get_tied_edges([],[]).
|
|
|
|
get_tied_edges([N-g(_,Vs,_)|TGraph],Edges) :-
|
|
|
|
add_tied(Vs,N,Edges,Edges0),
|
|
|
|
get_tied_edges(TGraph,Edges0).
|
|
|
|
|
|
|
|
add_tied([],_,Edges,Edges).
|
|
|
|
add_tied([N1|Vs],N,[N1-N|Edges],Edges0) :-
|
|
|
|
add_tied(Vs,N,Edges,Edges0).
|
|
|
|
|
|
|
|
distribute_tied_variables([], _, _, []).
|
|
|
|
distribute_tied_variables([N|Sort], TVars, I0, SortedVars) :-
|
|
|
|
member(N-g(Vs,_,_),TVars),
|
|
|
|
distribute_tied(Vs,I0,In,SortedVars,SortedVars0),
|
|
|
|
distribute_tied_variables(Sort, TVars, In, SortedVars0).
|
|
|
|
|
|
|
|
distribute_tied([],I,I,Vs,Vs).
|
|
|
|
distribute_tied([V|Vs],I0,In,[V|NVs],NVs0) :-
|
|
|
|
I is I0+1,
|
|
|
|
put_atts(V, [bnt_id(I0)]),
|
|
|
|
% clpbn:get_atts(V,[key(K)]),
|
|
|
|
distribute_tied(Vs,I,In,NVs,NVs0).
|
|
|
|
|
|
|
|
extract_graph(AllVars, Graph) :-
|
|
|
|
dgraph_new(Graph0),
|
|
|
|
dgraph_add_vertices(Graph0, AllVars, Graph1),
|
|
|
|
get_edges(AllVars,Edges),
|
|
|
|
dgraph_add_edges(Graph1, Edges, Graph).
|
2012-12-17 17:57:00 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
get_edges([],[]).
|
|
|
|
get_edges([V|AllVars],Edges) :-
|
|
|
|
clpbn:get_atts(V, [dist(_,Parents)]),
|
|
|
|
add_parent_child(Parents,V,Edges,Edges0),
|
|
|
|
get_edges(AllVars,Edges0).
|
|
|
|
|
|
|
|
add_parent_child([],_,Edges,Edges).
|
|
|
|
add_parent_child([P|Parents],V,[P-V|Edges],Edges0) :-
|
|
|
|
add_parent_child(Parents,V,Edges,Edges0).
|
|
|
|
|
|
|
|
number_graph([], [], I, I).
|
|
|
|
number_graph([V|SortedGraph], [I|Is], I0, IF) :-
|
|
|
|
I is I0+1,
|
|
|
|
put_atts(V, [bnt_id(I)]),
|
|
|
|
% clpbn:get_atts(V,[key(K)]),
|
|
|
|
% write(I:K),nl,
|
|
|
|
number_graph(SortedGraph, Is, I, IF).
|
2012-12-17 17:57:00 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
init_bnet(propositional, SortedGraph, NumberedGraph, Size, []) :-
|
|
|
|
build_dag(SortedGraph, Size),
|
|
|
|
init_discrete_nodes(SortedGraph, Size),
|
|
|
|
bnet <-- mk_bnet(dag, node_sizes, \discrete, discrete_nodes),
|
|
|
|
dump_cpts(SortedGraph, NumberedGraph).
|
2012-12-17 17:57:00 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
init_bnet(tied, SortedGraph, NumberedGraph, Size, Representatives) :-
|
|
|
|
build_dag(SortedGraph, Size),
|
|
|
|
init_discrete_nodes(SortedGraph, Size),
|
|
|
|
dump_tied_cpts(SortedGraph, NumberedGraph, Representatives).
|
|
|
|
|
|
|
|
build_dag(SortedVertices, Size) :-
|
|
|
|
get_numbered_edges(SortedVertices, Edges),
|
|
|
|
mkdag(Size, Edges).
|
|
|
|
|
|
|
|
get_numbered_edges([], []).
|
|
|
|
get_numbered_edges([V|SortedVertices], Edges) :-
|
|
|
|
clpbn:get_atts(V, [dist(_,Ps)]),
|
|
|
|
v2number(V,N),
|
|
|
|
add_numbered_edges(Ps, N, Edges, Edges0),
|
|
|
|
get_numbered_edges(SortedVertices, Edges0).
|
|
|
|
|
|
|
|
add_numbered_edges([], _, Edges, Edges).
|
|
|
|
add_numbered_edges([P|Ps], N, [PN-N|Edges], Edges0) :-
|
|
|
|
v2number(P,PN),
|
|
|
|
add_numbered_edges(Ps, N, Edges, Edges0).
|
|
|
|
|
|
|
|
v2number(V,N) :-
|
|
|
|
get_atts(V,[bnt_id(N)]).
|
|
|
|
|
|
|
|
init_discrete_nodes(SortedGraph, Size) :-
|
|
|
|
matlab_sequence(1,Size,discrete_nodes),
|
|
|
|
mksizes(SortedGraph, Size).
|
|
|
|
|
|
|
|
mkdag(N,Els) :-
|
|
|
|
Tot is N*N,
|
|
|
|
functor(Dag,dag,Tot),
|
|
|
|
add_els(Els,N,Dag),
|
|
|
|
Dag=..[_|L],
|
|
|
|
addzeros(L),
|
|
|
|
matlab_matrix(N,N,L,dag).
|
|
|
|
|
|
|
|
add_els([],_,_).
|
|
|
|
add_els([X-Y|Els],N,Dag) :-
|
|
|
|
Pos is (X-1)*N+Y,
|
|
|
|
arg(Pos,Dag,1),
|
|
|
|
add_els(Els,N,Dag).
|
|
|
|
|
|
|
|
addzeros([]).
|
|
|
|
addzeros([0|L]) :- !,
|
|
|
|
addzeros(L).
|
|
|
|
addzeros([1|L]) :-
|
|
|
|
addzeros(L).
|
|
|
|
|
|
|
|
mksizes(SortedVertices, Size) :-
|
|
|
|
get_szs(SortedVertices,Sizes),
|
|
|
|
matlab_matrix(1,Size,Sizes,node_sizes).
|
|
|
|
|
|
|
|
get_szs([],[]).
|
|
|
|
get_szs([V|SortedVertices],[LD|Sizes]) :-
|
|
|
|
clpbn:get_atts(V, [dist(Id,_)]),
|
|
|
|
get_dist_domain_size(Id,LD),
|
|
|
|
get_szs(SortedVertices,Sizes).
|
|
|
|
|
|
|
|
dump_cpts([], []).
|
|
|
|
dump_cpts([V|SortedGraph], [I|Is]) :-
|
|
|
|
clpbn:get_atts(V, [dist(Id,Parents)]),
|
|
|
|
get_dist_params(Id,CPT),
|
|
|
|
reorder_cpt(CPT,V,Parents,Tab),
|
|
|
|
mkcpt(bnet,I,Tab),
|
|
|
|
dump_cpts(SortedGraph, Is).
|
|
|
|
|
|
|
|
%
|
|
|
|
% This is complicated, the BNT and we have different orders
|
|
|
|
%
|
|
|
|
reorder_cpt(CPT,_, [], CPT) :- !.
|
|
|
|
reorder_cpt(CPT,V,Parents,Tab) :-
|
|
|
|
% get BNT label
|
|
|
|
get_sizes_and_ids(Parents,Ids),
|
|
|
|
% sort to BNT
|
|
|
|
keysort(Ids,NIds),
|
|
|
|
% get vars in order
|
|
|
|
extract_vars(NIds, [], NParents),
|
|
|
|
% do the actual work
|
|
|
|
reorder_CPT([V|Parents],CPT,[V|NParents],STab,_),
|
|
|
|
STab=..[_|Tab].
|
|
|
|
|
|
|
|
get_sizes_and_ids([],[]).
|
|
|
|
get_sizes_and_ids([V|Parents],[Id-V|Ids]) :-
|
|
|
|
get_atts(V, [bnt_id(Id)]),
|
|
|
|
get_sizes_and_ids(Parents,Ids).
|
|
|
|
|
|
|
|
extract_vars([], L, L).
|
|
|
|
extract_vars([_-V|NIds], NParents, Vs) :-
|
|
|
|
extract_vars(NIds, [V|NParents], Vs).
|
2012-12-20 23:19:10 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
mkcpt(BayesNet, I, Tab) :-
|
|
|
|
(BayesNet.'CPD'({I})) <-- tabular_CPD(BayesNet,I,Tab).
|
|
|
|
|
|
|
|
dump_tied_cpts(Graph, Is, Reps) :-
|
|
|
|
create_class_vector(Graph, Is, Classes, Reps0),
|
|
|
|
matlab_vector(Classes, eclass),
|
|
|
|
keysort(Reps0,Reps1),
|
|
|
|
representatives(Reps1,Reps),
|
|
|
|
bnet <-- mk_bnet(dag, node_sizes, \discrete, discrete_nodes, \equiv_class, eclass),
|
|
|
|
dump_tied_cpts(Reps).
|
|
|
|
|
|
|
|
create_class_vector([], [], [],[]).
|
|
|
|
create_class_vector([V|Graph], [I|Is], [Id|Classes], [Id-v(V,I,Parents)|Sets]) :-
|
|
|
|
clpbn:get_atts(V, [dist(Id,Parents)]),
|
|
|
|
create_class_vector(Graph, Is,Classes,Sets).
|
2012-12-20 23:19:10 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
representatives([],[]).
|
|
|
|
representatives([Class-Rep|Reps1],[Class-Rep|Reps]) :-
|
|
|
|
nonrepresentatives(Reps1, Class, Reps2),
|
|
|
|
representatives(Reps2,Reps).
|
|
|
|
|
|
|
|
nonrepresentatives([Class-_|Reps1], Class, Reps2) :- !,
|
|
|
|
nonrepresentatives(Reps1, Class, Reps2).
|
|
|
|
nonrepresentatives(Reps, _, Reps).
|
|
|
|
|
|
|
|
|
|
|
|
dump_tied_cpts([]).
|
|
|
|
dump_tied_cpts([Class-v(V,Id,Parents)|SortedGraph]) :-
|
|
|
|
get_dist_params(Class,CPT),
|
|
|
|
reorder_cpt(CPT,V,Parents,NCPT),
|
|
|
|
mktiedcpt(bnet,Id,Class,NCPT),
|
|
|
|
dump_tied_cpts(SortedGraph).
|
|
|
|
|
|
|
|
mktiedcpt(BayesNet, V, Class, Tab) :-
|
|
|
|
(BayesNet.'CPD'({Class})) <-- tabular_CPD(BayesNet,V,Tab).
|
|
|
|
|
|
|
|
set_inference :-
|
|
|
|
bnt_solver(Solver),
|
|
|
|
init_solver(Solver).
|
|
|
|
|
|
|
|
init_solver(jtree) :-
|
|
|
|
engine <-- jtree_inf_engine(bnet).
|
|
|
|
init_solver(belprop) :-
|
|
|
|
engine <-- belprop_inf_engine(bnet).
|
|
|
|
init_solver(likelihood_weighting) :-
|
|
|
|
engine <-- likelihood_weighting_inf_engine(bnet).
|
|
|
|
init_solver(enumerative) :-
|
|
|
|
engine <-- enumerative_inf_engine(bnet).
|
|
|
|
init_solver(gibbs) :-
|
|
|
|
engine <-- gibbs_sampling_inf_engine(bnet).
|
|
|
|
init_solver(global_joint) :-
|
|
|
|
engine <-- global_joint_inf_engine(bnet).
|
|
|
|
init_solver(pearl) :-
|
|
|
|
engine <-- pearl_inf_engine(bnet).
|
|
|
|
init_solver(var_elim) :-
|
|
|
|
engine <-- var_elim_inf_engine(bnet).
|
|
|
|
|
|
|
|
add_evidence(Graph, Size, Is) :-
|
|
|
|
mk_evidence(Graph, Is, LN),
|
|
|
|
matlab_initialized_cells( 1, Size, LN, evidence),
|
|
|
|
[engine_ev, loglik] <-- enter_evidence(engine, evidence).
|
2012-12-17 17:57:00 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
mk_evidence([], [], []).
|
|
|
|
mk_evidence([V|L], [I|Is], [ar(1,I,EvVal1)|LN]) :-
|
|
|
|
clpbn:get_atts(V, [evidence(EvVal)]), !,
|
|
|
|
EvVal1 is EvVal +1,
|
|
|
|
mk_evidence(L, Is, LN).
|
|
|
|
mk_evidence([_|L], [_|Is], LN) :-
|
|
|
|
mk_evidence(L, Is, LN).
|
2012-12-20 23:19:10 +00:00
|
|
|
|
2009-02-16 12:23:29 +00:00
|
|
|
evidence_val(Ev,Val,[Ev|_],Val) :- !.
|
|
|
|
evidence_val(Ev,I0,[_|Domain],Val) :-
|
|
|
|
I1 is I0+1,
|
|
|
|
evidence_val(Ev,I1,Domain,Val).
|
|
|
|
|
|
|
|
marginalize([[V]], _SortedVars,_NunmberedVars, Ps) :- !,
|
|
|
|
v2number(V,Pos),
|
|
|
|
marg <-- marginal_nodes(engine_ev, Pos),
|
|
|
|
matlab_get_variable( marg.'T', Ps).
|
|
|
|
|
|
|
|
marginalize([Vs], SortedVars, NumberedVars,Ps) :-
|
|
|
|
bnt_solver(jtree),!,
|
|
|
|
matlab_get_variable(loglik, Den),
|
|
|
|
clpbn_display:get_all_combs(Vs, Vals),
|
|
|
|
mk_evidence(SortedVars, NumberedVars, Ev),
|
|
|
|
length(SortedVars,L),
|
|
|
|
cycle_values(Den, Ev, Vs, L, Vals, Ps).
|
|
|
|
|
2012-12-17 17:57:00 +00:00
|
|
|
cycle_values(_D, _Ev, _Vs, _Size, [], []).
|
2009-02-16 12:23:29 +00:00
|
|
|
|
|
|
|
cycle_values(Den,Ev,Vs,Size,[H|T],[HP|TP]):-
|
|
|
|
mk_evidence_query(Vs, H, EvQuery),
|
|
|
|
append(EvQuery,Ev,Instantiation),
|
|
|
|
matlab_initialized_cells( 1, Size, Instantiation, instantiation),
|
|
|
|
[engine_ev, logll] <-- enter_evidence(engine, instantiation),
|
|
|
|
matlab_get_variable(logll, Num),
|
|
|
|
HP is exp(Num-Den),
|
|
|
|
cycle_values(Den,Ev,Vs,Size,T,TP).
|
|
|
|
|
|
|
|
mk_evidence_query([], [], []).
|
|
|
|
mk_evidence_query([V|L], [H|T], [ar(1,Pos,El)|LN]) :-
|
|
|
|
v2number(V,Pos),
|
|
|
|
clpbn:get_atts(V, [dist(Id,_)]),
|
|
|
|
get_dist_domain(Id,D),
|
|
|
|
nth(El,D,H),
|
|
|
|
mk_evidence_query(L, T, LN).
|
2012-12-17 14:50:12 +00:00
|
|
|
|