next up previous contents
Next: Quelques prédicats utiles en Up: Annexes Previous: Comparaisons avec les maximes

Probabilistic Truth Maintenance System

Le PTMS a été décrit dans le rapport (page 11). Le programme qui suit est une implémentation du PTMS en Prolog.

/******************************************************************************/
/*                                                                            */
/* Probabilistic Truth Maintenance System                                     */
/*                                                                            */
/******************************************************************************/

/* Le reseau est stocke dans la BD de Prolog (soit ptms cette cle)
 * Dans la suite : key-name = format designe un objet de type 'name'
 * enregistre avec la cle 'key' au format 'format'
 *
 * Liste des PTMS en cours d'utilisation :
 *  recorded_ptms-KEY = KEY
 *
 * Reseau des connaissances :
 *
 *  ptms-PTMS   = ptms(IRK,IIRK,MSK,GAME)
 *
 *  ptms_ir-IR  = ir(GAME,LHS,RHS,NLHS,NRHS,COND,P)
 *  ptms_iir-IIR= iir(REF,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)
 *  ptms_ms-MS  = ms(REF,A,P,JUSTIF,CONSEQ)
 *  PREMISSES   = [REF]
 *  CONCL       = [REF]
 *  JUSTIF      = [REF]
 *  CONSEQ      = [REF]
 *
 * Donnees intermediaires :
 *  state_to_propagate  : file des etats a propager (DEPTH,STATE,PROBA)
 */

:-module(ptms,
    [
        new_ptms/1,         % new_ptms(PTMS)
        delete_ptms/1,      % delete_ptms(PTMS)
        print_ptms/1,       % print_ptms(PTMS)
        copy_ptms/2,        % copy_ptms(PTMS1,PTMS2)
        get_ptms_game/2,    % get_ptms_game(PTMS,GAME)
        set_ptms_game/2,    % set_ptms_game(PTMS,GAME)
        new_ir/3,           % new_ir(PTMS,IR,GAME)
        ask/3,              % ask(PTMS,A,P)
        store/4             % store(PTMS,DEPTH,A,P)
    ]
).

:-use_module(cd-tools).

/******************************************************************************/
/*                                                                            */
/* Definition des connecteurs logiques                                        */
/*                                                                            */
/******************************************************************************/

:-op(
    [
        970,    xfx,    #,
        960,    xfy,    |,
        950,    xfx,    then,
        500,    yfx,    or,
        400,    yfx,    and,
        200,    fx,     -
    ]
).

/******************************************************************************/
/*                                                                            */
/* Initialisation du module                                                   */
/*                                                                            */
/******************************************************************************/

init:-
    empty_db([recorded_ptms,state_to_propagate,rule_to_connect,state_to_connect,
				state_to_eventually_connect,connection_to_propagate]),
    forall(recorded(recorded_ptms,PTMS),delete_ptms(PTMS)).

/******************************************************************************/
/*                                                                            */
/* Creation d'un nouveau PTMS                                                 */
/*                                                                            */
/******************************************************************************/

new_ptms(PTMS):-
    (   nonvar(PTMS)
    ;   gensym(ptms,PTMS)
    ),
    !,
    delete_ptms(PTMS),
    concat(PTMS,'_ir',IRK),
    concat(PTMS,'_iir',IIRK),
    concat(PTMS,'_ms',MSK),
    recordz(PTMS,ptms(IRK,IIRK,MSK,no_game_at_initialisation)),
    recordz(recorded_ptms,PTMS).

/******************************************************************************/
/*                                                                            */
/* Destruction d'un PTMS                                                      */
/*                                                                            */
/******************************************************************************/

delete_ptms(PTMS):-
    (   recorded(recorded_ptms,PTMS,REF1)
    ->  erase(REF1)
    ;   true
    ),
    recorded(PTMS,ptms(IRK,IIRK,MSK,_),REF2),
    !,
    empty_db([IRK,IIRK,MSK]),
    erase(REF2).
