如何在没有多余答案/解决方案的情况下紧凑地表达不等式的分离
考虑一下我尝试过的:
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)).