Prolog,动态规划,斐波那契级数

Prolog,动态规划,斐波那契级数,prolog,logic,fibonacci,Prolog,Logic,Fibonacci,我应该先说这是一个家庭作业问题,我有问题,我不确定这类事情是否允许在这里发生,但我不知道还有什么地方可以求助。这就是我被问到的问题: 在这个问题的示例代码中,您可以看到一个Fibonacci谓词fibSimple/2,它计算X的Fibonacci,一个自然数。朴素的递归解决方案的问题在于,最终会多次重新计算同一个递归案例。请看这里的解释 例如,计算fib5涉及三次计算fib2的解。动态规划方法可以解决这个问题。本质上,它归结为从fib2开始,然后计算fib3,然后是fib4等等。。。。直到你到达

我应该先说这是一个家庭作业问题,我有问题,我不确定这类事情是否允许在这里发生,但我不知道还有什么地方可以求助。这就是我被问到的问题:

在这个问题的示例代码中,您可以看到一个Fibonacci谓词fibSimple/2,它计算X的Fibonacci,一个自然数。朴素的递归解决方案的问题在于,最终会多次重新计算同一个递归案例。请看这里的解释

例如,计算fib5涉及三次计算fib2的解。动态规划方法可以解决这个问题。本质上,它归结为从fib2开始,然后计算fib3,然后是fib4等等。。。。直到你到达菲克斯。您可以将这些答案存储在列表中,fibX作为列表中的第一项

您的基本情况如下所示:

注意fib1被定义为[1,0]的方式。fib1实际上是1,但我们保留了以前答案的列表

我们为什么要这样做?因为要计算fibX,我们只需要计算fibX-1,将前两个元素加在一起,并将它们插入列表的前面。例如,从上面可以很容易地计算fib2,在这种情况下,fib2将是[1,1,0]。那么fib3将是[2,1,1,0],fib4将是[3,2,1,1,0]等等

如上所述完成fib/2谓词-基本情况如上所示。您需要找出在基本情况之后的一行来处理递归

这是他们提供的示例代码

fibSimple(0,0). % fib of 0 is 0
fibSimple(1,1). % fib of 1 is 1
fibSimple(N,X) :- N>1,fibSimple(N-1,A), fibSimple(N-2,B), X is A+B.

fib(0,[0]).
fib(1,[1,0]).
我已经尝试过几次了,虽然我相当肯定我的尝试最终会是无可救药的错误,但这是我最近尝试过的

fib(X,[fib(X-2)+fib(X-1) | _]).
我的推理是,如果你能得到最后2个的答案,并将它们加在一起,使它们成为列表的第一个或第一个,然后是代表其余部分的下划线

我的两个问题是:

1我不知道/认为这条下划线会达到我希望它达到的效果,我不知该怎么办 及


2我甚至不知道如何运行这个程序,因为fib\2谓词需要2个参数。比如说,我想运行fib\2来找到5的fibonacci,我不知道把什么作为第二个参数。

因为这是我的家庭作业,所以我只画出解决方案-但它应该能回答你提出的问题

谓词与函数的不同之处在于它没有返回值。Prolog只是告诉您它是否可以派生它*。所以如果你问fib5是不是真的,你能得到的最好答案是肯定的。那么从1到5的斐波那契数是多少呢?这就是第二个论点的用武之地。或者您已经知道并检查:

?- fib(5, [5, 3, 2, 1, 1, 0]).
true ;                   <--- Prolog can derive this fact. With ; I see more solutions.
false                    <--- no, there are no other solutions
因此,第二个参数包含您要查找的结果

您还可以询问其他查询,如fibX,Y,我们可以导出哪些数字及其fibonacci矩阵?或者fibX,[3 | u]哪一个数字计算fibonacci数3?。在第二种情况下,我们使用下划线表示列表的其余部分无关紧要。二,

那么我们用fibX做什么,[fibX-2+fibX-1 |?]。?如果我们将其添加到0和1的子句中,我们可以查询所有结果:

?- fib(X,Y).
X = 0,
Y = [1] ;    <-- first solution X = 0, Y = [1]
X = 1,
Y = [1, 0] ; <-- second solution X = 1, Y = [1, 0]
Y = [fib(X-2)+fib(X-1)|_2088]. <-- third solution
这意味着如果N>1,我们可以导出fibSimpleN-1,A,我们可以导出fibSimpleN-2,B,我们可以将X设置为A+B的结果,然后我们可以导出fibSimpleN,X。与您所写的不同之处在于,fibSimpleN-1,A出现在规则体中。参数N-1同样没有得到计算。实际发生的是,当使用查询fib3,X调用时,递归构造了术语3-1和3-1-1。实际的计算发生在算术谓词中是和1,因为1>1不是真的。但我们也没有触及基本情况fibSimple1,1,因为3-1-1项与1不相同,即使它们的计算结果相同

这就是Prolog在简单实现中找不到Fibonacci数3的原因:

?- fibSimple(3, X).
false.
算术计算是由is谓词完成的:查询X是3-1-1正好有解X=1。三,

所以fibSimple实际上必须是这样的:4

