Can this be made tail-recursive in Prolog? - recursion

I'm learning Prolog, and as an exercise, I'm experimenting with a simple database that calculates the sum of all numbers up to the given number (i.e. 0=0, 1=1, 2=3, 3=6, 4=10, ...). Easy enough:
counting_sum(0, 0).
counting_sum(Num, Sum) :- Num > 0, PrevNum is Num - 1,
counting_sum(PrevNum, PrevSum), Sum is Num + PrevSum.
That blows up somewhere around counting_sum(150000, X). with a stack overflow. I understand that Prolog can do tail recursion, but if I move the recursive call to the end of the rule, I get
error(instantiation_error,(is)/2)
which I assume is telling me I can't use PrevSum before it's been unified with counting_sum(PrevNum, PrevSum). Is that correct, and is there any way to make this tail-recursive? I'm using GNU Prolog 1.3.1 if that makes any difference.
P.S. I'm still shaky on the terminology. Let me know if I used the terms incorrectly.

Try something like this (use an accumulator):
counting_sum(Count, Sum):-
counting_sum(Count, 0, Sum).
counting_sum(0, Sum, Sum).
counting_sum(Num, PrevSum, Sum):- Num > 0, PrevNum is Num - 1,
NextSum is PrevSum + Num,
counting_sum(PrevNum, NextSum, Sum).

Related

Recursive iteration of a function getting stack overflows

