368 lines
9.5 KiB
Perl
368 lines
9.5 KiB
Perl
|
/*==============================================================================
|
||
|
* LPAD and CP-Logic reasoning suite
|
||
|
* File: parsing.pl
|
||
|
* Parses predicates to load LPADs (main predicate: parse(FileNameNoExt)
|
||
|
* Copyright (c) 2009, Stefano Bragaglia
|
||
|
*============================================================================*/
|
||
|
|
||
|
:- dynamic rule/4, def_rule/2.
|
||
|
|
||
|
% :- source.
|
||
|
% :- yap_flag(single_var_warnings, on).
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* BUILTIN PREDICATES
|
||
|
* ------------------
|
||
|
* This section declares the builtin predicates.
|
||
|
*/
|
||
|
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(_, _, _)).
|
||
|
builtin(eraseall(_Id)).
|
||
|
builtin(recordz(_Id, _Item, _)).
|
||
|
builtin(recordzifnot(_Id, _Item, _)).
|
||
|
|
||
|
|
||
|
|
||
|
member_eq(Item, [Head|_Tail]) :-
|
||
|
Item==Head, !.
|
||
|
|
||
|
member_eq(Item, [_Head|Tail]) :-
|
||
|
member_eq(Item, Tail).
|
||
|
|
||
|
|
||
|
|
||
|
not_already_present_with_a_different_head(_HeadId, _RuleId, _Subst, []).
|
||
|
|
||
|
not_already_present_with_a_different_head(HeadId, RuleId, Subst, [(HeadId1, RuleId, Subst1)|Tail]) :-
|
||
|
not_different(HeadId, HeadId1, Subst, Subst1), !,
|
||
|
not_already_present_with_a_different_head(HeadId, RuleId, Subst, Tail).
|
||
|
|
||
|
not_already_present_with_a_different_head(HeadId, RuleId, Subst, [(_HeadId1, RuleId1, _Subst1)|Tail]) :-
|
||
|
RuleId \== RuleId1,
|
||
|
not_already_present_with_a_different_head(HeadId, RuleId, Subst, Tail).
|
||
|
|
||
|
|
||
|
|
||
|
not_different(_HeadId, _HeadId1, Subst, Subst1) :-
|
||
|
Subst \= Subst1, !.
|
||
|
|
||
|
not_different(HeadId, HeadId1, Subst, Subst1) :-
|
||
|
HeadId \= HeadId1, !,
|
||
|
dif(Subst, Subst1).
|
||
|
|
||
|
not_different(HeadId, HeadId, Subst, Subst).
|
||
|
|
||
|
|
||
|
|
||
|
get_groundc([], [], [], P, P) :- !.
|
||
|
|
||
|
get_groundc([H|T], [H|T1], TV, P0, P1) :-
|
||
|
ground(H), !,
|
||
|
H=(N, R, S),
|
||
|
rule_by_num(R, S, _N, Head, _Body),
|
||
|
nth0(N, Head, (_A:P)),
|
||
|
P2 is P0*P,
|
||
|
get_groundc(T, T1, TV, P2, P1).
|
||
|
|
||
|
get_groundc([H|T], T1, [H|TV], P0, P1) :-
|
||
|
get_groundc(T, T1, TV, P0, P1).
|
||
|
|
||
|
get_prob([], P, P) :- !.
|
||
|
|
||
|
get_prob([H|T], P0, P1) :-
|
||
|
H=(N, R, S),
|
||
|
rule_by_num(R, S, _N, Head, _Body),
|
||
|
nth0(N, Head, (_A:P)),
|
||
|
P2 is P0*P,
|
||
|
get_prob(T, P2, P1).
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
find_rulec(H, (R, S, N), Body, C, P) :-
|
||
|
rule(H, P, N, R, S, _NH, _Head, Body),
|
||
|
not_already_present_with_a_different_head(N, R, S, C).
|
||
|
|
||
|
|
||
|
|
||
|
/* var2numbers([(Rule, Subst)|CoupleTail], Index, [[Index, Heads, Probs]|TripleTail])
|
||
|
* ----------------------------------------------------------------------------------
|
||
|
* This tail recursive predicate converts a list of couples (Rule, Subst) into a
|
||
|
* list of triples (Index, Count, Probs).
|
||
|
* Rule and Subst are the index of their equivalent rule and substitution.
|
||
|
* Index is a progressive identifier starting from 0.
|
||
|
* Count is the number of head atoms and Probs is the vector of their
|
||
|
* probabilities.
|
||
|
*
|
||
|
* INPUT
|
||
|
* - Couples: list of couples to convert.
|
||
|
*
|
||
|
* OUTPUT
|
||
|
* - Triples: list of equivalent triples.
|
||
|
*/
|
||
|
var2numbers([], _N, []).
|
||
|
|
||
|
var2numbers([(Rule, Subst)|CoupleTail], Index, [[Index, Heads, Probs]|TripleTail]) :-
|
||
|
find_probs(Rule, Subst, Probs),
|
||
|
length(Probs, Heads),
|
||
|
Next is Index+1,
|
||
|
var2numbers(CoupleTail, Next, TripleTail).
|
||
|
|
||
|
|
||
|
|
||
|
/* build_formula(ListC, Formula, VarIn, VarOut)
|
||
|
* --------------------------------------------
|
||
|
* This predicate parses a given list of C sets with a given list of variables
|
||
|
* and returns the equivalent formula with its list of variables.
|
||
|
*
|
||
|
* Note: each Formula is expressed in the form: [Term1, ..., TermN], where each
|
||
|
* term is expressed in the form: [Factor1, ..., FactorM], where each
|
||
|
* factor is hence expressed in the form: (Var, Name).
|
||
|
* Finally, Var is the index of the multivalued variable Var, and Value is
|
||
|
* the index of its value.
|
||
|
*
|
||
|
* INPUT
|
||
|
* - ListC: given list of C sets.
|
||
|
* - VarIn: list of variables pertaining to ListC.
|
||
|
*
|
||
|
* OUTPUT
|
||
|
* - Formula: the formula equivalent to ListC.
|
||
|
* - VarOut: list of variables pertaining to Formula.
|
||
|
*/
|
||
|
build_formula([], [], Var, Var, Count, Count).
|
||
|
%% Closing condition: stop if no more terms (current Var is final Var, current Count is final Count)
|
||
|
|
||
|
build_formula([D|TD], [F|TF], VarIn, VarOut, C0, C1) :-
|
||
|
length(D, NC),
|
||
|
C2 is C0+NC,
|
||
|
reverse(D, D1),
|
||
|
build_term(D1, F, VarIn, Var1),
|
||
|
build_formula(TD, TF, Var1, VarOut, C2, C1).
|
||
|
%% Recursive call: procedd to next terms, building rest of formula and handling vars and count.
|
||
|
|
||
|
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).
|
||
|
|
||
|
|
||
|
|
||
|
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).
|
||
|
|
||
|
|
||
|
|
||
|
/* nth0_eq(PosIn, PosOut, List, Elem)
|
||
|
* ----------------------------------
|
||
|
* This predicate searches for an element that matches with the given one in the
|
||
|
* given list, starting from the given position, and returns its position.
|
||
|
*
|
||
|
* INPUT
|
||
|
* - PosIn: initial position.
|
||
|
* - List: list to parse.
|
||
|
* - Elem: element to match.
|
||
|
*
|
||
|
* OUTPUT
|
||
|
* - PosOut: next position of a matching element.
|
||
|
*/
|
||
|
nth0_eq(N, N, [H|_T], Elem) :-
|
||
|
H==Elem, !.
|
||
|
|
||
|
nth0_eq(NIn, NOut, [_H|T], Elem) :-
|
||
|
N1 is NIn+1,
|
||
|
nth0_eq(N1, NOut, T, Elem).
|
||
|
|
||
|
|
||
|
|
||
|
list2and([X], X) :-
|
||
|
X\=(_, _), !.
|
||
|
|
||
|
list2and([H|T], (H, Ta)) :- !,
|
||
|
list2and(T, Ta).
|
||
|
|
||
|
|
||
|
|
||
|
list2or([X], X) :-
|
||
|
X\=;(_, _), !.
|
||
|
|
||
|
list2or([H|T], (H ; Ta)) :- !,
|
||
|
list2or(T, Ta).
|
||
|
|
||
|
|
||
|
|
||
|
choose_clausesc(_G, C, [], C).
|
||
|
|
||
|
choose_clausesc(CG0, CIn, [D|T], COut) :-
|
||
|
member((N, R, S), D),
|
||
|
choose_clauses_present(N, R, S, CG0, CIn, COut, T).
|
||
|
|
||
|
choose_clausesc(G0, CIn, [D|T], COut) :-
|
||
|
member((N, R, S), D),
|
||
|
new_head(N, R, S, N1),
|
||
|
\+ already_present(N1, R, S, CIn),
|
||
|
\+ already_present(N1, R, S, G0),
|
||
|
impose_dif_cons(R, S, CIn),
|
||
|
choose_clausesc(G0, [(N1, R, S)|CIn], T, COut).
|
||
|
|
||
|
|
||
|
|
||
|
choose_clauses_present(N, R, S, CG0, CIn, COut, T) :-
|
||
|
already_present_with_a_different_head_ground(N, R, S, CG0), !,
|
||
|
choose_clausesc(CG0, CIn, T, COut).
|
||
|
|
||
|
choose_clauses_present(N, R, S, CG0, CIn, COut, T) :-
|
||
|
already_present_with_a_different_head(N, R, S, CIn),
|
||
|
choose_a_head(N, R, S, CIn, C1),
|
||
|
choose_clausesc(CG0, C1, T, COut).
|
||
|
|
||
|
|
||
|
|
||
|
/* new_head(N, R, S, N1)
|
||
|
* ---------------------
|
||
|
* This predicate selects an head for rule R different from N with substitution
|
||
|
* S and returns it in N1.
|
||
|
*/
|
||
|
new_head(N, R, S, N1) :-
|
||
|
rule_by_num(R, S, Numbers, Head, _Body),
|
||
|
Head\=uniform(_, _, _), !,
|
||
|
nth0(N, Numbers, _Elem, Rest),
|
||
|
member(N1, Rest).
|
||
|
|
||
|
new_head(N, R, S, N1) :-
|
||
|
rule_uniform(_A, R, S, Numbers, 1/Tot, _L, _Number, _Body),
|
||
|
listN(0, Tot, Numbers),
|
||
|
nth0(N, Numbers, _Elem, Rest),
|
||
|
member(N1, Rest).
|
||
|
|
||
|
|
||
|
|
||
|
/* already_present(N, R, S, [(N, R, SH)|_T])
|
||
|
* -----------------------------------------
|
||
|
* This predicate checks if a rule R with head N and selection S (or one of its
|
||
|
* generalizations is in C) is already present 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).
|
||
|
|
||
|
|
||
|
|
||
|
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).
|
||
|
|
||
|
already_present_with_a_different_head_ground(N, R, S, [(NH, R, SH)|_T]) :-
|
||
|
S=SH, NH \= N.
|
||
|
|
||
|
already_present_with_a_different_head_ground(N, R, S, [_H|T]) :-
|
||
|
already_present_with_a_different_head_ground(N, R, S, T).
|
||
|
|
||
|
|
||
|
|
||
|
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).
|
||
|
|
||
|
|
||
|
|
||
|
/* choose_a_head(N, R, S, [(NH, R, SH)|T], [(NH, R, SH)|T])
|
||
|
* --------------------------------------------------------
|
||
|
* This predicate chooses and returns an head.
|
||
|
* It instantiates a more general rule if it is contained in C with a different
|
||
|
* head.
|
||
|
*/
|
||
|
choose_a_head(N, R, S, [(NH, R, SH)|T], [(NH, R, SH)|T]) :-
|
||
|
S=SH,
|
||
|
dif(N, NH).
|
||
|
|
||
|
/* choose_a_head(N, R, S, [(NH, R, SH)|T], [(NH, R, S), (NH, R, SH)|T])
|
||
|
* --------------------------------------------------------------------
|
||
|
* This predicate chooses and returns an head.
|
||
|
* It instantiates a more general rule if it is contained in C with a different
|
||
|
* head.
|
||
|
* It ensures the same ground clause is not generated again.
|
||
|
*/
|
||
|
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).
|
||
|
|
||
|
|
||
|
|
||
|
listN(N, N, []) :- !.
|
||
|
|
||
|
listN(NIn, N, [NIn|T]) :-
|
||
|
N1 is NIn+1,
|
||
|
listN(N1, N, T).
|
||
|
|
||
|
|