fibSimple(0,1).
fibSimple(1,1).
fibSimple(N,X) :-
    N>1,
    M1 is N -1,      % evaluate N - 1
    M2 is N -2,      % evaluate N - 2
    fibSimple(M1,A),
    fibSimple(M2,B),
    X is A+B.
对于fib,您可以将其用作只需要一个递归调用的模板,因为a和B都在历史记录列表中。请注意子句的开头:如果X是新值,那么它也不能是新的历史记录列表。例如,头部的形状可以是fibN,[X | Oldhistory]

祝你作业顺利

1这有点简化-Prolog通常会给您一个答案替换,告诉您查询中的变量有什么值。还有一些有限的方法来处理不可派生性,但这里不需要

2如果使用算术谓词is和>这两个查询将无法直接实现。更具声明性的处理方法是

3为使此评估有效,is的右侧可能不包含变量。这就是您需要2中的算术约束的地方

4或者,基本案例可以评估传递下来的算术术语:

fibSimple(X, 0) :-
    0 is X.
fibSimple(X, 1) :-
    1 is X.
fibSimple(N,X) :-
    N>1,
    fibSimple(N-1,A),
    fibSimple(N-2,B),
    X is A+B.

但这是效率较低的,因为单个数字比100000-1-1-1这个词占用的空间要小得多-1.

因为这是家庭作业,所以我只会草拟解决方案,但它应该能回答您提出的问题

谓词与函数的不同之处在于它没有返回值。Prolog只是告诉您它是否可以派生它*。所以如果你问fib5是不是真的,你能得到的最好答案是肯定的。那么从1到5的斐波那契数是多少呢?这就是第二个论点的用武之地。或者您已经知道并检查:

?- fib(5, [5, 3, 2, 1, 1, 0]).
true ;                   <--- Prolog can derive this fact. With ; I see more solutions.
false                    <--- no, there are no other solutions
因此,第二个参数包含您要查找的结果

您还可以询问其他查询,如fibX,Y,我们可以导出哪些数字及其fibonacci矩阵?或者fibX,[3 | u]哪一个数字计算fibonacci数3?。在第二种情况下,我们使用下划线表示列表的其余部分无关紧要。二,

那么我们用fibX做什么,[fibX-2+fibX-1 |?]。?如果我们将其添加到0和1的子句中,我们可以查询所有结果:

?- fib(X,Y).
X = 0,
Y = [1] ;    <-- first solution X = 0, Y = [1]
X = 1,
Y = [1, 0] ; <-- second solution X = 1, Y = [1, 0]
Y = [fib(X-2)+fib(X-1)|_2088]. <-- third solution
这意味着如果N>1,我们可以导出fibSimpleN-1,A,我们可以导出fibSimpleN-2,B,我们可以将X设置为A+B的结果,然后我们可以导出fibSimpleN,X。与您所写的不同之处在于,fibSimpleN-1,A出现在规则体中。参数N-1同样没有得到计算。实际发生的是,当使用查询fib3,X调用时,递归构造了术语3-1和3-1-1。实际的计算发生在算术谓词中是和1,因为1>1不是真的。但我们也没有触及基本情况fibSimple1,1,因为3-1-1项与1不相同,即使它们的计算结果相同

这就是Prolog在简单实现中找不到Fibonacci数3的原因:

?- fibSimple(3, X).
false.
算术计算是由is谓词完成的:查询X是3-1-1正好有解X=1。三,

所以fibSimple实际上必须是这样的:4

fibSimple(0,1).
fibSimple(1,1).
fibSimple(N,X) :-
    N>1,
    M1 is N -1,      % evaluate N - 1
    M2 is N -2,      % evaluate N - 2
    fibSimple(M1,A),
    fibSimple(M2,B),
    X is A+B.
对于fib,您可以将其用作只需要一个递归调用的模板,因为a和B都在历史记录列表中。请注意子句的开头:如果X是新值,那么它也不能是新的历史记录列表。例如,头部的形状可以是fibN,[X | Oldhistory]

祝你作业顺利

1这有点简化-Prolog通常会给您一个答案替换,告诉您查询中的变量有什么值。还有一些有限的方法来处理不可派生性,但这里不需要

2如果使用算术谓词is和>这两个查询将无法直接实现。更具声明性的处理方法是

3为使此评估有效,is的右侧可能不包含变量。这就是您需要2中的算术约束的地方

4或者,基本案例可以评估传递下来的算术术语:

fibSimple(X, 0) :-
    0 is X.
fibSimple(X, 1) :-
    1 is X.
fibSimple(N,X) :-
    N>1,
    fibSimple(N-1,A),
    fibSimple(N-2,B),
    X is A+B.

但这是效率较低的,因为单个数字比100000-1-1-1这个词占用的空间要小得多-1.

对于另一种直接使用断言的方法:。这基本上是一个自修改程序,使用Prolog数据库作为缓存。这不是我要走的路,但肯定是一个解决方案。我已经用更好、更容易理解的东西取代了我以前可怕的文本墙答案:计算斐波那契级数的各种方法的列表。对于另一种直接使用assert的方法:。这基本上是一个自修改程序,使用Prolog数据库作为缓存。这不是我要走的路,但肯定是一个解决方案。我已经用一个更好、更容易理解的东西取代了我以前可怕的文本答案墙:一个计算斐波那契级数的各种方法的列表。