我处理一个问题;我想计算我的代码递归规则的递归次数。
我的程序检查对象是否是计算机硬件的组件(通过组件(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).
在这种情况下,根据我的知识基础得到结果数字不正确。(或者我误解了它们 - 因为这种方式似乎有一些逻辑)
那么,我做错了什么,我该怎么写?
我期待着阅读你的答案!
答案 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之间的关系你的最后一句未能确立。只有当目的是执行副作用时才应使用子句打印...例如,调试...