delete_ptms(_).

/******************************************************************************/
/*                                                                            */
/* Affichage du reseau d'un PTMS                                              */
/*                                                                            */
/******************************************************************************/

print_ptms(PTMS):-
    recorded(PTMS,ptms(IRK,IIRK,MSK,CUR_GAME)),
    !,
    writef("Jeu courant : %t\n",[CUR_GAME]),
    (   nl,
        recorded(IRK,ir(GAME,LHS,RHS,_,_,COND,P)),
        numbervars((GAME,LHS,RHS,COND),0,_),
        writef("%t : %t then %t\t| %t\t# %t\n",[GAME,LHS,RHS,COND,P]),
        fail
    ;   nl,
        recorded(IIRK,iir(REF,GAME,LHS,RHS,_,_,P,_,_)),
        numbervars((GAME,LHS,RHS),0,_),
        writef("%t\t%t : %t then %t\t\t# %t\n",[REF,GAME,LHS,RHS,P]),
        fail
    ;   nl,
        recorded(MSK,ms(REF,A,P,_,_)),
        numbervars(A,0,_),
        writef("%t\t%t\t# %t\n",[REF,A,P]),
        fail
    ;   nl
    ).

/******************************************************************************/
/*                                                                            */
/* Duplication d'un PTMS                                                      */
/*                                                                            */
/******************************************************************************/

copy_ptms(PTMS1,PTMS2):-
    nonvar(PTMS1),
    new_ptms(PTMS2),
    get_ptms_game(PTMS1,GAME),
    set_ptms_game(PTMS2,GAME),
    recorded(PTMS1,ptms(IRK1,IIRK1,MSK1,_)),
    recorded(PTMS2,ptms(IRK2,IIRK2,MSK2,_)),
    copy(IRK1,IRK2),
    copy(IIRK1,IIRK2),
    copy(MSK1,MSK2).

copy(K1,K2):-
    forall(recorded(K1,X),recordz(K2,X)).

/******************************************************************************/
/*                                                                            */
/* Lecture du jeu courant d'un PTMS                                           */
/*                                                                            */
/******************************************************************************/

get_ptms_game(PTMS,GAME):-
    recorded(PTMS,ptms(_,_,_,GAME)).

/******************************************************************************/
/*                                                                            */
/* Changement du jeu courant d'un PTMS                                        */
/*                                                                            */
/******************************************************************************/

set_ptms_game(PTMS,GAME):-
    recorded(PTMS,ptms(IRK,IIRK,MSK,_),REF),
    erase(REF),
    recordz(PTMS,ptms(IRK,IIRK,MSK,GAME)).

/******************************************************************************/
/*                                                                            */
/* Ajout d'une nouvelle regle d'inference                                     */
/*                                                                            */
/******************************************************************************/

