Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 339
false Avatar asked Feb 05 '21 10:02

false


3 Answers

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).
like image 129
DuDa Avatar answered Nov 16 '22 02:11

DuDa


Expanding on the definition of dif/2:

dif_to_orto(A, B, C):-
   when((?=(A,B), ?=(A, C)), (A \== B -> true ; A \== C)).

Sample runs:

?- 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).
when((?=(A, B), ?=(A, C)),  (A\==B->true;A\==C)).
like image 20
gusbro Avatar answered Nov 16 '22 00:11

gusbro


Here is one suggestion. As far as I can tell, it does not create choice points or redundant solutions:

dif_to_orto(A, B, C) :-
   when(?=(A,B),(A==B->dif(A,C);true)),
   when(?=(A,C),(A==C->dif(A,B);true)).

For each disjunct, wait until it is known to be true or false. Once known, check its truth and, if false, then post the other disjunct.

like image 6
jnmonette Avatar answered Nov 16 '22 02:11

jnmonette