I'm trying to write a Maxima function that iterates another function provided as an argument. The goal is basically...
iter(f,0) ........ gives the identity function lambda([x],x)
iter(f,1) ........ gives f
iter(f,2) ........ gives lambda([x],f(f(x))
iter(f,3) ........ gives lambda([x],f(f(f(x)))
The reason is trying to figure out how an iterated polynomial behaves - similar to the Robert May population equation, but a different polynomial.
Anyway, I'm very new to Maxima (at least to things that seem more like simple programming than just asking for a solution) and after some time trying to figure out what I'm doing wrong, I think I've eliminated all silly mistakes and I must have a more fundamental misunderstanding of how Maxima works.
What I have...
iter(f,n) := if is (n=0)
then lambda ([x], x)
else block ([n2: floor (n/2),
nr: is (n2*2#n),
ff: iter (f,n2) ], if nr then lambda ([x],f(ff(ff(x))))
else lambda ([x], ff(ff(x)) ));
Maxima accepts this. Now as a simple example function to iterate...
inc(x):=x+1;
And some tests - first the base case...
iter(inc,0);
That works - it gives lambda([x],x) as expected. Next, "iterating" one time...
iter(inc,1);
I'm expecting something equivalent to inc, but because of the way this is written, more like lambda([x],inc(identity(identity(x))) but with more clutter. What I'm actually getting is a stack overflow...
Maxima encountered a Lisp error:
Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.
...
I can't see why the is (n=0) base-case check would fail to spot that in the recursive call, so I can't see why this iter function would be entered more than twice for n=1 - it seems pretty extreme for that the exhaust the stack.
Of course once I have the basic idea working I'll probably special-case n=1 as effectively another base case for efficiency (a less cluttered resulting function definition) and add more checks, but I just want something that doesn't stack-overflow in trivial cases for now.
What am I misunderstanding?
Here's what I came up with. It's necessary to substitute into the body of lambda since the body is not evaluated -- I guess you have encountered this important point already.
(%i3) iter(f, n) := if n = 0 then identity elseif n = 1 then f
else subst([ff = iter(f, n - 1),'f = f],
lambda([x], f(ff(x)))) $
(%i4) iter(inc, 0);
(%o4) identity
(%i5) iter(inc, 1);
(%o5) inc
(%i6) iter(inc, 2);
(%o6) lambda([x], inc(inc(x)))
(%i7) iter(inc, 3);
(%o7) lambda([x], inc(inc(inc(x))))
(%i8) iter(inc, 4);
(%o8) lambda([x], inc(inc(inc(inc(x)))))
(%i9) inc(u) := u + 1 $
(%i10) iter(inc, 4);
(%o10) lambda([x], inc(x + 3))
(%i11) %(10);
(%o11) 14
(%i12) makelist (iter(cos, k), k, 0, 10);
(%o12) [identity, cos, lambda([x], cos(cos(x))),
lambda([x], cos(cos(cos(x)))), lambda([x],
cos(cos(cos(cos(x))))), lambda([x], cos(cos(cos(cos(cos(x)))))),
lambda([x], cos(cos(cos(cos(cos(cos(x))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(x)))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(x))))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(cos(x)))))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(x)))))))))))]
(%i13) map (lambda([f], f(0.1)), %);
(%o13) [0.1, 0.9950041652780257, 0.5444993958277886,
0.8553867058793604, 0.6559266636704799, 0.7924831019448093,
0.7020792679906703, 0.7635010336918854, 0.7224196362389732,
0.7502080588752906, 0.731547032044224]
Maxima is almost good at stuff like this -- since it is built on top of Lisp, the right conceptual elements are present. However, the lack of lexical scope is a serious problem when working on problems like this, because it means that when you refer to f within a function definition, it is the same f which might exist outside of it. When the solution depends on carefully distinguishing which f you mean, that's a problem.
Anyway as it stands I hope this solution is useful to you in some way.
Earlier, after a moment of inspiration, I tried the following in Maxima...
block([a:1,b:a],b);
This gave me a where I was expecting 1, which suggests that the b:a variable definition cannot see the a:1 variable definition earlier in the same block. I had assumed that later variable definitions in a block would be able to see earlier definitions, and that affects two variable definitions in my iter function - in particular, iter (f,n2) cannot see the definition of n2 which breaks the base-case check in the recursion.
What I have now (WARNING - NOT A WORKING SOLUTION) is...
iter(f,n) := if is (n=0)
then lambda ([x], x)
else block ([n2: floor (n/2)],
block ([g: iter (f,n2)],
if is (n2*2#n) then lambda ([x],f(g(g(x))))
else lambda ([x], g(g(x)) )));
I'm nesting one block inside another so that the later variable definition can see the earlier one. There is no nr (n was rounded?) variable, though TBH keeping that wouldn't have required a third nested block. I replaced ff with g at some point.
This solves the stack overflow issue - the base case of the recursion seems to be handled correctly now.
This still isn't working - it seems like the references to g now cannot see the definition of g for some reason.
iter(inc,0) ................. lambda([x],x)
iter(inc,1) ................. lambda([x],f(g(g(x))))
iter(inc,2) ................. lambda([x],g(g(x)))
...
When the recursive half-size iteration g is needed, for some reason it's not substituted. Also noticable - neither is f substituted.
As a best guess, this is probably due to the function calls being by-name in the generated lambda, and due to nothing forcing them to be substituted in or forcing the overall expression to be simplified.
(update - This SO question suggests I've understood the problem, but the solution doesn't appear to work in my case - what I'm trying to substitute is referenced via a variable no matter what.)
But it's also a different question (it's not a recursion/stack overflow issue) so I'll come back and ask another question if I can't figure it out. I'll also add a working solution here if/when I figure it out.
I tried a few more approaches using subst and the double-quote notation, but Maxima stubbornly kept referring to f and g by name. After a little thought, I switched approach - instead of generating a function, generate an expression. The working result is...
iter(v,e,n) := if is (n=0)
then ''v
else block ([n2: floor (n/2)],
block ([g: iter (v,e,n2)],
block ([gg: subst([''v=g], g)],
if is (n2*2#n) then subst([''v=e], gg)
else gg )));
The three nested block expressions are annoying - I'm probably still missing something that's obvious to anyone with any Maxima experience. Also, this is fragile - it probably needs some parameter checks, but not on every recursive call. Finally, it doesn't simplify result - it just builds an expression by applying direct substitution into itself.
What if you do everything with expressions?
(%i1) iter(e, n):= block([ans: e], thru n - 1 do ans: subst('x = e, ans), ans) $
(%i2) iter(x^2 + x, 1);
2
(%o2) x + x
(%i3) iter(x^2 + x, 2);
2 2 2
(%o3) (x + x) + x + x
(%i4) iter(x^2 + x, 3);
2 2 2 2 2 2 2
(%o4) ((x + x) + x + x) + (x + x) + x + x
You can define a function at the end:
(%i5) define(g(x), iter(x^2 + x, 3));

Fibonacci sequence in solving an equation

Im trying to figure out an equation. This is f(n)=f(n-1) + 3n^2 - n. I also have the values to use as f(1), f(2), f(3). How would i go about solving this??
You would usually use recursion but, whether you do that or an iterative solution, you're missing (or simply haven't shown us) a vital bit of information, the terminating condition such as f(1) = 1 (for example).
With that extra piece of information, you could code up a recursive solution relatively easily, such as the following pseudo-code:
define f(n):
if n == 1:
return 1
return f(n-1) + (3 * n * n) - n
As an aside, that's not actually Fibonacci, which is the specific 1, 1, 2, 3, 5, 8, 13, ... sequence.
It can be said to be Fibonacci-like but it's actually more efficient to do this one recursively since it only involves one self-referential call per level whereas Fibonacci needs two:
define f(n):
if n <= 2:
return 1
return f(n-2) + f(n-1)
And if you're one of those paranoid types who doesn't like recursion (and I'll admit freely it can have its problems in the real world of limited stack depths), you could opt for the iterative version.
define f(n):
if n == 1:
return 1
parent = 1
for num = 2 to n inclusive:
result = parent + (3 * num * num) - num
parent = result
return result
If you ask this question on a programming site such as Stack Overflow, you can expect to get code as an answer.
On the other hand, if you are looking for a closed formula for f(n), then you should direct your question to a specialised StackExchange site such as Computer Science.
Note: what you are looking for is called the repertoire method. It can be used to solve your problem (the closed formula is very simple).

Introduction to programming using SML exercise 1.3

I am currently working through the Introduction to programming using SML book released back in 1999. I would like your help on how to declare a recursive function for exercise 1.3, which I have been stuck on for some time now.
1.3: Declare a recursive function f: int -> int, where
f(ᶯ) = 1 + 2 + ... + (ᶯ - 1) + ᶯ for ᶯ ≥ 0
Hint: Use two clauses with 0 and ᶯ as argument patterns. State the recursion formula corresponding to the declaration.
If anyone can provide some guidance on this that would be great.
More literal hint:
The solution is supposed to look like this:
fun sum 0 = ... something ...
| sum n = ... something else ...
You'll need to figure out
What is sum 0?
What information do you need in order to be able to calculate sum n?
If you're stuck, write down the calculation of f(1), f(2), f(3), and f(4) on a piece of paper and see if you can spot a pattern.

prolog recursive error (easy)

I'm new to prolog. I'm doing a recursive program the problem is that even though it prints the answer.. it doesn't stop after printing the answer and eventually gives "Out of local stack".
I've read it could be a left recursion issue but as I've already told you I'm new to prolog and I don't really understand what happens...
so.. here's code.
f(X, Y):-
Y is sqrt(1-((X-1)*(X-1))).
sum(SEGMENTS, 1, TOTAL):-
f(2/SEGMENTS*1,H1),
TOTAL is (2/SEGMENTS)*H1.
sum(SEGMENTS, NR, TOTAL):-
N1 is (NR-1),
sum(SEGMENTS, N1, S1),
f(2/SEGMENTS*NR,H1),
f(2/SEGMENTS*N1,H2),
TOTAL is S1 + (2/SEGMENTS)*((H1+H2)/2).
It's supposed to calculate a semicircle area with the trapezoid rule or something similar.
As I've already told you .. it does finishes but after getting to the base case sum(segments, 1, total) it calls the function with the second alternative... :S
Thanks guys!
Also: Here's what I get when I run it
?- sum(3000,3000,TOTAL).
TOTAL = 1.5707983753431007 ;
ERROR: Out of local stack
The problem is that backtracking will attempt the case of NR value of 1 on the second sum clause after the first clause has succeeded. This causes a long recursion process (since NR is being decremented continually for each recursive call, attempting to wrap around through all negative integer values, etc).
A simple way to resolve the problem is in your second sum clause. Since the intention is that it is for the case of NR > 1, put NR > 1 as your first statement:
sum(SEGMENTS, NR, TOTAL) :-
NR > 1,
N1 is (NR-1),
sum(SEGMENTS, N1, S1),
f(2/SEGMENTS*NR,H1),
f(2/SEGMENTS*N1,H2),
TOTAL is S1 + (2/SEGMENTS)*((H1+H2)/2).
Also note that the expression f(2/SEGMENTS*NR, H1) doesn't compute the expression 2/SEGMENTS*NR and pass it to f. It actually passes that expression symbolically. It just happens to work here because f includes it on the right hand side of an is/2 so it is evaluated as desired. If you trace it, you'll see what I mean.

Can recursion be dynamic programming?

I was asked to use dynamic programming to solve a problem. I have mixed notes on what constitutes dynamic programming. I believe it requires a "bottom-up" approach, where smallest problems are solved first.
One thing I have contradicting information on, is whether something can be dynamic programming if the same subproblems are solved more than once, as is often the case in recursion.
For instance. For Fibonacci, I can have a recursive algorithm:
RecursiveFibonacci(n)
if (n=1 or n=2)
return 1
else
return RecursiveFibonacci(n-1) + RecursiveFibonacci(n-2)
In this situation, the same sub-problems may be solved over-and-over again. Does this render it is not dynamic programming? That is, if I wanted dynamic programming, would I have to avoid resolving subproblems, such as using an array of length n and storing the solution to each subproblem (the first indices of the array are 1, 1, 2, 3, 5, 8, 13, 21)?
Fibonacci(n)
F1 = 1
F2 = 1
for i=3 to n
Fi=Fi-1 + Fi-2
return Fn
Dynamic programs can usually be succinctly described with recursive formulas.
But if you implement them with simple recursive computer programs, these are often inefficient for exactly the reason you raise: the same computation is repeated. Fibonacci is a example of repeated computation, though it is not a dynamic program.
There are two approaches to avoiding the repetition.
Memoization. The idea here is to cache the answer computed for each set of arguments to the recursive function and return the cached value when it exists.
Bottom-up table. Here you "unwind" the recursion so that results at levels less than i are combined to the result at level i. This is usually depicted as filling in a table, where the levels are rows.
One of these methods is implied for any DP algorithm. If computations are repeated, the algorithm isn't a DP. So the answer to your question is "yes."
So an example... Let's try the problem of making change of c cents given you have coins with values v_1, v_2, ... v_n, using a minimum number of coins.
Let N(c) be the minimum number of coins needed to make c cents. Then one recursive formulation is
N(c) = 1 + min_{i = 1..n} N(c - v_i)
The base cases are N(0)=0 and N(k)=inf for k<0.
To memoize this requires just a hash table mapping c to N(c).
In this case the "table" has only one dimension, which is easy to fill in. Say we have coins with values 1, 3, 5, then the N table starts with
N(0) = 0, the initial condition.
N(1) = 1 + min(N(1-1), N(1-3), N(1-5) = 1 + min(0, inf, inf) = 1
N(2) = 1 + min(N(2-1), N(2-3), N(2-5) = 1 + min(1, inf, inf) = 2
N(3) = 1 + min(N(3-1), N(3-3), N(3-5) = 1 + min(2, 0, inf) = 1
You get the idea. You can always compute N(c) from N(d), d < c in this manner.
In this case, you need only remember the last 5 values because that's the biggest coin value. Most DPs are similar. Only a few rows of the table are needed to get the next one.
The table is k-dimensional for k independent variables in the recursive expression.
We think of a dynamic programming approach to a problem if it has
overlapping subproblems
optimal substructure
In very simple words we can say dynamic programming has two faces, they are top-down and bottom-up approaches.
In your case, it is a top-down approach if you are talking about the recursion.
In the top-down approach, we will try to write a recursive solution or a brute-force solution and memoize the results so that we will try to use that result when a similar subproblem arrives, so it is brute-force + memoization. We can achieve that brute-force approach with a simple recursive relation.

Resources