new_ir(PTMS,(LHS then RHS|COND#P),GAME):-!,new_ir0(PTMS,LHS,RHS,COND,P,GAME).
new_ir(PTMS,(LHS then RHS|COND),GAME):-!,new_ir0(PTMS,LHS,RHS,COND,1,GAME).
new_ir(PTMS,(LHS then RHS#P),GAME):-!,new_ir0(PTMS,LHS,RHS,true,P,GAME).
new_ir(PTMS,(LHS then RHS),GAME):-!,new_ir0(PTMS,LHS,RHS,true,1,GAME).

new_ir0(PTMS,LHS,RHS,COND,P,GAME):-
    recorded(PTMS,ptms(IRK,_,_,_)),
    neg(LHS,NLHS),
    neg(RHS,NRHS),
    recordz(IRK,ir(GAME,LHS,RHS,NLHS,NRHS,COND,P)).

neg(P,NP):-simpl(-P,NP).

/******************************************************************************/
/*                                                                            */
/* Interrogation d'un PTMS                                                    */
/*                                                                            */
/******************************************************************************/

ask(PTMS,A,P):-
    recorded(PTMS,ptms(_,_,MSK,_)),
    simpl(A,A0),
%   findall(P0,ask0(MSK,A0,P0),LP),
%   max(LP,P).
    ask0(MSK,A0,P).

ask0(MSK,A,P):-
    var(A),
    !,
    recorded(MSK,ms(_,A,P,_,_)).
%   fail.

ask0(_,true,1):-!.
ask0(_,false,0):-!.

ask0(MSK,A and B,P):-
    !,
    ask0(MSK,A,PA),
    ask0(MSK,B,PB),
    P is min(PA,PB).

ask0(MSK,A or B,P):-
    !,
    ask0(MSK,A,PA),
    ask0(MSK,B,PB),
    P is max(PA,PB).

ask0(MSK,-A,P):-
    !,
    ask0(MSK,A,PA),
    P is 1-PA.

ask0(MSK,A,P):-
    (   recorded(MSK,ms(_,A,P,_,_))
    *-> true
    ;   P=0.5
    ).

simpl(V,V):- var(V), !.
simpl(-V,-V):- var(V), !.
simpl(-(-X),U):- !, simpl(X,U).
simpl(-(X and Y),U or V):- !, simpl(-X,U), simpl(-Y,V).
simpl(-(X or Y),U and V):- !, simpl(-X,U), simpl(-Y,V).
simpl(T,TS):-
    functor(T,F,N),
    !,
    functor(TS,F,N),
    simpl_args(N,T,TS).
simpl(T,T).

simpl_args(0,_,_):-!.
simpl_args(N,T,TS):-
    arg(N,T,A),
    simpl(A,AS),
    arg(N,TS,AS),
    N1 is N-1,
    simpl_args(N1,T,TS).

/******************************************************************************/
/*                                                                            */
/* Mise a jour d'un PTMS                                                      */
/*                                                                            */
/******************************************************************************/

store(PTMS,DEPTH,A,P):-
    simpl(A,A0),
    store0(PTMS,DEPTH,A0,P),
    !,
%   update(PTMS,DEPTH,A,P).
    propagate(PTMS).
store(_,_,_,_).

store1(PTMS,DEPTH,A,P):-
    simpl(A,A0),
    store0(PTMS,DEPTH,A0,P).

/* La mise a jour se fait de maniere a modifier le moins possible la
 * base de connaissances.
 */

/* store0 echoue s'il n'y a pas de modif a faire ! */

store0(_,_,V,_):-
    var(V),
    !,
    fail.

/* Conjonction : (A and B)(P)
 * KB={A(Pa), B(Pb)}
 * On veut : min{Pa',Pb'}>=P
 * donc Pi'=max(Pi,P)
 */

store0(K,D,A and B,P):-
    !,
    ask(K,A,PA),
    ask(K,B,PB),
    (   P>PA
    ->  store0(K,D,A,P),
        (   P>PB
        ->  store0(K,D,B,P)
        ;   true
        )
    ;   P>PB
    ->  store0(K,D,B,P)
    ).
        

/* Disjonction : (A or B)(P)
 * KB={A(Pa), B(Pb)}
 * On veut : max{Pa', Pb'}>=P
 * Donc si Pa<P et Pb<P, on maj l'etat le plus proche de P
 */

store0(K,D,A or B,P):-
    !,
    ask(K,A,PA),
    (   PA<P
    ->  ask(K,B,PB),
        (   PB<P
        ->  (   PA<PB           % PB plus proche de P que PA
            ->  store0(K,D,B,P)
            ;   store0(K,D,A,P)
            )
        )
    ).

/* Negation : (-A)(P)
 * KB={A(Pa)}
 * (-A)(P) : "A est faux avec une proba >= P
 * donc A est vrai avec une proba =< 1-P
 * donc Pa'=min{Pa,1-P}
 */

store0(_,_,-V,_):-
    var(V),
    !,
    fail.

%store0(K,D,-(A and B),P):-!, store0(K,D,-A or -B,P).
%store0(K,D,-(A or B),P):-!, store0(K,D,-A and -B,P).
%store0(K,D,-(-A),P):-!, store0(K,D,A,P).

store0(K,D,-A,P):-
    !,
    ask(K,A,PA),
    NPA is 1-P,
    (   NPA<PA
    ->  recordz(state_to_propagate,(D,A,NPA))
    ).

/* Fait positif : A(P)
 * KB={A(Pa)}
 * A(P) : "A est vrai avec une proba >= P
 * donc Pa'=max{Pa,P}
 */

store0(K,D,A,P):-
    ask(K,A,PA),
    (   P>PA
    ->  recordz(state_to_propagate,(D,A,P))
    ).

/******************************************************************************/
/*                                                                            */
/* Propagation des modifications dans le reseau                               */
/*                                                                            */
/******************************************************************************/

propagate(PTMS):-
    recorded(state_to_propagate,(D,A,P),REF),
    erase(REF),
    update(PTMS,D,A,P),
    (   D > 0
    ->  D1 is D-1,
        recorded(PTMS,ptms(_,IIRK,MSK,GAME)),
        recorded(MSK,ms(_,A,_,JUSTIF,CONSEQ)),
        !,
        (   member(REF_IIR,CONSEQ),
            recorded(IIRK,iir(REF_IIR,GAME,LHS,RHS,_,_,P_IIR,_,_)),
            ask(PTMS,LHS,P_LHS),
            P_RHS is min(P_LHS,P_IIR),
            store1(PTMS,D1,RHS,P_RHS),
            fail
        ;   member(REF_IIR,JUSTIF),
            recorded(IIRK,iir(REF_IIR,GAME,_,_,NLHS,NRHS,P_IIR,_,_)),
            ask(PTMS,NRHS,P_NRHS),
            P_NLHS is max(P_NRHS,1-P_IIR),
            store1(PTMS,D1,NLHS,P_NLHS),
            fail
        ;   true
        )
    ),
    propagate(PTMS).
propagate(_).   % Pas d'etat a propager

/******************************************************************************/
/*                                                                            */
/* Mise a jour des etats propages                                             */
/*                                                                            */
/******************************************************************************/

update(PTMS,D,A,P):-
    recorded(PTMS,ptms(_,_,MSK,_)),
    (   recorded(MSK,ms(REFA,A,_,JUSTIF,CONSEQ),REF)
    ->  erase(REF),
        recordz(MSK,ms(REFA,A,P,JUSTIF,CONSEQ))
    ;   gen_ref(REFA),
        recordz(MSK,ms(REFA,A,P,[],[])),
        connect(PTMS,REFA,D)
    ).

/******************************************************************************/
/*                                                                            */
/* Connexion d'un etat au PTMS                                                */
/*                                                                            */
/******************************************************************************/

connect(_,_,0):-!.
connect(PTMS,REFA,DEPTH):-
    recorded(PTMS,ptms(_,IIRK,MSK,_)),
    (   instanciated_inference_rule(PTMS,IIR),
        (   rule_uses(IIR,REFA),
            new_rule(IIRK,IIR)
        ->  IIR=iir(REF_IIR,_,_,_,_,_,_,_,_),
            gen_ref(REF_IIR),
            recordz(rule_to_connect,IIR),
            (   recorded(state_to_eventually_connect,ST0,REF),
                erase(REF),
                ST=ST0,  %simpl(ST0,ST),
                recordz(state_to_connect,ST),
                fail
            ;   true
            )
        ;   empty_db(state_to_eventually_connect)
        ),
        fail
    ;   recorded(state_to_connect,(NEW_REF,A,P),REF),
        erase(REF),
        recordz(MSK,ms(NEW_REF,A,P,[],[])),
        DEPTH1 is DEPTH-1,
        recordz(connection_to_propagate,(DEPTH1,NEW_REF)),
        fail
    ;   recorded(rule_to_connect,IIR,REF),
        erase(REF),
        connect_rule(PTMS,IIR),
        fail
    ;   recorded(connection_to_propagate,(D,R),REF)
    ->  erase(REF),
        connect(PTMS,R,D)
    ;   true
    ).

connect_rule(PTMS,iir(REF_IIR,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)):-
    recorded(PTMS,ptms(_,IIRK,MSK,_)),
    recordz(IIRK,iir(REF_IIR,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)),
    (   member(REF_MS,PREMISSES),
        recorded(MSK,ms(REF_MS,A,PA,JUSTIF,CONSEQ),REF),
        erase(REF),
        recordz(MSK,ms(REF_MS,A,PA,JUSTIF,[REF_IIR|CONSEQ])),
        fail
    ;   member(REF_MS,CONCL),
        recorded(MSK,ms(REF_MS,A,PA,JUSTIF,CONSEQ),REF),
        erase(REF),
        recordz(MSK,ms(REF_MS,A,PA,[REF_IIR|JUSTIF],CONSEQ)),
        fail
    ;   true
    ).

rule_uses(iir(_,_,_,_,_,_,_,PREMISSES,_),REFA):-
    memberchk(REFA,PREMISSES),
    !.
rule_uses(iir(_,_,_,_,_,_,_,_,CONCL),REFA):-
    memberchk(REFA,CONCL).

new_rule(IIRK,iir(_,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)):-
    \+recorded(IIRK,iir(_,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)),
    \+recorded(rule_to_connect,iir(_,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)).

/******************************************************************************/
/*                                                                            */
/* Instanciation d'une regle d'inference                                      */
/*                                                                            */
/******************************************************************************/

/* Le backtracking fournit toutes les instances possibles
 */

instanciated_inference_rule(PTMS,
							iir(_,GAME,LHS,RHS,NLHS,NRHS,P,PREMISSES,CONCL)):-
    recorded(PTMS,ptms(IRK,_,MSK,GAME)),
    recorded(IRK,ir(GAME,LHS0,RHS0,NLHS0,NRHS0,COND,P)),
    inst(LHS0,MSK,PREMISSES),
    COND,
    simpl(LHS0,LHS),
    simpl(RHS0,RHS),
    simpl(NLHS0,NLHS),
    simpl(NRHS0,NRHS),
    formula_items(RHS,MSK,CONCL).

inst(A,MSK,PA):-
    var(A),
    !,
    inst0(A,MSK,PA).

inst(A and B,MSK,PAB):-
    !,
    inst(A,MSK,PA),
    inst(B,MSK,PB),
    union(PA,PB,PAB).

inst(A or B,MSK,PAB):-
    !,
    inst(A,MSK,PA),
    inst(B,MSK,PB),
    union(PA,PB,PAB).

inst(-A,MSK,PA):-
    !,
    inst(A,MSK,PA).

inst(A,MSK,PA):-
    inst0(A,MSK,PA).

inst0(A,MSK,[REF]):- recorded(MSK,ms(REF,A,_,_,_)).
inst0(A,_,[REF]):- recorded(state_to_connect,(REF,A,_)).

formula_items(A,_,_):-
    var(A),
    !,
    fail.

formula_items(A and B,MSK,PAB):-
    !,
    formula_items(A,MSK,PA),
    formula_items(B,MSK,PB),
    union(PA,PB,PAB).

formula_items(A or B,MSK,PAB):-
    !,
    formula_items(A,MSK,PA),
    formula_items(B,MSK,PB),
    union(PA,PB,PAB).

formula_items(-A,MSK,PA):-
    !,
    formula_items(A,MSK,PA).

formula_items(A,MSK,[REFA]):-
    (   (   recorded(MSK,ms(REFA,A,_,_,_))
        ;   recorded(state_to_connect,(REFA,A,_))
        ;   recorded(state_to_eventually_connect,(REFA,A,_))
        )
    *-> true
    ;   gen_ref(REFA),
        recordz(state_to_eventually_connect,(REFA,A,0.5))
    ).



Christophe Delord
1998-09-02