假设我们有以下内容:
edge(a, 1, 10).
edge(b, 2, 20).
edge(c, 3, 30).
edge(d, 4, 40).
我想提取这些事实的矩阵表示(M
),例如
M = [[a,b,c,d],[1,2,3,4],[10,20,30,40]]
这是一个简单明了的解决方案:
edgeMatrix(M) :-
findall(A, edge(A, _, _), As),
findall(B, edge(_, B, _), Bs),
findall(C, edge(_, _, C), Cs),
M = [As, Bs, Cs].
此方法存在一些问题,但 viz :
所以问题是:在Prolog中实现这一目标最常用的方法是什么?
答案 0 :(得分:5)
怎么样:
edgeMatrix(M) :-
findall([A,B,C],edge(A,B,C),Trans),
transpose(Trans,M).
现在您只需从REST framework JWT Auth模块导入transpose/2
矩阵,或者像clpfd
那样自己实现一个矩阵(是的,我知道这很懒,但是什么是重新发明轮子的意义?)。
如果我在swipl
中运行,我会:
?- edgeMatrix(M).
M = [[a, b, c, d], [1, 2, 3, 4], [10, 20, 30, 40]].
看起来就像你想要的那样。
你当然可以说计算transpose/2
还有一些计算开销,但收集阶段只进行一次(如果这些不仅仅是事实,而是来自条款的答案)也是昂贵的,而且我认为一个模块无论如何都可能非常有效地实现条款。
答案 1 :(得分:2)
我认为你不会找到一个既普通又极其高效的解决方案。这是N = 3的简单解决方案:
edges(Edges) :-
Goal = edge(_A, _B, _C),
findall(Goal, Goal, Edges).
edges_abcs_([], [], [], []).
edges_abcs_([edge(A,B,C)|Edges], [A|As], [B|Bs], [C|Cs]) :-
edges_abcs_(Edges, As, Bs, Cs).
edges_abcs([As, Bs, Cs]) :-
edges(Edges),
edges_abcs_(Edges, As, Bs, Cs).
添加100,000个edge/3
个事实后,执行如下操作:
?- time(edges_abcs(M)).
% 200,021 inferences, 0.063 CPU in 0.065 seconds (97% CPU, 3176913 Lips)
M = [[a, b, c, d, 1, 2, 3, 4|...], [1, 2, 3, 4, 1, 2, 3|...], [10, 20, 30, 40, 1, 2|...]].
为了进行比较,以下是问题的实施衡量标准:
?- time(edgeMatrix_orig(M)).
% 300,043 inferences, 0.061 CPU in 0.061 seconds (100% CPU, 4896149 Lips)
M = [[a, b, c, d, 1, 2, 3, 4|...], [1, 2, 3, 4, 1, 2, 3|...], [10, 20, 30, 40, 1, 2|...]].
以下是Willem基于transpose/2
的更一般的解决方案:
?- time(edgeMatrix_transpose(M)).
% 700,051 inferences, 0.098 CPU in 0.098 seconds (100% CPU, 7142196 Lips)
M = [[a, b, c, d, 1, 2, 3, 4|...], [1, 2, 3, 4, 1, 2, 3|...], [10, 20, 30, 40, 1, 2|...]].
因此,就推理数量而言,我的解决方案似乎最佳:findall/3
的100,000次推断和遍历列表的100,000次推断。该问题的解决方案每个findall/3
有100,000个推论,但仅此而已。然而,它稍微快一点,因为它的内存效率更高:分配的所有内容都在最终解决方案中结束,而我的程序则分配100,000个edge/3
项的列表,然后必须进行垃圾回收。 (在SWI-Prolog中,如果打开探查器和/或GC跟踪,则可以看到垃圾收集。)
如果我真的需要尽可能快地将和推广到许多不同的N值,我会写一个宏扩展到类似的东西问题中的解决方案。
编辑:如果取消“惯用”要求,我会将edge
数据库存储为SWI-Prolog全局变量中的列表。在这种情况下,我的单通道实现可以在没有findall/3
开销的情况下工作,并且不会产生中间垃圾。