在 SWI-Prolog 中聚合谓词
我需要计算 some_predicate(X)
成立的所有 X
,而且确实有很多这样的 X
。 最好的方法是什么?
第一个线索是findall
,累积到一个列表并返回列表的长度。
countAllStuff( X ) :-
findall( Y
, permutation( [1,2,3,4,5,6,7,8,9,10], Y )
, List
),
length( List, X ).
(permutation/2
只是一个虚拟占位符,表明有很多结果,并且计算计数的方式很糟糕)
显然,对于真实数据,将会有一个堆栈溢出。
?- countAllStuff( X ).
ERROR: Out of global stack
然后,我尝试用 setof
替换 findall
,但无济于事。
最后,我找到了 [aggregate
][1](可点击)谓词系列,并尝试使用 aggregate/3
和 aggregate/4< /code>:
?- aggregate(count, permutation([1,2,3,4], X), Y ).
X = [1, 2, 3, 4],
Y = 1 .
?- aggregate(count, [1,2,3,4], permutation([1,2,3,4], X), Y ).
X = [1, 2, 3, 4],
Y = 1 ;
X = [1, 2, 4, 3],
Y = 1 ;
我认为这都是错误的。我需要得到这样的东西:
?- aggregate(count, permutation([1,2,3,4], X), Y ).
Y = 24 .
我做错了什么?
如何声明谓词来计算正确的答案? [1]: http: //www.swi-prolog.org/pldoc/doc/home/vnc/prolog/lib/swipl/library/aggregate.pl
I need to count all X
for which some_predicate(X)
holds, and there really a lot of such X
.
What is the best way to do that?
First clue is to findall
, accumulate to a list and return the length of the list.
countAllStuff( X ) :-
findall( Y
, permutation( [1,2,3,4,5,6,7,8,9,10], Y )
, List
),
length( List, X ).
(permutation/2
is only a dummy placeholder demonstrating that there are many results and that it's bad way to compute the count)
Obviously, with real data, there will be a stack overflow.
?- countAllStuff( X ).
ERROR: Out of global stack
Then, I'm trying to replace findall
with setof
, to no avail.
At last, I've found the [aggregate
][1] (clickable) family of predicates, and trying to use aggregate/3
and aggregate/4
:
?- aggregate(count, permutation([1,2,3,4], X), Y ).
X = [1, 2, 3, 4],
Y = 1 .
?- aggregate(count, [1,2,3,4], permutation([1,2,3,4], X), Y ).
X = [1, 2, 3, 4],
Y = 1 ;
X = [1, 2, 4, 3],
Y = 1 ;
It's all wrong, I think. I need to get something like this:
?- aggregate(count, permutation([1,2,3,4], X), Y ).
Y = 24 .
What am I doing wrong?
How can I declare a predicate to conpute the right answer?
[1]: http://www.swi-prolog.org/pldoc/doc/home/vnc/prolog/lib/swipl/library/aggregate.pl
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用存在量化变量,就像使用
setof
一样:Use an existentially quantified variable, as you would with
setof
:在 SWI-Prolog 中,有一个更高效的版本,它也可以避免锁定全局存储。因此,只需使用 nb_setval 和 nb_getval 即可获得至少 3 倍的性能(更多关于多线程)。
不久前,另一个问题是关于计算解决方案。作为聚合的基础,它是学习 Prolog 时的一个明显的停止点。为了评估我们使用这些单线程语义等效调用所获得的效率增益:
在我的系统上,我得到
In SWI-Prolog there is a much more efficient version, that also avoid locking the global store. So simply using nb_setval and nb_getval you gain at least 3 times the performance (more on multithreading).
Just little time ago another question was on counting solutions. Being the base of aggregation it's an obvious stop point while learning Prolog. To evaluate the efficiency gain we get using these monothread semantically equivalent calls:
On my system, i get
还有
aggregate_all/3
:但是,就运行时和堆栈溢出而言,它似乎与您的
findall
+length
表现得同样好解决方案:您可以使用
assert
/retract
来计算解决方案,这很慢,但确实避免了“堆栈外”问题:There is also
aggregate_all/3
:However, as far as runtime and stack overflows are concerned it seems to perform equally well to your
findall
+length
solution:You can count the solutions using
assert
/retract
, this is quite slow but does avoid the "out of stack" problem:这是 Kaarel 帖子的附录。同时,一些Prolog系统更新了
aggregate/3
和aggregate_all/3
的实现。因此,不再出现“超出全局堆栈”错误:在 SWI-Prolog 中:
在 Jekejeke Prolog 中:
新的实现不会首先计算列表,然后计算列表的长度。相反,他们使用某种全局变量作为计数器。这种方法也用于
sum
、max
等......This is an addendum to Kaarel’s post. Meanwhile some Prolog systems have updated their implementation of
aggregate/3
andaggregate_all/3
. So there is not anymore an "Out of global stack" error:In SWI-Prolog:
In Jekejeke Prolog:
The new implementations do not first compute a list, and then count the length of the list. Rather they use some kind of global variable as a counter. This approach is also used for
sum
,max
, etc...