prologswi-prologreify

Eliminating three-valued logic predicates choice points with if_/3


I'm trying to completely remove the choice points of my logical or/3 predicate that relates two logical variables and associates it with a third that can be either true or 'u' (unknown) (and when it's false, the predicate should fail).

Edit: adequated descriptions of the logical predicates to my own needs.

The simple predicate works:

or(A,B,true) :-
    A = true, B = true ; A = true, B = false ; A = false, B = true.
or(A,B,u) :-
    A = u, B = u; A = u, B = false ; A = false, B = u.

but yields multiple unnecessary choice points like:

?- or(A,false,C).      
A = C, C = true ;
A = C, C = u ;
false.

I tried using if_/3 and reif package but i always end up with a choice point somewhere. This is one of the iterations I managed to make, but it still has a useless choice point in the end:

or3(A, B, C) :-
    if_( C = u
       , if_( A = u
            , ( B = u ; B = false)
            , ( A = false, B = u )
            ),
    if_( C = true
       , if_( A = true
            , ( B = true ; B = false)
            , ( A = false, B = true )
            )
       , false
       )
    ).

?- or3(A,false,C). 
Correct to: "tri_logic:or3(A,false,C)"? yes
A = C, C = u ;
A = C, C = true ;
false.

I also tried directly using =/3 and ;/3 to implement a version that only works for true values, but the results were even pretty much the same:

or3(A,B,C) :-
    =( C, true, T),
    ;( ( A = true, B = true ), ( A = true, B = false ), T1 ),
    ;( T1=true, ( A = false, B = true), T).


?- or3(A,false,C). 
Correct to: "tri_logic:or3(A,false,C)"? yes
A = C, C = u ;
A = C, C = true ;
false.

What am I missing here?


Solution

  • To prevent unwanted choicepoints, both parameters must be considered simultaneously. Whereas if_ considers a single value.

    Can use the relational aspect of Prolog - list the possibilities:

    % Using table to improve determinism
    :- table and_or/4.
    % Bool (or u), Bool (or u), AND, OR
    and_or(true, true, true, true).
    and_or(false, true, false, true).
    and_or(u, true, u, true).
    and_or(true, false, false, true).
    and_or(false, false, false, false).
    and_or(u, false, false, u).
    and_or(true, u, u, true).
    and_or(false, u, false, u).
    and_or(u, u, u, u).
    

    The table directive in swi-prolog is being used here to prevent unwanted choicepoints by indexing the and_or lookup.

    Then, it's simply a case of performing the lookup:

    andt(A, B, T) :-
        and_or(A, B, T, _).
        
    ort(A, B, T) :-
        and_or(A, B, _, T).
    

    Examples:

    ?- andt(true, u, T).
    T = u.  % No unwanted choicepoint
    
    ?- ort(true, u, T).
    T = true.  % No unwanted choicepoint