如何在没有冗余的情况下简洁地表达不等式的析取 answers/solutions

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

考虑一下我的尝试:

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

虽然从声明的角度来看这个定义很好,但它包含许多冗余。想到:

?- 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

甚至在这种情况下也不行:

?- 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

至少,这是一个没有冗余的案例...

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

...但是有一个浪费资源的剩余选择点。

很少有这种定义有效的情况:

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

此外,最一般的查询会产生两个答案,这对我来说听起来效率很低:

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

... 这也会产生以下冗余:

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

一个dif/2就够了!

有没有办法避免所有这些冗余和低效率?

这是一个建议。据我所知,它不会创建选择点或冗余解决方案:

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

对于每个析取,等待直到知道它是真还是假。一旦知道,检查它的真实性,如果为假,则 post 另一个析取。

扩展 dif/2 的定义:

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

样本运行:

?- 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)).

此解决方案首先等待 3 个变量中的 2 个具有可比性,然后如果无法确定约束是否应该成功,则添加新约束:

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) )
             )
         )).

样本运行:

?- 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).

撤销支票:

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)
         )).

这个怎么样:

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

测试用例:

?- 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).