[英]Prolog binary addition
I need to implement binary addition in prolog, where binary numbers are represented as follows:我需要在prolog中实现二进制加法,其中二进制数表示如下:
0: bot
1 : o(bot)
2 -> 10: z(o(bot))
3 -> 11: o(o(bot))
10 -> 1010: z(o(z(o(bot))))
I've written this:我写过这个:
add(X,bot,X):-!.
add(bot,X,X):-!.
add(z(X),z(Y),Res):- add(X,Y,D), Res = z(D).
add(z(X),o(Y),Res):- add(X,Y,D), Res = o(D).
add(o(X),z(Y),Res):- add(X,Y,D), Res = o(D).
add(o(X),o(Y),Res):-addc(X,Y,D), Res = z(D).
addc(X,bot,Res):-add(X,o(bot),Res),!.
addc(bot,X,Res):-add(X,o(bot),Res),!.
addc(z(X),z(Y),Res):- add(X,Y,D),Res = o(D).
addc(z(X),o(Y),Res):-addc(X,Y,D),Res = z(D).
addc(o(X),z(Y),Res):-addc(X,Y,D),Res = z(D).
addc(o(X),o(Y),Res):-addc(X,Y,D),Res = o(D).
It works when the first 2 arguments are concrete:当前两个参数是具体的时,它起作用:
?-add(o(o(bot)),z(o(o(bot))),D).
D = o(z(z(o(bot))))
When one of the first 2 arguments is a variable, it goes into an infinite recursion:当前两个参数之一是变量时,它进入无限递归:
?-add(o(o(bot)),X,z(o(o(bot)))).
Stack limit (0.2Gb) exceeded
Stack sizes: local: 0.1Gb, global: 34.9Mb, trail: 11.6Mb
Stack depth: 1,524,958, last-call: 50%, Choice points: 762,476
Possible non-terminating recursion:
[1,524,958] add(bot, <compound s/1>, _1496)
[1,524,957] add(bot, <compound s/1>, <compound z/1>)
How can i make this work for any one non-concrete argument?我怎样才能使这项工作适用于任何一个非具体的论点?
(Using bot
for what is otherwise considered zero
, null
or 0
is a bit odd. Lattices are not our major concern here.) (使用bot
否则被认为是zero
, null
或0
有点奇怪。格子不是我们在这里的主要关注点。)
First, we try to understand why the program does not terminate.首先,我们试图理解为什么程序不会终止。 This can be quite tricky, in particular in presence of the !
这可能非常棘手,尤其是在!
which is one of Prolog's impure elements.这是Prolog的不纯元素之一。 They are needed to a certain degree, but here in this case, they are harmful only, as they are hindering our reasoning.它们在一定程度上是需要的,但在这种情况下,它们只是有害的,因为它们阻碍了我们的推理。 So instead of the first two cutful clauses, write 1所以不要写前两个cutful子句,而是写1
add(bot, X, X).
add(X, bot, X) :- dif(X, bot).
and similarly for the next two cuts.接下来的两次剪辑也是如此。 Note that those two clauses are now disjoint.请注意,这两个子句现在是不相交的。 After this we have a pure monotonic program and thus we can apply various reasoning techniques.在此之后,我们有一个纯单调程序,因此我们可以应用各种推理技术。 In this case, a failure-slice is just what we need.在这种情况下, 故障切片正是我们所需要的。 To better understand the reason for non-termination, I will add goals false
into the program, for there is a nice property we can exploit: If the new program does not terminate, then also the old one will not terminate.为了更好地理解不终止的原因,我将在程序中添加目标false
,因为我们可以利用一个很好的特性:如果新程序不终止,那么旧程序也不会终止。 In this manner we can narrow down the problem to a smaller part of the original program.通过这种方式,我们可以将问题缩小到原始程序的一小部分。 After a couple of tries, I came up with the following failure-slice:经过几次尝试,我想出了以下失败片段:
add(bot,X,X) :- false.add(X,bot,X) :- false, dif(X,bot).add(z(X),z(Y),Res) :- false, add(X,Y,D), Res = z(D).add(z(X),o(Y),Res) :- false, add(X,Y,D), Res = o(D).add(o(X),z(Y),Res) :- false, add(X,Y,D), Res = o(D).add(o(X),o(Y),Res) :- addc(X,Y,D), false,Res = z(D). addc(bot,X,Res) :- add(X,o(bot),Res), false. addc(X,bot,Res) :- dif(X, bot), add(X,o(bot),Res), false.addc(z(X),z(Y),Res) :- false, add(X,Y,D), Res = o(D).addc(z(X),o(Y),Res) :- false, addc(X,Y,D), Res = z(D).addc(o(X),z(Y),Res) :- false, addc(X,Y,D), Res = z(D).addc(o(X),o(Y),Res) :- addc(X,Y,D), false,Res = o(D).?- add(o(o(bot)),X,z(o(o(bot)))).
Out of the ~2^23 possible failure slices, this appears to be a minimal one.在 ~2^23 个可能的故障切片中,这似乎是最小的一个。 That is, any further false
makes the program terminate.也就是说,任何进一步的false
都会使程序终止。
Let's look at it: Everywhere Res
is either ignored or just passed further on.让我们看看它:Everywhere Res
要么被忽略,要么被进一步传递。 Therefore the third argument has no influence on termination whatsoever.因此,第三个参数对终止没有任何影响。 But you can put all those Res =
equations just after the :-
.但是您可以将所有这些Res =
方程放在:-
。 That's the earliest possible place.那是最早的地方。
add(bot,X,X).
add(X,bot,X):- dif(X,bot).
add(z(X),z(Y), z(D)) :- add(X,Y,D).
add(z(X),o(Y), o(D)) :- add(X,Y,D).
add(o(X),z(Y), o(D)) :- add(X,Y,D).
add(o(X),o(Y), z(D)) :- addc(X,Y,D).
addc(bot,X,Res):- add(X,o(bot),Res).
addc(X,bot,Res):- dif(X, bot), add(X,o(bot),Res).
addc(z(X),z(Y),o(D)):- add(X,Y,D).
addc(z(X),o(Y),z(D)):- addc(X,Y,D).
addc(o(X),z(Y),z(D)):- addc(X,Y,D).
addc(o(X),o(Y),o(D)):- addc(X,Y,D).
Also cTI gives favorable termination conditions: cTI还给出了有利的终止条件:
% NTI summary: Complete result is optimal.
add(A,B,C)terminates_if b(A),b(B);b(C).
% optimal. loops found: [add(z(_),z(_),z(_)),add(o(bot),o(o(_)),z(z(_))),add(o(o(_)),o(bot),z(z(_)))]. NTI took 8ms,72i,30i
addc(A,B,C)terminates_if b(A),b(B);b(C).
% optimal. loops found: [addc(z(z(_)),z(z(_)),o(z(_))),addc(bot,o(_),z(_)),addc(o(_),bot,z(_))]. NTI took 4ms,96i,96i
So add/3
terminates either if the first two, or the last argument are given.因此,如果给出前两个参数或最后一个参数,则add/3
终止。 So you do not need the first argument.所以你不需要第一个参数。 In stead, even the more general query terminates:相反,即使是更一般的查询也会终止:
?- add(X,Y,z(o(o(bot)))).
X = bot, Y = z(o(o(bot)))
; X = z(o(o(bot))), Y = bot
; X = z(bot), Y = z(o(o(bot)))
; X = z(o(o(bot))), Y = z(bot)
; X = z(z(bot)), Y = z(o(o(bot)))
; X = z(z(o(bot))), Y = z(o(bot))
; X = z(z(z(bot))), Y = z(o(o(bot)))
; X = z(z(o(bot))), Y = z(o(z(bot)))
; X = z(o(bot)), Y = z(z(o(bot)))
; X = z(o(o(bot))), Y = z(z(bot))
; X = z(o(z(bot))), Y = z(z(o(bot)))
; X = z(o(o(bot))), Y = z(z(z(bot)))
; X = o(bot), Y = o(z(o(bot)))
; X = o(z(o(bot))), Y = o(bot)
; X = o(z(bot)), Y = o(z(o(bot)))
; X = o(z(o(bot))), Y = o(z(bot))
; X = o(z(z(bot))), Y = o(z(o(bot)))
; X = o(z(o(bot))), Y = o(z(z(bot)))
; X = Y, Y = o(o(bot))
; X = o(o(bot)), Y = o(o(z(bot)))
; X = o(o(z(bot))), Y = o(o(bot))
; X = Y, Y = o(o(z(bot)))
; false.
1 And even better, use if_/3
of library reif
for SICStus and SWI to keep those clauses as determinate as possible. 1 更好的是,对SICStus和SWI使用库reif
if_/3
以保持这些子句尽可能确定。
add(A, B, C) :- if_(A = bot, B = C, ( B = bot, A = C ) ).
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.