我怎样才能计算递归规则的递归次数?

时间:2016-01-29 21:03:35

标签: recursion prolog transitive-closure

我处理一个问题;我想计算我的代码递归规则的递归次数。

我的程序检查对象是否是计算机硬件的组件(通过组件(X,Y)谓词).E.g组件(计算机,主板) - >真正。

它甚至检查对象不是直接组件而是另一组件的子组件的情况。例如。子组件(计算机,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).

好吧,为了计算给定组件Y给定组件Y的组件数量 - 即递归规则子组件(X,Y)的递归次数,我做了一些失败的尝试。但是,我在下面介绍它们:

i)

 number_of_components(X,Y,N,T):- T is N+1, subcomponent(X,Y).
 number_of_components(X,Y,N,T):- M is N+1, subcomponent(X,Z), number_of_components(Z,Y,M,T).

在这种情况下,我收到此错误:"错误:是/ 2:参数未充分实例化"。

ⅱ)

number_of_components(X,Y):- bagof(Y,subcomponent(X,Y),L),
                        length(L,N),
                        write(N).

在这种情况下,我得到的结果是1或11,在此数字之后为真,这就是全部。完全没有逻辑!

ⅲ)

count_elems_acc([], Total, Total).
count_elems_acc([Head|Tail], Sum, Total) :-
      Count is Sum + 1, 
      count_elems_acc(Tail, Count, Total).


number_of_components(X,Y):- bagof(Y,subcomponent(X,Y),L),
                        count_elems_acc(L,0,Total),
                        write(Total).

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

那么,我做错了什么,我该怎么写?

我期待着阅读你的答案!

2 个答案:

答案 0 :(得分:3)

您可以做的一件事是使用call_with_depth_limit/3进行迭代加深。您调用谓词(在本例中为subcomponent/2)。在获得结果之前增加限制,如果得到结果,则限制是使用的最深递归级别。您可以看到相关文档。

但是,你可以做的更容易。您的数据库可以表示为未加权,定向,非循环图。因此,将整个数据库放在有向图中,如library(ugraphs)中所实现的那样,并找到它的传递闭包。在传递闭包中,组件的邻居都是其子组件。完成!

制作图表:

findall(C-S, component(C, S), Es),
vertices_edges_to_ugraph([], Es, Graph)

找到传递闭包:

transitive_closure(Graph, Closure)

找到子组件:

neighbours(Component, Closure, Subcomponents)

Subcomponents将是一个列表,您可以使用length/2获取其长度。

修改

一些随意的想法:在你的情况下,你的数据库似乎描述了一个定义为非定向和非循环的图形(组件 - 子组件关系严格按照一种方式,对吧?)。这就是没有必要在图表中定义自己的步骤,例如在this great question and answers中很好地演示。因此,您不需要定义自己的递归subcomponent谓词等。

将数据库表示为使用它时的术语,而不是将其保持为平面表,这是一个很棒的事情,就是编写操纵它的谓词变得微不足道:你可以免费获得Prolog的回溯。由于库(ugraph)使用的图形的S表示非常适合Prolog,因此您最有可能最终获得更高效的程序。

答案 1 :(得分:1)

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

?- 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%

另一方面,最重要的是子句变量中的关系。这是Prolog的精髓。所以,试着阅读 - 用简单的英语说 - 你的规则。

i)number_of_components(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)number_of_components(X,Y)如果Y是X的number_of_components,那么这将有意义。然后,

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 - 或多或少 - 等于长度/ 2,因此结果(打印)似乎是正确的,但同样,它是X和Y之间的关系你的最后一句未能确立。只有当目的是执行副作用时才应使用子句打印...例如,调试...