如何在下面的代码中修剪选择点使其更有效(Prolog)?

时间:2015-06-13 23:51:17

标签: prolog prolog-cut

在下面给出的代码中,有!(cut)修剪选择点以提高效率。我非常确定reverse谓词和agent_do_moves谓词是必不可少的。

solve_task(Task,Cost):-
    agent_current_position(oscar,P),
    solve_task_a(Task,[b(0,0,P)],[],R,Cost,_NewPos),!,  % prune choice point for efficiency
    reverse(R,[_Init|Path]),
    agent_do_moves(oscar,Path).

1 个答案:

答案 0 :(得分:7)

以上示例中的剪辑具有以下效果:

理想情况下,提交solve_task_a/6内可能发生的搜索到找到的第一个答案。这样可以释放资源,找到进一步的答案,从而改善空间消耗。

范围问题

然而,与此同时,它也可能隐藏 agent_current_position/2的更多答案。当然,对这个目标有进一步的答案没有多大意义,但这可能是一个错误,恰好睡了一会儿,只是变得活跃但在最糟糕的情况下仍未被发现。

出于这个原因,最好写而不是剪切

    ...,
    once( solve_task_a( ... ) ),
    ...

这将范围精确地限制在您想表达的范围内。

坚定性问题

但这不是问题的唯一可能来源。我看到了这个变量Cost。当你打电话给solve_task(Task, Cost)时,它会被实例化吗?我可以在这里做很多猜测。但至少这个变量可能会影响Prolog将承诺的答案。因此solve_task(Task, 99)solve_task(Task, Cost), Cost = 99可能会产生不同的答案。事实上,后者甚至可能会失败。据说存在此类问题的谓词缺乏坚定性

为了说明在这种情况下如何容易丢失坚定性,请考虑(已经改进的)程序的这个(可运行的)草图:

solve_task(Task,Cost):-
    % agent_current_position(oscar,P),
    once(solve_task_a(Task,[b(0,0,P)],[],R,Cost,_NewPos)),
    true.

solve_task_a(_, _, _, _, 20, _).
solve_task_a(_, _, _, _, 30, _).

现在

?- solve_task(a, Cost).
Cost = 20.

?- solve_task(a, 30).
true.

?- solve_task(a, Cost), Cost = 30.
false.

通过干净地测试变量Cost,可以轻松解决此问题,例如产生实例化错误的Cost >= 0应该Cost是一个未实例化的变量。但是如果你想(如你在评论中指出的那样)确定成本,你需要这样说:

solve_task(Task,Cost):-
    % agent_current_position(oscar,P),
    once(solve_task_a(Task,[b(0,0,P)],[],R,CostX,_NewPos)),
    CostX = Cost
    true.

通过这种方式,我们可以确定Cost无法影响solve_task_a/6的结果(euh - 假设CostTask之间没有别名 - 但我们假设那个时刻)。有人说,输出统一被置于提交之后。

许多人会告诉您,不需要额外的照顾,因为您永远不会以给定的费用使用solve_task(Task, Cost)。可能是这种情况,但你确定你会记得吗?你确定源代码会记住它(没有任何动态检查)吗?如果你的心智能力负担过重,这种隐含的假设很容易累积。

并不总是有一个简单的出路。但通常有可能坚持逻辑纯度。在这种情况下,您不必记住任何此类假设。

无论如何,我建议你暂时不要进入Prolog的这些部分。而是坚持以及保留的其他干净,单调的程序。有很多东西需要学习!

相关问题