简体   繁体   English

序言超出本地堆栈空间/无限递归

[英]Prolog out of local stack space/ infinite recursion

I have read other similar questions and answers on this site, but can't seem to find the answer to my particular problem. 我已经在该网站上阅读了其他类似的问题和答案,但似乎找不到我特定问题的答案。 I am trying to encode a maze in Prolog. 我正在尝试在Prolog中编码一个迷宫。 From region 0, you can move freely to regions 1 or region 3. From region 3, you can move freely to region 0, region 4, or region 5, etc. I want to find the all paths of length 7 from the beginning to the end (from 0 to 14). 从区域0,您可以自由移动到区域1或区域3。从区域3,您可以自由移动到区域0,区域4或区域5,依此类推。我想找到从头到尾长度为7的所有路径。结束(从0到14)。 I have encoded the problem in the following manner in SWI-Prolog: 我在SWI-Prolog中以以下方式编码了问题:

    region(0).
    region(1).
    region(2).
    region(3).
    region(4).
    region(5).
    region(6).
    region(7).
    region(8).
    region(9).
    region(10).
    region(11).
    region(12).
    region(13).
    region(14).
    region(15).

    connection(0,1).                %connection exists between these two regions
    connection(0,3).        
    connection(1,2).
    connection(1,8).
    connection(1,7).
    connection(3,4).
    connection(3,5).
    connection(7,9).
    connection(7,5).
    connection(7,8).
    connection(5,6).
    connection(8,10).
    connection(8,11).
    connection(11,12).
    connection(11,13).
    connection(13,15).
    connection(13,14).

    double_link(X,Y) :-
       region(X),
       region(Y),
       ( connection(X,Y) | connection(Y,X) ). %can go from region X to region Y, and vice versa

    path(X,Y) :-
       double_link(X,Y).
    path(X,Y) :-
       double_link(X,Z),
       path(Z,Y).

When I execute path(14,0). 当我执行path(14,0). I get true . 我是true However, when I execute path(0,14)., I run out of local stack space. 但是,当我执行path(0,14)。时,我用完了本地堆栈空间。 I don't know how that can be. 我不知道怎么回事。 Thanks for any help! 谢谢你的帮助!

You said: 你说:

When I execute path(14,0). 当我执行path(14,0). I get true . 我是true

That is half of the truth! 那是事实的一半! Oh, even less than that! 哦,比这还少! In fact you get true not once but many times! 其实你true不是一次,而是很多次!

?- path(14,0).
true ;
true ;
true ;
true ;
true ;
true ...

There is a simple way to avoid typing ; 有一个简单的避免输入的方法; or SPACE all the time. 或一直保持空格 Simply use the goal false . 只需将目标false

?- path(14,0), false
    **LOOPS**

And now, you can also add such false -goals into your program. 现在,您还可以在程序中添加这些false目标。 In this manner you are ruling out parts of the program ; 通过这种方式,您可以排除程序的某些部分; and if the remaining part still loops, you know that there must be a problem there. 如果其余部分仍然循环播放,则说明那里一定有问题。 This is what I got: 这就是我得到的:

region(0) :- false.
% ...
region(12) :- false.
region(13).
region(14).
region(15) :- false.

connection(0,1) :- false.
% ...
connection(13,15) :- false.
connection(13,14).

double_link(X,Y) :-
   region(X),
   region(Y),
   ( connection(X,Y) ; connection(Y,X) ).

path(X,Y) :- false,
   double_link(X,Y).
path(X,Y) :-
   double_link(X,Z),
   path(Z,Y), false.

So in this remaining part that loop has to be addressed. 因此,在其余部分中,必须解决该循环。 It should be now self-explanatory, isn't it? 现在应该不言自明了,不是吗?

The problem arises because you can go in circles in the maze. 出现问题是因为您可以在迷宫中盘旋。 Eg in your maze you have the connections 0 - 1 - 7 - 5 - 3 - 0 . 例如,在您的迷宫中,连接0 - 1 - 7 - 5 - 3 - 0 You have not taken any measures to ensure that the search does not follow those circles blindly. 您尚未采取任何措施来确保搜索不会盲目追踪这些圈子。

A usual approach would be to add an argument to your path predicate that contains the already visited regions (initially empty). 通常的方法是在您的路径谓词中添加一个参数,其中包含已经访问过的区域(最初为空)。 Then you have to ensure when you go to a new location X that X is not in that list (eg with nonmember(X,Visited) ). 然后,您必须确保在转到新位置X X不在该列表中(例如,具有nonmember(X,Visited) )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM