【问题标题】:Prolog - Help fixing a ruleProlog - 帮助修复规则
【发布时间】:2012-01-13 21:38:09
【问题描述】:

我有一个充满事实的数据库,例如:

overground(newcrossgate,brockley,2).
overground(brockley,honoroakpark,3).
overground(honoroakpark,foresthill,3).
overground(foresthill,sydenham,2).
overground(sydenham,pengewest,3).
overground(pengewest,anerley,2).
overground(anerley,norwoodjunction,3).
overground(norwoodjunction,westcroydon,8).
overground(sydenham,crystalpalace,5).
overground(highburyandislington,canonbury,2).
overground(canonbury,dalstonjunction,3).
overground(dalstonjunction,haggerston,1).
overground(haggerston,hoxton,2).
overground(hoxton,shoreditchhighstreet,3).

示例:newcrossgate 到布罗克利需要 2 分钟。

然后我创建了一个规则,这样如果我输入查询 istime(newcrossgate,honoroakpark,Z)。那么prolog应该给我在这两个站之间旅行的时间。 (我制定的规则旨在计算任何两个站点之间的距离,而不仅仅是相邻站点)。

istime(X,Y,Z):- istime(X,Y,0,Z); istime(Y,X,0,Z).
istime(X,Y,T,Z):- overground(X,Y,Z), T1 is T + Z.
istime(X,Y,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
istime(X,Y,Z):- overground(X,B,T), istime(B,X,T1), Z is T + T1.

它似乎非常适合 newcrossgate 到前几个车站,例如 newcrossgate 到 Foresthill 或 sydenham。然而,在测试 newcrossgate 到 westcroydon 需要 26 分钟之后,我尝试了 newcrossgate 到水晶宫,prolog 说它应该需要 15 分钟......尽管事实上它是 westcroydon 之后的下一站。显然这里出了点问题,但是它适用于大多数车站,但时不时地偶尔会出现错误,谁能告诉我有什么问题吗? :S

【问题讨论】:

  • 最后一个子句正确吗?你似乎是从 X 到 B,然后从 B 到 X。你什么时候去 Y?

标签: database prolog rules accumulator


【解决方案1】:

这个问题和你上一个问题本质上是一样的,唯一的不同就是你需要边走边累积时间。

我看到的一件事是您的“公共”谓词istime/3 试图做太多事情。它应该做的就是为累加器播种并调用工作谓词istime/4。由于您正在寻找双向的路线/时间,因此公共谓词应该只是

istime( X , Y , Z ) :- istime( X , Y , 0 , Z ) .
istime( X , Y , Z ) :- istime( Y , X , 0 , Z ) .

上面基本上是你的istime/3谓词的第一个子句

istime(X,Y,Z):- istime(X,Y,0,Z); istime(Y,X,0,Z).

istime/3 的剩余子句,递归子句:

istime(X,Y,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
istime(X,Y,Z):- overground(X,B,T), istime(B,X,T1), Z is T + T1.

应该正确地成为istime/4 的一部分并且具有累加器。这就是你的问题所在。

再试一次并编辑您的问题以显示下一次迭代。如果你还是不明白,我会告诉你一些不同的方法。

一些提示

  1. 您的“worker”谓词可能看起来很像您之前的“查找两个站点之间的路线”练习,但它会有一个额外的参数,即经过时间的累加器。

  2. 有两种特殊情况。如果您使用“在两个站点之间查找路线”解决方案中使用的方法,则特殊情况是

    • A 和 B 直接相邻。
    • A 和 B 通过至少一个中间站连接。

还有另一种方法,可能被描述为使用前瞻,在这种情况下,特殊情况是

  • A 和 B 相同,在这种情况下,您就到了。
  • A 和 B 不是,而是由零个或多个中间停靠点连接。

FWIW,您不必期望经过时间最短或跳数最少的路线是找到的第一个解决方案。回溯会产生所有的路径,但是它们被发现的顺序与事实在数据库中的存储顺序有关。图的最低成本搜索完全是另一锅鱼。

【讨论】:

    【解决方案2】:

    您是否尝试过使用; 循环浏览答案? 26 分钟 不是 newcrossgate 和 westcroydon 之间的最短时间...

    编辑:我的错!显然,较短的结果是由于您的代码中的错误造成的(请参阅我对第 4 条的评论)。但是,您的代码是正确的,15 分钟是 newcrossgate 和水晶宫之间的最短路线。只是因为有一条路线从 newcrossgate 到 westcroydon,然后是水晶宫,这并不意味着它是最短路线,或者您的程序将首先产生的路线。

    更新:如果您在寻找某些路线的答案时遇到问题,我建议将第 3 条更改为:

    istime(X,Y,_,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
    

    原因很简单:您的第一个子句将 X 与 Y 交换,这很好,因为您说的路线是对称的。但是,第 3 个子句并没有从中受益,因为它从未被交换过的子句调用。忽略第 3 个参数(无论如何您都没有使用),从而让第 1 个子句调用第 3 个参数可能会解决您的问题,因为现在将出现一些以前未使用的有效路由。

    (另外:我同意 Nicholas Carey 的回答,最好将第三个参数用作累加器;但正如我所说,暂时忽略它可能会起作用)

    【讨论】:

    • 我更改了代码的最后一行,将 B 到 X 的路线更改为 B 到 Y,我希望这就是你的意思。我现在正在测试它是否可以正常工作。 istime(X,Y,Z):- overground(X,B,T), istime(B,Y,T1), Z 是 T + T1。
    • 该死的似乎不起作用...每次我尝试从里士满到吠叫之类的长途旅行时,我都会误会...
    • @JimmyK 不是真的,如果你仔细观察,changed 子句与第三个子句相同(将变量的名称从 A 更改为 B 无关紧要),所以它只会重复计算。
    • 嗯,我不太确定该怎么做,每次我在脑海中读出代码时,在我看来它应该可以正常工作......哦,找到最短的路线并不是真的没关系,只要它有效,它就有效
    • @JimmyK 我刚刚更新了我的答案,看看它是否有帮助。总的来说,你的原始代码没问题,你只需要注意一些小细节。
    【解决方案3】:

    要使其发挥作用,您需要对上一条中所述的两次旅程进行相反的操作。 保持谓词原样,istime(X,Y,Z) 并创建另一个包含反向旅程的子句。 通过这种方式,它适用于所有站点。 (久经考验)

    【讨论】:

    • 嗯.. 似乎不太好用,我得到了两次不同的时间,以一种方式完成相同的确切旅程,然后以相反的方式完成
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多