在Prolog中断言中间结果

在Prolog中断言中间结果,prolog,dynamic-programming,Prolog,Dynamic Programming,这就是问题所在 定义一个谓词sigmaN,S,使S=1+2+…+N,并记住查询中的每个新中间结果。例如,在查询sigma3,S之后,它将像sigma2,3,sigma3,6这样的东西存储到数据库中,这样我们以后就不需要重复和无用的工作了 我试着用下面的方法来解决它 sigmares(1,1). mysigma(N,A,Sum) :- sigmares(N,SN), Sum is SN+A, !. mysigma(N1,Acc,Sum) :- N is N1-1

这就是问题所在

定义一个谓词sigmaN,S,使S=1+2+…+N,并记住查询中的每个新中间结果。例如,在查询sigma3,S之后,它将像sigma2,3,sigma3,6这样的东西存储到数据库中,这样我们以后就不需要重复和无用的工作了

我试着用下面的方法来解决它

sigmares(1,1).

mysigma(N,A,Sum) :-
    sigmares(N,SN),
    Sum is SN+A,
    !.

mysigma(N1,Acc,Sum) :-
    N is N1-1,
    A is Acc + N1,
    mysigma(N,A,Sum),
    assertz(sigmares(N1,Sum)). % <<<<<<<<<< This line doesn't work properly.

sigma(N,X) :-
    mysigma(N,0,X).

assertz生产线存在一些问题。由于sum只能初始化一次,它是sum从1到N的值,因此对于查询sigma3,将插入sigma2,6、sigma3,6。有没有其他方法来存储新的中间sigmare?

首先,使用标准的dynamic/1指令声明代码使用的动态谓词是一种很好的编码方式。只需在文件开头添加:

:- dynamic(sigmares/2).
mysigma/3谓词定义中一个有趣的方面是,它是一个非尾部递归,其结果是它的输入需要线性空间。但这允许它按照您的意愿缓存所有中间结果。您的代码的固定版本将是:

:- dynamic(sigma_cache/2).

sigma_cache(1, 1).

sigma(N, S) :-
    sigma_cache(N, S),
    !.
sigma(N, S) :-
    N > 1,
    M is N - 1,
    sigma(M, SM),
    S is SM + N,
    assertz(sigma_cache(N, S)).
电话示例:

?- sigma(5, S).
S = 15.

?- listing(sigma_cache/2).
:- dynamic sigma_cache/2.

sigma_cache(1, 1).
sigma_cache(2, 3).
sigma_cache(3, 6).
sigma_cache(4, 10).
sigma_cache(5, 15).

true.

此备选答案提供了一种基于某些Prolog系统中的表格机制的解决方案,包括B-Prolog、Ciao、SWI Prolog、XSB和YAP:

:- table(sigma/2).

sigma(1, 1).
sigma(N, S) :-
    N > 1,
    M is N - 1,
    sigma(M, SM),
    S is SM + N.
让我们借助SWI Prolog handy time/1库谓词测试它,该谓词报告证明目标所用的时间和推理次数:

?- time(sigma(5, S)).
% 166 inferences, 0.000 CPU in 0.006 seconds (2% CPU, 1238806 Lips)
S = 15.

?- time(sigma(5, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (68% CPU, 208333 Lips)
S = 15.
请注意,我特意为sigma/2谓词使用了一个非尾部递归定义,以便根据问题中的要求缓存所有中间结果。例如:

?- time(sigma(4, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 217391 Lips)
S = 10.
您可以看到,在第一次调用之后,结果由tabling机制缓存,从而在重复查询时产生的推断数量要少得多

?- time(sigma(6, S)).
% 32 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 727273 Lips)
S = 21.

?- time(sigma(6, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 217391 Lips)
S = 21.

再次注意推论的数量。第一个查询将重用sigma5,S的缓存结果,并缓存sigma6,S的结果,这样重复查询会更快,因为它只是重用缓存的结果。

感谢您的回答。但您只缓存最终计算结果,而不缓存中间结果。我想储存的东西包括新的中间标志。很抱歉遗漏了这个细节。修好了,谢谢!这对我有帮助。但我认为函子sigma和sigma是一样的,我们只需要一个:当然是染料。与先前的答案保持一致。固定的