9

This logic programming is really making a lap dance on my imperative programming skills. This is homework, so please just don't drop me the answer. This is what I have:

fibo(N,1) :-
   N < 2,
   !. 
fibo(N,R) :-
   N1 is N-1,
   N2 is N-2,
   fibo(N1,R1),
   fibo(N2,R2),
   R is R1+R2.

I'm suppose to make another function that looks like this; fib(N,Value,LastValue). N is the n'th number, and value is the return value. I don't understand how I can rewrite this using accumulation. And since it counts backwards I don't see how it can "know" a last value before it calculates anything. :s Any input is appreciated.

repeat
  • 19,449
  • 4
  • 51
  • 152
Algific
  • 1,300
  • 2
  • 17
  • 32
  • See Bobby Tables's answer. Not sure if this is what's throwing you, but remember that in Prolog, "input" and "output" arguments to a predicate can come in any order, and in some cases are only distinctions in your head or the way you use a predicate. – aschepler Nov 23 '10 at 20:20

5 Answers5

5

I could post here the solution, but since that this is homework, it would be counter-productive. Instead, here's a lead:

The problem with the version of Fibonacci that you listed is that it is inefficient. Each call to fibo/2 causes another two calls, but some of these calls calculate the values of the same Fibonacci numbers. For example, in pseudo-code:

(a) fibo(4) -> fibo(3), fibo(2)
(b) fibo(3) -> fibo(2), fibo(1)
(c) fibo(2) -> fibo(1), fibo(0) % called from (a)
(d) fibo(2) -> fibo(1), fibo(0) % called from (b), redundant

To overcome this deficiency, you were asked to rephrase Fibonacci in terms of returning not just the last value, but the last two values, so that each call to fib/3 will cause only a single recursive call (hence calculate the Fibonacci series in linear time). You'll need to change the base cases to:

fib(1,1,0).
fib(2,1,1).

I'll leave the recursive case to you.


For the impatient

Here is the recursive case as well:

fib(N, Val, Last) :-
  N > 2,
  N1 is N - 1,
  fib(N1, Last, Last1), % single call with two output arguments, 
                        % instead of two calls with one output argument
  Val is Last + Last1.
Little Bobby Tables
  • 5,021
  • 2
  • 31
  • 44
  • Agree with everything here, except I think you actually only need one base case fact when done this way. – aschepler Nov 23 '10 at 20:22
  • Its due very soon. Might I have the solution? If I don't hand this in I won't even get to take the exam. I will spare you the excuses, but one tip; Don't make you're own schedule when in Uni, because everything crashes. – Algific Nov 23 '10 at 21:02
  • Interesting, I didn't think of having the call itself have the 2 prior values. I was thinking in terms of memoizing. – Paul Nathan Nov 23 '10 at 22:44
2

See the related discussion:

Generalizing Fibonacci sequence with SICStus Prolog

and consider ony's very good solution using finite domain constraints from there.

Community
  • 1
  • 1
mat
  • 39,707
  • 3
  • 42
  • 68
1

Perhaps using tail recursion is a good option

edit: Instead of breaking fib(6) into fib(5)+fib(4) you might try something like fib(6) = fib(6,0,0) the first parameter is the count of steps, when it reaches 0 you stop, the second parameter the last value you calculated, and the third parameter is the value to calculate which is equal to the sum of current second and third parameters (with the exception of the first step, in which 0 + 0 will be 1)

So to calculate you set the second parameter at each call and acumulate in the third so fib(6,0,0) => fib(5,0,1) => fib(4,1,1) => fib(3,1,2) => fib(2,2,3) => fib(1,3,5) => fib(0,5,8) then you return 8

In that method you dont actually have to save in the stack the adress return, avoiding stack overflow

rpfaraco
  • 219
  • 1
  • 4
0

Remember that there is another way to calculate the Fibonacci sequence: starting from the base case and moving up.

Right now, to calculate fib(n), you add fib(n-1) and fib(n-2). Instead, flip that around and calculate fib(0) and fib(1) based on the definition of the Fibonacci sequence, and build up from that.

Paul
  • 2,170
  • 1
  • 14
  • 18
-1

You almost already have it. Just rewrite:

fibo(N, Value) :-
N1 is N-1, N2 is N-2,
 fibo(N1, LastValue),fibo(N2, SecondToLastValue),
 Value is LastValue + SecondToLastValue.

in terms of

fibo2(N, Value, LastValue):- ...

I don't understand how I can rewrite this using accumulation

Just don't, this is not needed (although it's possible to do so).

jpalecek
  • 44,865
  • 7
  • 95
  • 139
  • Remember that this is homework. While he doesn't _have_ to do this, the question is definitely phrased in a way that indicates the marker is looking for the other method of calculating the Fibonacci sequence, as outlined in my answer. – Paul Nov 23 '10 at 00:53
  • @Paul: In the question, the OP specifically states he has to write a function `fib(N,Value,LastValue)`. This doesn't indicate he wants to do anything radical. After all, what I outlined in my post, _is_ linear, and proceeds exactly the same as "the other method". – jpalecek Nov 23 '10 at 08:43
  • The point of using accumulation is to make it more memory efficient, when the n'th fib number gets large now I get global stack overflow for numbers which aren't that large actually. – Algific Nov 23 '10 at 10:03