Reification integration issues
我为最近的问题 Segregating Lists in Prolog 提供了以下基于 clpfd 的代码:
1 2 3 4 5 6 7
| list_evens_odds ([],[],[]).
list_evens_odds ([X |Xs ],[X |Es ],Os ) :-
X mod 2 # = 0,
list_evens_odds (Xs ,Es ,Os ).
list_evens_odds ([X |Xs ],Es ,[X |Os ]) :-
X mod 2 # = 1,
list_evens_odds (Xs ,Es ,Os ). |
简洁而纯粹,但会留下许多不必要的选择点。考虑:
1
| ?- list_evens_odds([1,2,3,4,5,6,7],Es,Os). |
上面的查询为 [1,2,3,4,5,6,7] 中的每个非奇数项留下一个无用的选择点。
替代实施
使用@false 在Prolog union for A U B U C 中演示的具体化技术可以减少不必要的选择点的数量。实现可以更改为:
1 2 3 4 5
| list_evens_odds ([],[],[]).
list_evens_odds ([X |Xs ],Es ,Os ) :-
if_ (# <=>(X mod 2 # = 0), (Es =[X |Es0 ],Os = Os0 ),
(Es = Es0 , Os =[X |Os0 ])),
list_evens_odds (Xs ,Es0 ,Os0 ). |
为了直接与 clpfd-reification 交互,if_/3 的实现可以这样调整:
1 2 3 4
| if_ ( C_1 , Then_0 , Else_0 ) :-
call(C_1 ,Truth01 ),
indomain (Truth01 ),
( Truth01 == 1 -> Then_0 ; Truth01 == 0, Else_0 ). |
当然,(=)/3 也需要适应这个约定。
底线
所以我想知道:使用 0 和 1 作为真值而不是 false 和 true 是个好主意吗?
我在那条路上错过了问题吗?请帮忙!提前谢谢你!
- 快速修复 ..., X mod 2 #= M, if_(M=0, ...。此外,您可以给另一个 if_/3 取另一个名字,例如 if0_/3
我已经重新考虑了我提议的 if_/3 的"双重用途",我觉得我现在通过它看得更清楚了。
@false 和@lurker 的评论以及@mat 的回答在帮助我理解方面发挥了应有的作用。谢谢!
我获得的"见解"绝不是戏剧性的;我还是想和你分享:
像我一样调整 if_/3 是可行的,并且可能与某些 LOC 相同。
但是,它混合了两个在程序上完全不同的概念:默认情况下,clpfd 传播然后延迟。物化术语平等OTOH立即迫使选择。
因此,将这两个用例分开会更清晰。当然,"清洁确实仅次于虔诚"……
在 SWI-Prolog 中,你可以使用 zcompare/3:
1 2 3 4 5 6 7 8 9 10 11
| :- use_module (library (clpfd )).
list_evens_odds ([], [], []).
list_evens_odds ([X |Xs ], Es , Os ) :-
Mod # = X mod 2,
zcompare (Ord , 0, Mod),
ord_ (Ord , X , Es0 , Es , Os0 , Os ),
list_evens_odds (Xs , Es0 , Os0 ).
ord_ (=, X , Es0 , [X |Es0 ], Os , Os ).
ord_ (<, X , Es , Es , Os0 , [X |Os0 ]). |
查询示例:
1 2 3
| ?- list_evens_odds([1,2,3,4,5,6,7], Es, Os).
Es = [2, 4, 6],
Os = [1, 3, 5, 7]. |
- 这看起来不必要地晦涩难懂。为什么将 {0,1} 映射到 {<,=} 而不是直接在 ord_/6 中使用它?
-
发生这种情况是因为我使用您的代码作为起点,它使用一个具体化的值进行分支。使用 zcompare/3,不再需要具体化,因此我将其删除。
-
这不是我的意思,物化很好。 zcompare 是没有意义的。您可以只使用实体化布尔值作为 ord_/6 的第一个参数。
-
有几个 CLP(FD) 系统还不支持物化。 zcompare/3 或类似的构造更容易添加到此类系统中,并且仍然为与比较相关的此类分支提供声明性解决方案,因此我使用它来展示您如何提供,而无需处理许多具体化的谓词,类似于 CLP(FD) 中原始问题的 if_/3 构造。
-
mat:"有几个 CLP(FD) 系统还不支持物化"——真的吗?"zcompare/3 或类似的结构更容易添加到这样的系统中" - 怎么样?它本质上是一种具体化的比较,并不容易实现。没有必要重新发明轮子。
-
这是不正确的,但不是在这里讨论它的地方。
-
是的,你仍然可以很容易地找到这样的系统,但我当然希望他们在不久的将来添加它。还请参见例如 SWI-Prolog 中 zcompare/3 的来源:实现它不需要具体化。我认为这是一个重要的特性,而且我也认为正确地具体化 CLP(FD) 约束比人们一开始可能意识到的要难。例如,您仍然可以在当前系统中轻松找到产生错误结果的案例(尤其是涉及除零的案例)。
-
我同意。我只是想表明正确的具体化远比实现 zcompare/3 困难得多,而不是显示任何特定系统当前的缺陷,所以我对评论进行了概括。
-
然而,我所说的是"zcompare 本质上是一个具体的比较,并没有更容易实现",仅此而已。如果您想认真讨论,请给我发电子邮件。
-
完全具体化有一个显着差异:zcompare/3 不支持复合算术表达式作为其参数,而仅支持单个变量或整数。这就是为什么它比算术表达式的全面具体化更容易实现的原因。像 X/0 这样的 CLP(FD) 表达式,这使得具体化比人们最初预期的更难实现,它不能出现在 zcompare/3 中。要实现 zcompare/3,您基本上只需要 freeze/2 和一个传播器,比一般具体化的代码要少得多。
直接的解决方案(适用于任何可具体化的 clp(fd) 条件)似乎是
1 2 3 4 5 6 7
| :- use_module (library (clpfd )).
list_evens_odds ([],[],[]).
list_evens_odds ([X |Xs ],Es ,Os ) :-
B # <==> (X mod 2 # = 0),
freeze (B , (B =1 -> Es =[X |Es0 ],Os =Os0 ; Es =Es0 ,Os =[X |Os0 ])),
list_evens_odds (Xs ,Es0 ,Os0 ). |
0/1 或真/假是否被用作真值在这里并不重要。在算术求解器中首选 0/1 约定的原因很简单,您可以轻松地在算术约束中重用真值,例如把它们加起来,等等。