Recursion 如何计算递归规则的递归数?

Recursion 如何计算递归规则的递归数?,recursion,prolog,transitive-closure,Recursion,Prolog,Transitive Closure,我处理一个问题;我想计算我的代码的递归规则执行多少次递归 我的程序检查对象是否是计算机硬件的组件(通过组件(X,Y)谓词)。例如组件(计算机,主板)->true 它甚至会检查对象不是直接组件而是另一个组件的子组件的情况。例如,子组件(计算机、ram)->正确。(因为ram是主板的组成部分,主板是计算机的组成部分) 因为我的代码超过400行,所以我将向您展示表单组件(X,Y)和规则子组件(X,Y)的一些谓词 下面是一些谓词: component(computer,case). component(

我处理一个问题;我想计算我的代码的递归规则执行多少次递归

我的程序检查对象是否是计算机硬件的组件(通过组件(X,Y)谓词)。例如组件(计算机,主板)->true

它甚至会检查对象不是直接组件而是另一个组件的子组件的情况。例如,子组件(计算机、ram)->正确。(因为ram是主板的组成部分,主板是计算机的组成部分)

因为我的代码超过400行,所以我将向您展示表单组件(X,Y)和规则子组件(X,Y)的一些谓词

下面是一些谓词:

component(computer,case).
component(computer,power_supply).
component(computer,motherboard).
component(computer,storage_devices).
component(computer,expansion_cards).
component(case,buttons).
component(case,fans).
component(case,ribbon_cables).
component(case,cables).

component(motherboard,cpu).
component(motherboard,chipset).
component(motherboard,ram).
component(motherboard,rom).
component(motherboard,heat_sink).
component(cpu,chip_carrier).
component(cpu,signal_pins).
component(cpu,control_pins).
component(cpu,voltage_pins).
component(cpu,capacitors).
component(cpu,resistors).
等等

我的规则是:

subcomponent(X,Z):- component(X,Z).
subcomponent(X,Z):- component(X,Y),subcomponent(Y,Z).
为了计算给定组件X到给定组件Y的组件数量,即递归规则子组件(X,Y)的递归数量,我做了一些失败的尝试。然而,我在下面介绍它们:

(一)

在本例中,我得到一个错误:“error:is/2:参数没有充分实例化”

(ii)

在这种情况下,我得到的结果是1或11,在这个数字之后是真的,仅此而已。完全没有逻辑

(iii)

在这种情况下,根据我的知识库,我得到的结果数字是不正确的。(或者我误译了它们,因为这种方式似乎有一些逻辑)

那么,我做错了什么,我应该写什么来代替呢


我期待着阅读你的答案

谓词的调用次数可能是一个困难的概念。我会说,使用你的系统提供的

?- profile(number_of_components(computer,X)).
20===================================================================
Total time: 0.00 seconds
=====================================================================
Predicate                       Box Entries =    Calls+Redos     Time
=====================================================================
$new_findall_bag/0                        1 =        1+0         0.0%
$add_findall_bag/1                       20 =       20+0         0.0%
$free_variable_set/3                      1 =        1+0         0.0%
...
so:count_elems_acc/3                      1 =        1+0         0.0%
so:subcomponent/2                        22 =        1+21        0.0%
so:component/2                           74 =       42+32        0.0%
so:number_of_components/2                 2 =        1+1         0.0%
另一方面,最重要的是子句变量之间的关系。这是序言的精髓。所以,试着用通俗易懂的英语阅读你的规则

i)
组件的数量(X,Y,N,T)
N,T与X有什么关系?我不能说。所以

?- leash(-all),trace.
?- number_of_components(computer,Y,N,T).
   Call: (7) so:number_of_components(computer, _G1931, _G1932, _G1933)
   Call: (8) _G1933 is _G1932+1
ERROR: is/2: Arguments are not sufficiently instantiated
   Exception: (8) _G1933 is _G1932+1 ? 
ii)
分量的个数(X,Y)
如果Y是X的分量个数,那么这里很有意义

number_of_components(X,Y):- bagof(S,subcomponent(X,S),L), length(L,Y).
这就产生了

?- number_of_components(computer,X).
X = 20.
或者更好

?- aggregate(count, S^subcomponent(computer,S), N).
N = 20.
注意
S
的用法。它在出现的目标中被“存在量化”。也就是说,在证明目标的同时允许改变


iii)count_elements_acc/3或多或少等于length/2,因此结果(打印)似乎是正确的,但最后一个子句未能确定的是X和Y之间的关系。仅当目的是执行副作用时,才应使用从条款打印。。。例如,调试…

您可以做的一件事是使用。调用谓词(在本例中为
subcomponent/2
)。增加限制直到得到结果,如果得到结果,限制是使用的最深递归级别。您可以查看这方面的文档

然而,你可以做一些更容易的事情。您的数据库可以表示为未加权、有向、非循环的图。因此,将整个数据库固定在一个有向图中(如中所实现),并找到它的传递闭包。在传递闭包中,一个组件的邻居都是它的子组件。完成了

要制作图表,请执行以下操作:

findall(C-S, component(C, S), Es),
vertices_edges_to_ugraph([], Es, Graph)
要查找传递闭包,请执行以下操作:

transitive_closure(Graph, Closure)
以及查找子组件:

neighbours(Component, Closure, Subcomponents)
子组件将是一个列表,您可以使用
length/2
获取其长度

编辑

一些随机的想法:在您的例子中,您的数据库似乎描述了一个定义为有向和无环的图(组件-子组件关系严格来说是单向的,对吧?)。这就是为什么不需要定义自己在图形中的漫游,例如中很好地演示的。因此,您不需要定义自己的递归
子组件
谓词等


在使用数据库时,将其表示为一个术语而不是将其保持为一个平面表的一个好处是,编写操作它的谓词变得非常简单:您可以免费获得Prolog的回溯。由于库(ugraph)使用的图的S表示法非常适合于Prolog,您很可能也会得到一个更高效的程序。

我认为这是《Prolog的艺术》一书中元解释器的一个例子。我检查了它,但我没有找到任何示例代码作为解决方案或类似的内容来导航me@CapelliC(注:“ugraphs”中的“u”表示“未加权”,而不是“无向”。)OP问题中的数据库正是一个未加权、有向、无环的图。所以这感觉像是正确的数据结构。这个库(ugraphs)有一些非常有用的谓词,你可以免费得到。我认为你的答案非常好,我的答案只是提供了另一种方法。是的,当然你完全正确(+1)。。。我浏览了一下文档,同时删除了我愚蠢的评论…@Boris我应该创建一个规则
number\u of\u components(X,Y)
,其中包括你上面键入的谓词或其他我不懂的东西吗?@Jimbo\u ai是的。或者,如果你只查阅带有
component/2
规则的文件,你可以在顶层逐字输入这些规则(中间有逗号),你就会得到你想要的答案。@Jimbo\u ai如果我是你,我会做以下事情:首先,制作一个只包含
component/2
规则的文件。然后,从最高层进行咨询。然后,试着像我的答案一样找到findall(…)
,看看你得到了什么。然后,将
顶点\u边\u添加到\u ugraph(…)
到查询中,然后查看得到的结果。然后,将
传递闭包(…)
添加到查询中,等等。一旦知道发生了什么,就可以开始考虑如何在添加到程序中的规则中组织这些。
findall(C-S, component(C, S), Es),
vertices_edges_to_ugraph([], Es, Graph)
transitive_closure(Graph, Closure)
neighbours(Component, Closure, Subcomponents)