Search code examples
prologprolog-dif

How to express a disjunction of inequalities compactly without redundant answers/solutions


Consider what I have tried:

dif_to_orto(A, B, C) :-
   (  dif(A, B)
   ;  dif(A, C)
   ).

While this definition is fine from a declarative viewpoint it contains many redundancies. Think of:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
   A = 1, B = 2, C = 2
;  A = 1, B = 2, C = 2.   % unexpected redundant solution

And not even in this case:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
   A = 1, B = 2, C = 3
;  A = 1, B = 2, C = 3.   % unexpected redundant solution

At least, here is a case without redundancy...

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
   A = 1, B = 2, C = 1
;  false.                 % unexpected inefficient leftover choicepoint

...but with a resource-wasting leftover choicepoint.

Rare are the occasions where this definition is efficient:

?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
   A = 1, B = 1, C = 2.

Also that the most general query produces two answers sounds very inefficient to me:

?- dif_to_orto(A, B, C).
   dif:dif(A,B)
;  dif:dif(A,C).

... which produces also the following redundancy:

?- dif_to_orto(1, B, B).
   dif:dif(1,B)
;  dif:dif(1,B).    % unexpected redundant answer

One dif/2 would be enough!

Is there a way to avoid all these redundancies and inefficiencies?


Solution

  • How about this one:

    dif_to_orto(A, B, C) :-
       dif(A-A, B-C).
    

    The test cases:

    ?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
    A = 1,
    B = C, C = 2.
    
    ?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
    A = 1,
    B = 2,
    C = 3.
    
    ?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
    A = C, C = 1,
    B = 2.
    
    ?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
    A = B, B = 1,
    C = 2.
    
    ?- dif_to_orto(A, B, C).
    dif(f(B, A), f(A, C)).
    
    ?- dif_to_orto(1, B, B).
    dif(B, 1).