如何在没有多余答案/解决方案的情况下紧凑地表达不等式的分离

考虑一下我尝试过的:

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


回答

此解决方案首先等待 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) :-
   when(?=(A,B),(A==B->dif(A,C);true)),
   when(?=(A,C),(A==C->dif(A,B);true)).

对于每个析取,等待直到知道它是真还是假。一旦知道,检查它的真实性,如果是错误的,然后发布另一个分离。


回答

扩展diff/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)).


以上是如何在没有多余答案/解决方案的情况下紧凑地表达不等式的分离的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>