2:- module(viterbi,[ viterbi/3,
3 op(600,xfy,'::')
4 ]).
18:- thread_local vit_input_mod/1.
19
20:-meta_predicate viterbi(:,-,-).
21
22
23default_setting_viterbi(epsilon_parsing, 1e-5).
31viterbi(M:Goals,Prob,Exp):-
32 must_be(nonvar, Goals),
33 must_be(var,Prob),
34 must_be(var,Exp),
35 retractall(M:best_prob(_)),
36 retractall(M:best_exp(_)),
37 retractall(M:best_goal(_)),
38 assert(M:best_prob(0.0)),
39 assert(M:best_exp([])),
40 list2and(GL,Goals),
41 assert(M:best_goal(GL)),
42 (find_exp(GL,M),fail; true),
43 M:best_prob(Prob),
44 M:best_exp(Exp0),
45 M:best_goal(GL),
46 convert_exp(Exp0,M,Exp),
47 retractall(M:best_prob(_)),
48 retractall(M:best_exp(_)).
49
50complete_exp(Exp0,Prob0,M,Exp,Prob):-
51 findall((R,S),(M:rule_by_num(R,S,_,Head,Body),\+ member(rule(R,_,Head,Body),Exp0)),L)->
52 maplist(find_max(M),L,Exp1),
53 foldl(mult,Exp1,Prob0,Prob),
54 convert_exp(Exp1,M,Exp2),
55 append(Exp0,Exp2,Exp).
56
57mult((_,_,_,P1),P0,P):-
58 P is P0*P1.
59
60find_max(M,(R,S),(R,S,N,P)):-
61 M:rule_by_num(R,S,[_|Numbers],[_:P0|Head],_Body),
62 foldl(get_max,Head,Numbers,(P0,0),(P,N)).
63
64get_max(_:P,N,(P0,N0),(P1,N1)):-
65 (P>P0->
66 N1=N,
67 P1=P
68 ;
69 N1=N0,
70 P1=P0
71 ).
72
73
74convert_exp([],_M,[]).
75
76convert_exp([(R,S,N,_)|T],M,[rule(R,Head,HeadList,Body)|TDelta]):-
77 M:rule(Head, _, N, R, S, _NH, HeadList, Body),!,
78 convert_exp(T,M,TDelta).
79
80find_exp(GL,M):-
81 solve(GL,M,[],Exp,1,P),
82 retract(M:best_prob(_)),
83 retract(M:best_exp(_)),
84 retract(M:best_goal(_)),
85 assert(M:best_prob(P)),
86 assert(M:best_exp(Exp)),
87 assert(M:best_goal(GL)).
88
93
96
97
98solve([],_M,C,C,P,P):-!.
99
100solve([\+ H|T],M,CIn,COut,P0,P):-
101 builtin(H),!,
102 \+ H,
103 solve(T,M,CIn,COut,P0,P).
104
105solve([\+ H |T],M,CIn,COut,P0,P):-
106 !,
107 list2and(HL,H),
108 (setof(D,solve_nob(HL,M,[],D),L)->
109 choose_clauses(L,CIn,M,C1,P0,P1),
110 solve(T,M,C1,COut,P1,P)
111 ;
112 solve(T,M,CIn,COut,P0,P)
113 ).
114
115solve([H|T],M,CIn,COut,P0,P):-
116 builtin(H),!,
117 call(H),
118 solve(T,M,CIn,COut,P0,P).
119
120solve([H|T],M,CIn,COut,P0,P):-
121 M:def_rule(H,B),
122 append(B,T,NG),
123 solve(NG,M,CIn,COut,P0,P).
124
125solve([H|T],M,CIn,COut,P0,P):-
126 find_rule(H,M,(R,S,N,PR),B,CIn),
127 append(B,T,NG),
128 solve(NG,M,CIn,C1,P0,P1),
129 update_exp(C1,COut,(R,S,N,PR),P1,P),
130 check_bound(P,M).
131
132
133update_exp(C,C,Ch,P,P):-
134 member(Ch,C),!.
135
136update_exp(C0,[(R,S,N,PR)|C0],(R,S,N,PR),P0,P):-
137 P is P0*PR.
138
139check_bound(P,M):-
140 M:best_prob(BP),
141 P>BP.
142
143
144solve_nob([],_M,C,C):-!.
145
146solve_nob([\+ H|T],M,CIn,COut):-
147 builtin(H),!,
148 call(\+ H),
149 solve_nob(T,M,CIn,COut).
150
151solve_nob([\+ H |T],M,CIn,COut):-!,
152 list2and(HL,H),
153 (setof(D,solve_nob(HL,M,[],D),L)->
154 choose_clauses_nob(L,CIn,M,C1),
155 solve_nob(T,M,C1,COut)
156 ;
157 solve_nob(T,M,CIn,COut)
158 ).
159
160solve_nob([H|T],M,CIn,COut):-
161 builtin(H),!,
162 call(H),
163 solve_nob(T,M,CIn,COut).
164
165solve_nob([H|T],M,CIn,COut):-
166 M:def_rule(H,B),
167 append(B,T,NG),
168 solve_nob(NG,M,CIn,COut).
169
170solve_nob([H|T],M,CIn,COut):-
171 find_rule(H,M,(R,S,N,P),B,CIn),
172 append(B,T,NG),
173 solve_nob(NG,M,CIn,C1),
174 update_exp(C1,COut,(R,S,N,P),1,_P2).
175
176
177find_rule(H, M,(R, S, N,P), Body, C) :-
178 M:rule(H, P, N, R, S, _NH, _Head, Body),
179 not_already_present_with_a_different_head(N, R, S, C).
180
181not_already_present_with_a_different_head(_HeadId, _RuleId, _Subst, []).
182
183not_already_present_with_a_different_head(HeadId, RuleId, Subst, [(HeadId1, RuleId, Subst1,_P)|Tail]) :-
184 not_different(HeadId, HeadId1, Subst, Subst1), !,
185 not_already_present_with_a_different_head(HeadId, RuleId, Subst, Tail).
186
187not_already_present_with_a_different_head(HeadId, RuleId, Subst, [(_HeadId1, RuleId1, _Subst1,_P)|Tail]) :-
188 RuleId \== RuleId1,
189 not_already_present_with_a_different_head(HeadId, RuleId, Subst, Tail).
190
191
192
193not_different(_HeadId, _HeadId1, Subst, Subst1) :-
194 Subst \= Subst1, !.
195
196not_different(HeadId, HeadId1, Subst, Subst1) :-
197 HeadId \= HeadId1, !,
198 dif(Subst, Subst1).
199
200not_different(HeadId, HeadId, Subst, Subst).
201
202
203choose_clauses([],C,_M,C,P,P).
204
205choose_clauses([D|T],CIn,M,COut,P0,P):-
206 member((N,R,S,_P),D),
207 already_present_with_a_different_head(N,R,S,CIn),!,
208 choose_clauses(T,CIn,M,COut,P0,P).
209
210
211choose_clauses([D|T],CIn,M,COut,P0,P):-
212 member((R,S,N,_P),D),
213 new_head(M,N,R,S,N1,PR),
214 \+ already_present(N1,R,S,CIn),
215 P1 is P0*PR,
216 check_bound(P1,M),
217 choose_clauses(T,[(R,S,N1,PR)|CIn],M,COut,P1,P).
218
219choose_clauses_nob([],C,_M,C).
220
221choose_clauses_nob([D|T],CIn,M,COut):-
222 member((R,S,N,_P),D),
223 already_present_with_a_different_head(N,R,S,CIn),!,
224 choose_clauses_nob(T,CIn,M,COut).
225
226
227choose_clauses_nob([D|T],CIn,M,COut):-
228 member((R,S,N,_P),D),
229 new_head(M,N,R,S,N1,PR),
230 \+ already_present(N1,R,S,CIn),
231 choose_clauses_nob(T,[(R,S,N1,PR)|CIn],M,COut).
232
235new_head(M,N,R,S,N1,P):-
236 M:rule_by_num(R,S,Numbers,_Head,_Body),
237 nth0(N, Numbers, _Elem, Rest),
238 member(N1,Rest),
239 M:rule(_H, P, N1, R, _S, _NH, _HL, _B).
240
241
242
243already_present_with_a_different_head(N,R,S,[(NH,R,SH,_P)|_T]):-
244 S=SH,NH \= N.
245
246already_present_with_a_different_head(N,R,S,[_H|T]):-
247 already_present_with_a_different_head(N,R,S,T).
248
249
252already_present(N,R,S,[(N,R,S,_P)|_T]):-!.
253
254already_present(N,R,S,[_H|T]):-
255 already_present(N,R,S,T).
256
265
266
267builtin(average(_L,_Av)).
268builtin(prob(_,_)).
269builtin(G):-
270 predicate_property(G,built_in).
271builtin(G):-
272 predicate_property(G,imported_from(lists)).
273
274average(L,Av):-
275 sum_list(L,Sum),
276 length(L,N),
277 Av is Sum/N.
278
279
280listN(N, N, []) :- !.
281
282listN(NIn, N, [NIn|T]) :-
283 N1 is NIn+1,
284 listN(N1, N, T).
285
300assert_rules([],_M, _Index, _HeadList, _BodyList, _Choices, _Id, _Subst) :- !.
301
302assert_rules(['':_Prob], _M,_Index, _HeadList, _BodyList, _Choices, _Id, _Subst) :- !.
303
304assert_rules([Head:Prob|Tail],M, Index, HeadList, BodyList, Choices, Id, Subst) :-
305 assertz(M:rule(Head, Prob, Index, Id, Subst, Choices, HeadList, BodyList)),
306 Next is Index + 1,
307 assert_rules(Tail,M, Next, HeadList, BodyList,Choices,Id,Subst).
308
309
310list2and([],true):-!.
311
312list2and([X],X):-
313 X\=(_,_),!.
314
315list2and([H|T],(H,Ta)):-!,
316 list2and(T,Ta).
317
318
319process_head(HeadList, GroundHeadList) :-
320 ground_prob(HeadList), !,
321 process_head_ground(HeadList, 0, GroundHeadList).
322
323process_head(HeadList0, HeadList):-
324 get_probs(HeadList0,PL),
325 foldl(minus,PL,1,PNull),
326 append(HeadList0,['':PNull],HeadList).
327
328minus(A,B,B-A).
329
330prob_ann(_:P,P):-!.
331prob_ann(P::_,P).
332
333
334gen_head(H,P,V,V1,H1:P):-copy_term((H,V),(H1,V1)).
335gen_head_disc(H,V,V1:P,H1:P):-copy_term((H,V),(H1,V1)).
336
337
341process_head_ground([H], Prob, [Head:ProbHead1|Null]) :-
342 (H=Head:ProbHead;H=ProbHead::Head),!,
343 ProbHead1 is float(ProbHead),
344 ProbLast is 1.0 - Prob - ProbHead1,
345 prolog_load_context(module, M),vit_input_mod(M),
346 M:local_viterbi_setting(epsilon_parsing, Eps),
347 EpsNeg is - Eps,
348 ProbLast > EpsNeg,
349 (ProbLast > Eps ->
350 Null = ['':ProbLast]
351 ;
352 Null = []
353 ).
354
355process_head_ground([H|Tail], Prob, [Head:ProbHead1|Next]) :-
356 (H=Head:ProbHead;H=ProbHead::Head),
357 ProbHead1 is float(ProbHead),
358 ProbNext is Prob + ProbHead1,
359 process_head_ground(Tail, ProbNext, Next).
360
361
362ground_prob([]).
363
364ground_prob([_Head:ProbHead|Tail]) :-!,
365 ground(ProbHead),
366 ground_prob(Tail).
367
368ground_prob([ProbHead::_Head|Tail]) :-
369 ground(ProbHead),
370 ground_prob(Tail).
371
372
373get_probs(Head, PL):-
374 maplist(prob_ann,Head,PL).
375
376
377list2or([],true):-!.
378
379list2or([X],X):-
380 X\=;(_,_),!.
381
382list2or([H|T],(H ; Ta)):-!,
383 list2or(T,Ta).
394set_vit(M:Parameter,Value):-
395 retract(M:local_viterbi_setting(Parameter,_)),
396 assert(M:local_viterbi_setting(Parameter,Value)).
405setting_vit(M:P,V):-
406 M:local_viterbi_setting(P,V).
407
408
409assert_all([],_M,[]).
410
411assert_all([H|T],M,[HRef|TRef]):-
412 assertz(M:H,HRef),
413 assert_all(T,M,TRef).
414
415
416get_next_rule_number(PName,R):-
417 retract(PName:rule_n(R)),
418 R1 is R+1,
419 assert(PName:rule_n(R1)).
420
421
422
423
424vit_expansion((:- begin_plp), []) :-
425 prolog_load_context(module, M),
426 vit_input_mod(M),!,
427 assert(M:vit_on).
428
429vit_expansion((:- end_plp), []) :-
430 prolog_load_context(module, M),
431 vit_input_mod(M),!,
432 retractall(M:vit_on).
433
434vit_expansion((:- begin_lpad), []) :-
435 prolog_load_context(module, M),
436 vit_input_mod(M),!,
437 assert(M:vit_on).
438
439vit_expansion((:- end_lpad), []) :-
440 prolog_load_context(module, M),
441 vit_input_mod(M),!,
442 retractall(M:vit_on).
443
444vit_expansion((Head :- Body), []):-
445 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,
447 Head = (_;_), !,
448 list2or(HeadListOr, Head),
449 process_head(HeadListOr, HeadList),
450 list2and(BodyList, Body),
451 length(HeadList, LH),
452 listN(0, LH, NH),
453 get_next_rule_number(M,R),
454 append(HeadList,BodyList,List),
455 term_variables(List,VC),
456 assert_rules(HeadList, M, 0, HeadList, BodyList, NH, R, VC),
457 assertz(M:rule_by_num(R, VC, NH, HeadList, BodyList)).
458
459
460vit_expansion((Head :- Body), []):-
461 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,
462 (Head=(_:_); Head=(_::_)), !,
463 list2or(HeadListOr, Head),
464 process_head(HeadListOr, HeadList),
465 list2and(BodyList, Body),
466 length(HeadList, LH),
467 listN(0, LH, NH),
468 get_next_rule_number(M,R),
469 append(HeadList,BodyList,List),
470 term_variables(List,VC),
471 assert_rules(HeadList, M,0, HeadList, BodyList, NH, R, VC),
472 assertz(M:rule_by_num(R, VC, NH, HeadList, BodyList)).
473
474vit_expansion((Head :- Body), []):-
475 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,!,
476 list2and(BodyList, Body),
477 assert(M:def_rule(Head, BodyList)).
478
479vit_expansion(Head , []):-
480 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,
481 Head=(_;_), !,
482 list2or(HeadListOr, Head),
483 process_head(HeadListOr, HeadList),
484 length(HeadList, LH),
485 listN(0, LH, NH),
486 get_next_rule_number(M,R),
487 term_variables(HeadList,VC),
488 assert_rules(HeadList, M, 0, HeadList, [], NH, R, VC),
489 assertz(M:rule_by_num(R, VC, NH, HeadList, [])).
490
491vit_expansion(Head , []):-
492 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,
493 (Head=(_:_); Head=(_::_)), !,
494 list2or(HeadListOr, Head),
495 process_head(HeadListOr, HeadList),
496 length(HeadList, LH),
497 listN(0, LH, NH),
498 get_next_rule_number(M,R),
499 term_variables(HeadList,VC),
500 assert_rules(HeadList, M, 0, HeadList, [], NH, R, VC),
501 assertz(M:rule_by_num(R, VC, NH, HeadList, [])).
502
503vit_expansion(Head, []):-
504 prolog_load_context(module, M),vit_input_mod(M),M:vit_on,!,
505 assert(M:def_rule(Head, [])).
506
507:- multifile sandbox:safe_meta/2.
508
509sandbox:safe_meta(viterbi:viterbi(_,_,_), []).
510
511:- thread_local vit_file/1.
512
513user:term_expansion((:- viterbi), []) :-!,
514 prolog_load_context(source, Source),
515 asserta(vit_file(Source)),
516 prolog_load_context(module, M),
517 retractall(M:local_viterbi_setting(_,_)),
518 findall(local_viterbi_setting(P,V),default_setting_viterbi(P,V),L),
519 assert_all(L,M,_),
520 assert(vit_input_mod(M)),
521 retractall(M:rule_n(_)),
522 assert(M:rule_n(0)),
523 M:(dynamic rule_by_num/5),
524 M:(dynamic rule/8,def_rule/2),
525 retractall(M:rule_by_num(_,_,_,_,_)),
526 retractall(M:rule(_,_,_,_,_,_,_,_)),
527 style_check(-discontiguous).
528
529user:term_expansion(end_of_file, end_of_file) :-
530 vit_file(Source),
531 prolog_load_context(source, Source),
532 retractall(vit_file(Source)),
533 prolog_load_context(module, M),
534 vit_input_mod(M),!,
535 retractall(vit_input_mod(M)),
536 style_check(+discontiguous).
537
538
539user:term_expansion(In, Out) :-
540 \+ current_prolog_flag(xref, true),
541 vit_file(Source),
542 prolog_load_context(source, Source),
543 vit_expansion(In, Out)
viterbi
This module performs reasoning over Logic Programs with Annotated Disjunctions and CP-Logic programs. It reads probabilistic program and computes the most likely explanation of the query