How to express a disjunction of inequalities compactly without redundant answers/solutions
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).
This solution first awaits for 2 of the 3 variables to be comparable, then if it cannot decide whether the constraint should succeed adds a new constraint:
dif_to_orto(A, B, C) :-
when((?=(A, B) ; ?=(A, C) ; ?=(B, C)),
( ?=(A, B) ->
( A\==B -> true ; dif(A, C) )
;
(
?=(A, C) ->
( A\==C -> true ; dif(A, B) )
;
( B\==C -> true ; dif(A, B) )
)
)).
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, C);?=(B, C);?=(A, B)), (?=(A, B)->(A\==B->true;dif(A, C));?=(A, C)->(A\==C->true;dif(A, B));B\==C->true;dif(A, B))).
?- dif_to_orto(1, 2, Z).
true.
?- dif_to_orto(1, B, B).
dif(B, 1).
Reversing the checks:
dif_to_orto(A, B, C) :-
when((?=(A, B) ; ?=(A, C) ; ?=(B, C)),
(
A==B -> dif(A, C)
;
((A==C ; B==C) -> dif(A, B) ; true)
)).
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.