I'm having trouble understanding the following factorial program
fact1(0,Result) :-
Result is 1.
fact1(N,Result) :-
N > 0,
N1 is N-1,
fact1(N1,Result1),
Result is Result1*N.
When fact1 is called nested within the second fact1, doesn't that mean that the the last line, Result is Result1*N., is never called? Or in Prolog does the last line get executed before the recursive call?
BTW once you got the basic recursion understood, try to achieve tail recursion whenever possible, here it'd be:
factorial(N, R) :- factorial(N, 1, R).
factorial(0, R, R) :- !.
factorial(N, Acc, R) :-
NewN is N - 1,
NewAcc is Acc * N,
factorial(NewN, NewAcc, R).
Tail recursion, unlike the recursion you used previously, allows interpreter/compiler to flush context when going on to the next step of recursion. So let's say you calculate factorial(1000), your version will maintain 1000 contexts while mine will only maintain 1. That means that your version will eventually not calculate the desired result but just crash on an Out of call stack memory error.
You can read more about it on wikipedia.
No, the recursive call happens first! It has to, or else that last clause is meaningless. The algorithm breaks down to:
factorial(0) => 1
factorial(n) => factorial(n-1) * n;
As you can see, you need to calculate the result of the recursion before multiplying in order to return a correct value!
Your prolog implementation probably has a way to enable tracing, which would let you see the whole algorithm running. That might help you out.
Generally speaking, #m09's answer is basically right about the importance of tail-recursion.
For big N, calculating the product differently wins! Think "binary tree", not "linear list"...
Let's try both ways and compare the runtimes. First, #m09's factorial/2:
?- time((factorial(100000,_),false)).
% 200,004 inferences, 1.606 CPU in 1.606 seconds (100% CPU, 124513 Lips)
false.
Next, we do it tree-style—using meta-predicate reduce/3 together with lambda expressions:
?- time((numlist(1,100000,Xs),reduce(\X^Y^XY^(XY is X*Y),Xs,_),false)).
% 1,300,042 inferences, 0.264 CPU in 0.264 seconds (100% CPU, 4922402 Lips)
false.
Last, let's define and use dedicated auxiliary predicate x_y_product/3:
x_y_product(X, Y, XY) :- XY is X*Y.
What's to gain? Let's ask the stopwatch!
?- time((numlist(1,100000,Xs),reduce(x_y_product,Xs,_),false)).
% 500,050 inferences, 0.094 CPU in 0.094 seconds (100% CPU, 5325635 Lips)
false.
factorial(1, 1).
factorial(N, Result) :- M is N - 1,
factorial(M, NextResult), Result is NextResult * N.
Base case is declared. The conditions that N must be positive and multiply with previous term.
factorial(0, 1).
factorial(N, F) :-
N > 0,
Prev is N -1,
factorial(Prev, R),
F is R * N.
To run:
factorial(-1,X).
A simple way :
factorial(N, F):- N<2, F=1.
factorial(N, F) :-
M is N-1,
factorial(M,T),
F is N*T.
I would do something like:
fact(0, 1).
fact(N, Result):-
Next is N - 1,
fact(Next, Recursion),
Result is N * Recursion.
And a tail version would be like:
tail_fact(0, 1, 0). /* when trying to calc factorial of zero */
tail_fact(0, Acc, Res):- /* Base case of recursion, when reaches zero return Acc */
Res is Acc.
tail_fact(N, Acc, Res):- /* calculated value so far always goes to Acc */
NewAcc is N * Acc,
NewN is N - 1,
tail_fact(NewN, NewAcc, Res).
So for you to call the:
non-tail recursive method: fact(3, Result).
tail recursive method: tail_fact(3, 1, Result).
This might help ;)
non-tailer recursion :
fact(0,1):-!.
fact(X,Y):- Z=X-1,
fact(Z,NZ),Y=NZ*X.
tailer recursion:
fact(X,F):- X>=0,fact_aux(X,F,1).
fact_aux(0,F,F):-!.
fact_aux(X,F,Acc):-
NAcc=Acc*X, NX=X-1,
fact_aux(NX,F,NAcc).
Related
I am trying to work out calculating the difference for 'Peano numbers' (Recursive definition of natural numbers represented as s(0), s(s(0)) etc.) but I am kind of stuck with one problem.
The definition for subtraction is the following:
s(X) - 0 = s(X)
s(X) - s(s(X)) = 0
s(X) - s(X) = 0
s(s(X)) - s(X) = s(0)
0 - s(X) = 0
This is my current code:
nat(0).
nat(s(X)) :- nat(X).
% sub/3
% Subtracts right operand from left operand and returns difference
sub(0, _, 0).
sub(X, 0, X).
sub(s(X), s(Y), X) :-
sub(X,Y,X).
My thought process behind this:
Since I don't really need to recursively increase the difference I can just use the last X i have left after the recursion as my result.
For some reason the following question works:
?- sub(s(0), s(0), X).
X = 0 ;
But this one doesn't:
?- sub(s(s(0)), s(s(0)), X).
false.
Can anyone point out my mistake or suggest a better way to implement the sub procedure?
This might be a beginner mistake, since i really haven't done much. Sorry if that's the case.
//EDIT
This is how i resolved it
sub(X, 0, X).
sub(0, _, 0).
% not sure why I didn't test this before, thought I did.
sub(s(X), s(Y), Diff) :-
sub(X,Y,Diff).
sub(s(X), s(Y), X) :- sub(X,Y,X).
says that
You can prove that s(X)-s(Y) = X
if you can prove that X-Y = X
which is a bit weird. There should be a third variable in there, Z.
Prolog tries to prove (make true)
sub(s(s(0)), s(s(0)), X).
which can be done if
sub(s(0),s(0),s(0)).
because the right-hand side of the rule is set thus by positing X=s(0) and Y=s(0) through pattern-matching the LHS.
Trying to prove this sub(s(0),s(0),s(0)) again means using the rule (nothing else is applicable), positing X=0, Y=0, X=s(0). But X cannot be both 0 and s(0). Impasse! false.
I want to learn some prolog and found the exercise to calculate pi recursively for a given predicat pi(10, Result). I don't want it to be tail recursive because I find tail recursion to be easier. I've been trying to do this for hours now but it seems like I can't come to a solution, this is how far I've come:
(I'm using Leibniz' pi formula as reference)
pi(0, 0).
pi(Next, Result) :-
Num is -1**(Next + 1),
Part is Num / (2 * Next - 1),
N1 is Next -1,
pi(N1, R),
Result is Part + R.
Now, I'm aware that the addition at the end is wrong. Also I need to multiply the end result by 4 and I don't know how to do that. Would be glad if anyone could help out. And no, this is not a homework or anything. :)
Here's a slightly different twist that terminates based upon reaching a given precision. It also is tail recursive. Because Leibniz converges very slowly, the formula is a stack hog when done using simple recursion. it's not an algorithm well-suited for a recursive solution in any language. However, a smart Prolog interpreter can take advantage of the tail recursion and avoid that. Just by way of example, it only allows precision within a specific range.
pi(Precision, Pi) :-
Precision > 0.0000001,
Precision < 0.1,
pi_over_4(1, 1, Precision/4, 1, Pi_over_4), % Compensate for *4 later
Pi is Pi_over_4 * 4.
pi_over_4(AbsDenominator, Numerator, Precision, Sum, Result) :-
NewAbsDenominator is AbsDenominator + 2,
NewNumerator is -Numerator,
NewSum is Sum + NewNumerator/NewAbsDenominator,
( abs(NewSum - Sum) < Precision
-> Result = NewSum
; pi_over_4(NewAbsDenominator, NewNumerator, Precision, NewSum, Result)
).
2 ?- pi(0.0001, P).
P = 3.1416426510898874.
3 ?- pi(0.00001, P).
P = 3.141597653564762.
4 ?- pi(0.000005, P).
P = 3.141595153583494.
This is strictly an imperative use of Prolog, which isn't what Prolog is strong for.
I'm trying to find time complexity (big O) of a recursive formula.
I tried to find a solution, you may see the formula and my solution below:
Like Brenner said, your last assumption is false. Here is why: Let's take the definition of O(n) from the Wikipedia page (using n instead of x):
f(n) = O(n) if and only if there exist constants c, n0 s.t. |f(n)| <= c |g(n)|, for alln >= n0.
We want to check if O(2^n^2) = O(2^n). Clearly, 2^n^2 is in O(2^n^2), so let's pick f(n) = 2^n^2 and check if this is in O(2^n). Put this into the above formula:
exists c, n0: 2^n^2 <= c * 2^n for all n >= n0
Let's see if we can find suitable constant values n0 and c for which the above is true, or if we can derive a contradiction to proof that it is not true:
Take the log on both sides:
log(2^n^2) <= log(c * 2 ^ n)
Simplify:
2 ^n log(2) <= log(c) + n * log(2)
Divide by log(2):
n^2 <= log(c)/log(2) * n
It's easy to see know that there is no c, n0 for which the above is true for all n >= n0, thus O(2^n^2) = O(n^2) is not a valid assumption.
The last assumption you've specified with the question mark is false! Do not make such assumptions.
The rest of the manipulations you've supplied seem to be correct. But they actually bring you nowhere.
You should have finished this exercise in the middle of your draft:
T(n) = O(T(1)^(3^log2(n)))
And that's it. That's the solution!
You could actually claim that
3^log2(n) == n^log2(3) ==~ n^1.585
and then you get:
T(n) = O(T(1)^(n^1.585))
which is somewhat similar to the manipulations you've made in the second part of the draft.
So you can also leave it like this. But you cannot mess with the exponent. Changing the value of the exponent changes the big-O classification.
I am having some troubles with my CS assignment. I am trying to call another rule that I created previously within a new rule that will calculate the factorial of a power function (EX. Y = (N^X)!). I think the problem with my code is that Y in exp(Y,X,N) is not carrying over when I call factorial(Y,Z), I am not entirely sure though. I have been trying to find an example of this, but I haven been able to find anything.
I am not expecting an answer since this is homework, but any help would be greatly appreciated.
Here is my code:
/* 1.2: Write recursive rules exp(Y, X, N) to compute mathematical function Y = X^N, where Y is used
to hold the result, X and N are non-negative integers, and X and N cannot be 0 at the same time
as 0^0 is undefined. The program must print an error message if X = N = 0.
*/
exp(_,0,0) :-
write('0^0 is undefined').
exp(1,_,0).
exp(Y,X,N) :-
N > 0, !, N1 is N - 1, exp(Y1, X, N1), Y is X * Y1.
/* 1.3: Write recursive rules factorial(Y,X,N) to compute Y = (X^N)! This function can be described as the
factorial of exp. The rules must use the exp that you designed.
*/
factorial(0,X) :-
X is 1.
factorial(N,X) :-
N> 0, N1 is N - 1, factorial(N1,X1), X is X1 * N.
factorial(Y,X,N) :-
exp(Y,X,N), factorial(Y,Z).
The Z variable mentioned in factorial/3 (mentioned only once; so-called 'singleton variable', cannot ever get unified with anything ...).
Noticed comments under question, short-circuiting it to _ won't work, you have to unify it with a sensible value (what do you want to compute / link head of the clause with exp and factorial through parameters => introduce some parameter "in the middle"/not mentioned in the head).
Edit: I'll rename your variables for you maybe you'll se more clearly what you did:
factorial(Y,X,Result) :-
exp(Y,X,Result), factorial(Y,UnusedResult).
now you should see what your factorial/3 really computes, and how to fix it.
The full Context of the Problem can be seen here
Details.
Also you can try my Sourcecode to plot the recursion for small numbers:
Pastebin
I'm looking at this problem the math way, its a nested recursion and looks like follows:
Function Find(integer n, function func)
If n=1
For i = 1 to a do func()
Elseif n=2
For i = 1 to b do func()
Else Find(n-1,Find(n-2,func))
Function Main
Find(n,funny)
My implementation in Mathematica without the Modulo-Operation is:
$IterationLimit = Infinity
Clear[A]
A [a_, b_, f_, 1] := A [a, b, f, 1, p] = (f a);
A [a_, b_, f_, 2] := A [a, b, f, 2, p] = (f b);
A [a_, b_, f_, n_] :=
A [a, b, f, n, p] = (A[a, b, A[a, b, f, n - 2], n - 1]);
This reveals some nice Output for general a and b
A[a, b, funny, 1]
a funny
A[a, b, funny, 2]
b funny
A[a, b, funny, 3]
a b funny
A[a, b, funny, 4]
a b^2 funny
A[a, b, funny, 5]
a^2 b^3 funny
A[a, b, funny, 6]
a^3 b^5 funny
So when we are looking at how often the Func is called, it seems like a^(F(n)) * b^(F(n+1))
with F(n) as the n-th Fibonacci Number. So my Problem is: How do i get very huge Fibonacci-Numbers modulo p, i did a lot of research on this, read through Cycle-Lenghts of Fibonacci, tried some Recursion with:
F(a+b) = F(a+1) * F(b) + F(a)*F(b-1)
but it seems like the Recursion-Depth (log_2(1.000.000.000) ~=30 ) when splitting p into two numbers is way to much, even with a deep first recursion.
a= floor(n/2)
b= ceiling(n/2)
When i have the Fib-Numbers, the multiplication and exponentiation
should not be a problem in my point of view.
Unfortunately not :/
I'm still stuck with the Problem. Computing the Fibonacci-Numbers in the Exponent first did not solve the Problem correct, it was a wrong Mathformula I applied there :/
So i thought of other ways Computing the Formula:
(a^(Fibonacci(n-2))*b^(Fibonacci(n-1))) mod p
But as the Fibonacci Numbers get really large, I am assuming that there must be an easier way than computing the whole Fibonacci-Number and then applying the discrete exponential function with BigInteger/BigFloat. Does someone have a hint for me, i see no further progress. Thanks
So this is where i am so far, might be just a little thing I'm missing, so looking forward to your replies
Thanks
If it's about calculating fibonacci numbers, there is a non-recursive, non-iterative formula for it. It's featured prominently on the Dutch wikipedia page about fibonacci numbers, but not so much on the English page.
F(n) = ( ( 1 + sqrt(5) ) ^ n - ( 1- sqrt(5) ) ^ n ) / (2 ^ n * sqrt(5))
http://upload.wikimedia.org/wikipedia/nl/math/1/7/4/1747ee745fbe1fbf10fb3d9de36b8927.png
Source: http://nl.wikipedia.org/wiki/Rij_van_Fibonacci
Maybe there's something you can do with this formula.
You might find helpful my ruminations on various ways to compute the Fibonacci and Lucas numbers. In there I show how to do the computation using a recursive scheme that is basically O(log2(n)). It works very nicely for large fibonacci numbers. And if you do it all modulo some small number, you need not even use a big integer tool for the computations. This would be blindingly fast for even huge Fibonacci numbers. This one below is only moderately large.
fibonacci(10000)
ans =
33644764876431783266621612005107543310302148460680063906564769974680
081442166662368155595513633734025582065332680836159373734790483865268263
040892463056431887354544369559827491606602099884183933864652731300088830
269235673613135117579297437854413752130520504347701602264758318906527890
855154366159582987279682987510631200575428783453215515103870818298969791
613127856265033195487140214287532698187962046936097879900350962302291026
368131493195275630227837628441540360584402572114334961180023091208287046
088923962328835461505776583271252546093591128203925285393434620904245248
929403901706233888991085841065183173360437470737908552631764325733993712
871937587746897479926305837065742830161637408969178426378624212835258112
820516370298089332099905707920064367426202389783111470054074998459250360
633560933883831923386783056136435351892133279732908133732642652633989763
922723407882928177953580570993691049175470808931841056146322338217465637
321248226383092103297701648054726243842374862411453093812206564914032751
086643394517512161526545361333111314042436854805106765843493523836959653
428071768775328348234345557366719731392746273629108210679280784718035329
131176778924659089938635459327894523777674406192240337638674004021330343
297496902028328145933418826817683893072003634795623117103101291953169794
607632737589253530772552375943788434504067715555779056450443016640119462
580972216729758615026968443146952034614932291105970676243268515992834709
891284706740862008587135016260312071903172086094081298321581077282076353
186624611278245537208532365305775956430072517744315051539600905168603220
349163222640885248852433158051534849622434848299380905070483482449327453
732624567755879089187190803662058009594743150052402532709746995318770724
376825907419939632265984147498193609285223945039707165443156421328157688
908058783183404917434556270520223564846495196112460268313970975069382648
706613264507665074611512677522748621598642530711298441182622661057163515
069260029861704945425047491378115154139941550671256271197133252763631939
606902895650288268608362241082050562430701794976171121233066073310059947
366875
The trick is simple. Simply relate the 2n'th Fibonacci and Lucas numbers to the n'th such numbers. It allows us to work backwards. So to compute F(n) and L(n), we need to know F(n/2) and L(n/2). Clearly this works as long as n is even. For odd n, there are similar schemes that will allow us to move recursively downwards.
For kicks, I just modified the above tool, to accept a modulus. So to compute the last 6 digits of the Fibonacci number with index 1e15, it took about 1/6 of a second.
tic,[Fn,Ln] = fibonacci(1e15,1000000),toc
Elapsed time is 0.161468 seconds.
Fn =
546875
Ln =
328127
Note: In my discussion of recursion to compute the Fibonacci numbers, I do make a few comments on the number of recursive calls required. See that that number is indeed related quite nicely to the Fibonacci sequence itself. This is easily derived.