Intuition behind tail recursionin Fibonacci - python

The following code compute the nth Fibonnacci number:
def fib(n, a=0, b=1):
return fib(n-1, b, a+b) if n > 0 else a
I am struggling to understand how to come up with such a solution.
It looks like the formula comes from a void. However, there must be some steps that led so such a formula. Unfortunately, such a scaffolding has been removed and a clean formula is given.
PS: I am aware that Python does not have TCO.
If there is some graph or animation, it would be perfect.

So. The best explanation I can come up with. Normally, Fibonacci numbers start with 0, 1, to give the sequence
0, 1, 1, 2, 3, 5, 8, 13, 21, ...
But you can have sequences that start with any pair of numbers. For example
2, 5, 7, 12, 19, 31, 50, ....
Now here's an interesting fact. Look at the sequence
1, 1, 2, 3, 5, 8, 13, 21, ...
it's one of these alternative sequences, but it starts with 1, 1. And it just happens to be the elements of the Fibonacci sequence missing the first one.
And
1, 2, 3, 5, 8, 13, 21, 34, ...
is another of these alternate sequences, but it's also the Fibonacci sequence missing the first two elements.
So fib(n, a, b) is just "give me the nth element of the 'alternative' Fibonacci sequence whose first two elements are a and b.

n is the reversed index of fib values
a is fib(n) beginning at 0
b is fib(n+1)

As n decreases with every recursive call, b is passed as the new a while the new b is the old a+b. Notice how that represents exactly the fibonacci logic:
n 0 1 1 2 3 5 8
5 a b
4 a b
3 a b
2 a b
1 a b
0 a b # -> fib(5) == 5 (== a)

Trace through the calls, for n=5 in this case:
def fib(n, a=0, b=1):
return fib(n-1, b, a+b) if n > 0 else a
call fib(5)
call fib(4, 1, 1)
call fib(3, 1, 2)
call fib(2, 2, 3)
call fib(1, 3, 5)
call fib(0, 5, 8)
return 5
return 5
return 5
return 5
return 5
return 5

this is basically the iterative version but written in recursive form:
def fibi(n,a=0,b=1):
while n>0:
a,b = b, a+b
n = n-1
return a
in both cases n is no more that a counter that tell us how many times we should do the a,b = b, a+b step, is the same if we initialize a counter i=0 and count up to until we get to n or like here we decrease n which in this case tell us how many step we have left

The code seems to be just a fancy way of rewriting a simple loop.
Note that n in the recursive code does not interact at all with a or b. It serves just as a counter. It decreases by 1 each time, and when it becomes 0, recursion ends. So it really is just a for loop with n iterations. Then the way a and b are switched everytime, which is fairly a standard way of calculating Fibonacci.
So the following is more or less equivalent rewriting of the code:
def fib(n):
a = 0
b = 1
for _ in range(n):
a, b = b, a + b
return a

Related

How can I get a sum from some elements of a list? [duplicate]

I have a list of numbers. I also have a certain sum. The sum is made from a few numbers from my list (I may/may not know how many numbers it's made from). Is there a fast algorithm to get a list of possible numbers? Written in Python would be great, but pseudo-code's good too. (I can't yet read anything other than Python :P )
Example
list = [1,2,3,10]
sum = 12
result = [2,10]
NOTE: I do know of Algorithm to find which numbers from a list of size n sum to another number (but I cannot read C# and I'm unable to check if it works for my needs. I'm on Linux and I tried using Mono but I get errors and I can't figure out how to work C# :(
AND I do know of algorithm to sum up a list of numbers for all combinations (but it seems to be fairly inefficient. I don't need all combinations.)
This problem reduces to the 0-1 Knapsack Problem, where you are trying to find a set with an exact sum. The solution depends on the constraints, in the general case this problem is NP-Complete.
However, if the maximum search sum (let's call it S) is not too high, then you can solve the problem using dynamic programming. I will explain it using a recursive function and memoization, which is easier to understand than a bottom-up approach.
Let's code a function f(v, i, S), such that it returns the number of subsets in v[i:] that sums exactly to S. To solve it recursively, first we have to analyze the base (i.e.: v[i:] is empty):
S == 0: The only subset of [] has sum 0, so it is a valid subset. Because of this, the function should return 1.
S != 0: As the only subset of [] has sum 0, there is not a valid subset. Because of this, the function should return 0.
Then, let's analyze the recursive case (i.e.: v[i:] is not empty). There are two choices: include the number v[i] in the current subset, or not include it. If we include v[i], then we are looking subsets that have sum S - v[i], otherwise, we are still looking for subsets with sum S. The function f might be implemented in the following way:
def f(v, i, S):
if i >= len(v): return 1 if S == 0 else 0
count = f(v, i + 1, S)
count += f(v, i + 1, S - v[i])
return count
v = [1, 2, 3, 10]
sum = 12
print(f(v, 0, sum))
By checking f(v, 0, S) > 0, you can know if there is a solution to your problem. However, this code is too slow, each recursive call spawns two new calls, which leads to an O(2^n) algorithm. Now, we can apply memoization to make it run in time O(n*S), which is faster if S is not too big:
def f(v, i, S, memo):
if i >= len(v): return 1 if S == 0 else 0
if (i, S) not in memo: # <-- Check if value has not been calculated.
count = f(v, i + 1, S, memo)
count += f(v, i + 1, S - v[i], memo)
memo[(i, S)] = count # <-- Memoize calculated result.
return memo[(i, S)] # <-- Return memoized value.
v = [1, 2, 3, 10]
sum = 12
memo = dict()
print(f(v, 0, sum, memo))
Now, it is possible to code a function g that returns one subset that sums S. To do this, it is enough to add elements only if there is at least one solution including them:
def f(v, i, S, memo):
# ... same as before ...
def g(v, S, memo):
subset = []
for i, x in enumerate(v):
# Check if there is still a solution if we include v[i]
if f(v, i + 1, S - x, memo) > 0:
subset.append(x)
S -= x
return subset
v = [1, 2, 3, 10]
sum = 12
memo = dict()
if f(v, 0, sum, memo) == 0: print("There are no valid subsets.")
else: print(g(v, sum, memo))
Disclaimer: This solution says there are two subsets of [10, 10] that sums 10. This is because it assumes that the first ten is different to the second ten. The algorithm can be fixed to assume that both tens are equal (and thus answer one), but that is a bit more complicated.
I know I'm giving an answer 10 years later since you asked this, but i really needed to know how to do this an the way jbernadas did it was too hard for me, so i googled it for an hour and I found a python library itertools that gets the job done!
I hope this help to future newbie programmers.
You just have to import the library and use the .combinations() method, it is that simple, it returns all the subsets in a set with order, I mean:
For the set [1, 2, 3, 4] and a subset with length 3 it will not return [1, 2, 3][1, 3, 2][2, 3, 1] it will return just [1, 2, 3]
As you want ALL the subsets of a set you can iterate it:
import itertools
sequence = [1, 2, 3, 4]
for i in range(len(sequence)):
for j in itertools.combinations(sequence, i):
print(j)
The output will be
()
(1,)
(2,)
(3,)
(4,)
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)
Hope this help!
So, the logic is to reverse sort the numbers,and suppose the list of numbers is l and sum to be formed is s.
for i in b:
if(a(round(n-i,2),b[b.index(i)+1:])):
r.append(i)
return True
return False
then, we go through this loop and a number is selected from l in order and let say it is i .
there are 2 possible cases either i is the part of sum or not.
So, we assume that i is part of solution and then the problem reduces to l being l[l.index(i+1):] and s being s-i so, if our function is a(l,s) then we call a(l[l.index(i+1):] ,s-i). and if i is not a part of s then we have to form s from l[l.index(i+1):] list.
So it is similar in both the cases , only change is if i is part of s, then s=s-i and otherwise s=s only.
now to reduce the problem such that in case numbers in l are greater than s we remove them to reduce the complexity until l is empty and in that case the numbers which are selected are not a part of our solution and we return false.
if(len(b)==0):
return False
while(b[0]>n):
b.remove(b[0])
if(len(b)==0):
return False
and in case l has only 1 element left then either it can be part of s then we return true or it is not then we return false and loop will go through other number.
if(b[0]==n):
r.append(b[0])
return True
if(len(b)==1):
return False
note in the loop if have used b..but b is our list only.and i have rounded wherever it is possible, so that we should not get wrong answer due to floating point calculations in python.
r=[]
list_of_numbers=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]
list_of_numbers=sorted(list_of_numbers)
list_of_numbers.reverse()
sum_to_be_formed=401.54
def a(n,b):
global r
if(len(b)==0):
return False
while(b[0]>n):
b.remove(b[0])
if(len(b)==0):
return False
if(b[0]==n):
r.append(b[0])
return True
if(len(b)==1):
return False
for i in b:
if(a(round(n-i,2),b[b.index(i)+1:])):
r.append(i)
return True
return False
if(a(sum_to_be_formed,list_of_numbers)):
print(r)
this solution works fast.more fast than one explained above.
However this works for positive numbers only.
However also it works good if there is a solution only otherwise it takes to much time to get out of loops.
an example run is like this lets say
l=[1,6,7,8,10]
and s=22 i.e. s=1+6+7+8
so it goes through like this
1.) [10, 8, 7, 6, 1] 22
i.e. 10 is selected to be part of 22..so s=22-10=12 and l=l.remove(10)
2.) [8, 7, 6, 1] 12
i.e. 8 is selected to be part of 12..so s=12-8=4 and l=l.remove(8)
3.) [7, 6, 1] 4
now 7,6 are removed and 1!=4 so it will return false for this execution where 8 is selected.
4.)[6, 1] 5
i.e. 7 is selected to be part of 12..so s=12-7=5 and l=l.remove(7)
now 6 are removed and 1!=5 so it will return false for this execution where 7 is selected.
5.)[1] 6
i.e. 6 is selected to be part of 12..so s=12-6=6 and l=l.remove(6)
now 1!=6 so it will return false for this execution where 6 is selected.
6.)[] 11
i.e. 1 is selected to be part of 12..so s=12-1=1 and l=l.remove(1)
now l is empty so all the cases for which 10 was a part of s are false and so 10 is not a part of s and we now start with 8 and same cases follow.
7.)[7, 6, 1] 14
8.)[6, 1] 7
9.)[1] 1
just to give a comparison which i ran on my computer which is not so good.
using
l=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,145.21,123.56,11.90,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]
and
s=2000
my loop ran 1018 times and 31 ms.
and previous code loop ran 3415587 times and took somewhere near 16 seconds.
however in case a solution does not exist my code ran more than few minutes so i stopped it and previous code ran near around 17 ms only and previous code works with negative numbers also.
so i thing some improvements can be done.
#!/usr/bin/python2
ylist = [1, 2, 3, 4, 5, 6, 7, 9, 2, 5, 3, -1]
print ylist
target = int(raw_input("enter the target number"))
for i in xrange(len(ylist)):
sno = target-ylist[i]
for j in xrange(i+1, len(ylist)):
if ylist[j] == sno:
print ylist[i], ylist[j]
This python code do what you asked, it will print the unique pair of numbers whose sum is equal to the target variable.
if target number is 8, it will print:
1 7
2 6
3 5
3 5
5 3
6 2
9 -1
5 3
I have found an answer which has run-time complexity O(n) and space complexity about O(2n), where n is the length of the list.
The answer satisfies the following constraints:
List can contain duplicates, e.g. [1,1,1,2,3] and you want to find pairs sum to 2
List can contain both positive and negative integers
The code is as below, and followed by the explanation:
def countPairs(k, a):
# List a, sum is k
temp = dict()
count = 0
for iter1 in a:
temp[iter1] = 0
temp[k-iter1] = 0
for iter2 in a:
temp[iter2] += 1
for iter3 in list(temp.keys()):
if iter3 == k / 2 and temp[iter3] > 1:
count += temp[iter3] * (temp[k-iter3] - 1) / 2
elif iter3 == k / 2 and temp[iter3] <= 1:
continue
else:
count += temp[iter3] * temp[k-iter3] / 2
return int(count)
Create an empty dictionary, iterate through the list and put all the possible keys in the dict with initial value 0.
Note that the key (k-iter1) is necessary to specify, e.g. if the list contains 1 but not contains 4, and the sum is 5. Then when we look at 1, we would like to find how many 4 do we have, but if 4 is not in the dict, then it will raise an error.
Iterate through the list again, and count how many times that each integer occurs and store the results to the dict.
Iterate through through the dict, this time is to find how many pairs do we have. We need to consider 3 conditions:
3.1 The key is just half of the sum and this key occurs more than once in the list, e.g. list is [1,1,1], sum is 2. We treat this special condition as what the code does.
3.2 The key is just half of the sum and this key occurs only once in the list, we skip this condition.
3.3 For other cases that key is not half of the sum, just multiply the its value with another key's value where these two keys sum to the given value. E.g. If sum is 6, we multiply temp[1] and temp[5], temp[2] and temp[4], etc... (I didn't list cases where numbers are negative, but idea is the same.)
The most complex step is step 3, which involves searching the dictionary, but as searching the dictionary is usually fast, nearly constant complexity. (Although worst case is O(n), but should not happen for integer keys.) Thus, with assuming the searching is constant complexity, the total complexity is O(n) as we only iterate the list many times separately.
Advice for a better solution is welcomed :)

Python -While loop to recursive [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
How do you convert the code below to recursive ?
def fibonacci(n):
a, b = 0, 1
fibonacci = [0]
while a < n:
fibonacci.append(b)
a, b = b, a+b
print ('The fibonacci sequence is : '+" ".join(map(str,fibonacci)))
so basically I'm trying write a function fibonacci that receives a
number as parameter and computes the fibonacci series up to that number.
I was able to come up with the above iteration method but it has to be recursive.
This is what I have done so far in terms of converting to recursive but it's not giving me the output I need
def fibo(n, a = 0, b = 1, fib = [0]):
if a < n:
fib.append(b)
a, b = b, a + b
return fib
return fibo(n, a, b, fib)
how about this ?:
def fibonacci(n, a=0, b=1):
if a >= n : return [a]
return [a] + fibonacci(n,b,a+b)
[EDIT] Here's how it works:
The function progressively builds an array by adding one element [a] to the result of the next call to itself.
The first line allows it to stop when the target is reached. Without it, the second line of the function would keep calling itself and there would never be a result coming back from the recursion.
Because the parameters of a function are local to each call, the value of a and b in the second call are different from the previous ones.
If we follow the logic for fibonacci(7), we get:
1) fibonacci(n=7, a=0, b=1) ==> will return [0] + fibonacci(7,1,1).
2) fibonacci(n=7, a=1, b=1) ==> will return [1] + fibonacci(7,1,2).
3) fibonacci(n=7, a=1, b=2) ==> will return [1] + fibonacci(7,2,3).
4) fibonacci(n=7, a=2, b=3) ==> will return [2] + fibonacci(7,3,5).
5) fibonacci(n=7, a=3, b=5) ==> will return [3] + fibonacci(7,5,8).
6) fibonacci(n=7, a=5, b=8) ==> will return [5] + fibonacci(7,8,13).
7) fibonacci(n=7, a=8, b=13) ==> 8 >= 7 so the first line returns [8]
At that point there are no more recursive calls (the first line returns without calling the function again) and the return values start coming back up.
7) returns [8]
6) returns [5,8]
5) returns [3,5,8]
4) returns [2,3,5,8]
3) returns [1,2,3,5,8]
2) returns [1,1,2,3,5,8]
1) returns [0,1,1,2,3,5,8]
One way to think about recursive functions is to look only at the incremental work to be done on the result that would be produced by a prior parameter value. Most of the time this part of the logic applies backwards (i.e computing the end result based on a previous one). For example, a factorial can be thought of as the multiplication of a number with the factorial of the previous number.
This gives you the equivalent of the second line.
Once you have that down, all you need to decide is the condition that makes the recursion stop. Usually this corresponds to the smallest/simplest use case. For example, a factorial does not need to recurse when the number is less than 2 so the function can return 1 directly.
This gives you the equivalent of the first line.
As you can see in the above tracing, the function will proceed "forward" but actually ends up waiting for a result from itself (with different parameters) before being able to complete the process. This is how recursive functions work. The final result is typically built when the return values come back up from the stack of multiple self-calls.
Your fibonacci function is a bit trickier than a factorial because the series can only be computed from the original (0,1) values. Unlike the factorial, we don't have enough information to figure out the value of a and b based on the supplied parameter (n).
And, if you'd like to sink you teeth in cryptic code, here's a one line version:
def fibo(n,a=0,b=1):return [a]+fibo(n,b,a+b) if a < n else [a]
The point of a recursive implementation is to organize things like this:
if we're at a base case:
return the result for that base case
else:
call ourselves with a reduced case
possibly modify the result
return the result
For the base case, a < n, what you do should be related to what you do after the while loop in the iterative version. Adding the last value to the accumulator list fib and returning it makes sense. It may or may not be right, but it's at least in the right direction.
But in your recursive case, you're not calling yourself with a reduced case, you're just calling yourself with the exact same arguments. That's obviously going to be an infinite loop. (Well, Python doesn't do tail call elimination, so it's going to be a stack overflow, which shows up as a max recursion exception, but that's no better.)
So, what should you be doing? Something related to what happens inside the original non-recursive while loop. What you were doing there is:
fibonacci.append(b)
a, b = b, a+b
So, the equivalent is:
fib.append(b)
return fibo(n, b, a+b, fib)
Again, that may not be right, but it's in the right direction. So, if you get the idea, you should be able to carry on from there to debugging the full function.
I think that Dash's answer is correct, modulo a couple of colons. The original question ask for the computation, not printing.
I've added a dict to store computed values to speed things up a bit, and this code works for me:
fib = {}
fib[0] = 0
fib[1] = 1
def fibonacci(n):
if n not in fib.keys():
fib[n] = fibonacci(n - 1) + fibonacci(n - 2)
return fib[n]
if __name__=="__main__":
for i in range(10):
print i, fibonacci(i)
Output:
0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
recursion is a functional heritage
Recursion is a concept that comes from functional style. Mixing imperative-style mutations (like append) and reassignments like a, b = b, a + b is a source of much pain and confusion for new programmers
def fibseq (n, a = 0, b = 1, seq = []):
if n == 0:
return seq + [a]
else:
return fibseq (n - 1, b, a + b, seq + [a])
for x in range (10):
print (fibseq (x))
# [0]
# [0, 1]
# [0, 1, 1]
# [0, 1, 1, 2]
# [0, 1, 1, 2, 3]
# [0, 1, 1, 2, 3, 5]
# [0, 1, 1, 2, 3, 5, 8]
# [0, 1, 1, 2, 3, 5, 8, 13]
# [0, 1, 1, 2, 3, 5, 8, 13, 21]
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def fibonacci(n):
if n == 0:
return 0
elif n == 1
return 1
else
return fibonacci(n - 1) + fibonacci(n - 2)

How to search for combination of digits in number (optimizing for speed)?

I'm trying to look for the number of combinations of 7 digit numbers (or more, actually need it to work for 10, but its faster to test with 7) that have 1,3,5,7 in it. Tried a few different methods like using
combinations = 0
for combination in itertools.product(xrange(10), repeat=7):
if all(x in combination for x in (1,3,5,7)):
combinations += 1
However, this next method worked out to be about 4 times faster as it doesnt look for 3,5,7 if 1 is not in the list.
combinations = 0
for combination in itertools.product(xrange(10), repeat=7):
if 1 in combination:
if 3 in combination:
if 5 in combination:
if 7 in combination:
combinations += 1
I'm sure there is a more cleaver way to achieve this result with numpy or something like that, but I can't figure it out.
Thanks for feedback
The problem is to find k-digit numbers that contain all the digits 1, 3, 5, 7.
This answer contains a number of solutions, increasing in sophistication and algorithmic efficiency. By the end, we'll be able to, in a fraction of a second, count solutions for huge k, for example 10^12, modulo a large prime.
The section at the end includes tests that provide good evidence that all the implementations are correct.
Brute force: O(k10^k) time, O(k) space
We'll use this slow approach to test the more optimized versions of the code:
def contains_1357(i):
i = str(i)
return all(x in i for x in '1357')
def combos_slow(k):
return sum(contains_1357(i) for i in xrange(10 ** k))
Counting: O(k^4) time, O(k) space
The simplest moderately efficient method is to count. One way to do this is to count all k-digit numbers where the first occurrences of the four special digits appear at digits a, b, c, d.
Given such an a, b, c, d, the digits up to a must be 0,2,4,6,8,9, the digit a must be one of [1, 3, 5, 7], the digits between a and b must be either the same as the digit a or any of the safe digits, the digit b must be one of [1, 3, 5, 7] that's different from the digit at a, and so on.
Summing over all possible a, b, c, d gives the result. Like this:
import itertools
def combos0(k):
S = 0
for a, b, c, d in itertools.combinations(range(k), 4):
S += 6 ** a * 4 * 7**(b-a-1) * 3 * 8**(c-b-1) * 2 * 9**(d-c-1) * 10**(k-d-1)
return S
Dynamic programming: O(k) time, O(k) and then O(1) space
You can solve this more efficiently with dynamic programming: let c[j][i] be the number of i-digit numbers which contain exactly j different digits from (1, 3, 5, 7).
Then c satisfies these recurrence relations:
c[0][0] = 1
c[j][0] = 0 for j > 0
c[0][i] = 6 * c[0][i-1] for i > 0
c[j][i] = (6+j)c[j][i-1] + (5-j)c[j-1][i-1] for i, j > 0
The final line of the recurrence relations is the hardest one to understand. The first part (6+j)c[j][i-1] says that you can make an i digit number containing j of the digits 1, 3, 5, 7 from a i-1 digit number containing j of the digits 1, 3, 5, 7, and add an extra digit that's either 0, 2, 4, 6, 8, 9 or any of the digits you've already got. Similarly, the second part (5-j)c[j-1][i-1] says that you can take an i-1 digit number containing j-1 of the digits 1, 3, 5, 7 and make it an i-digit number containing j of the special digits by adding one of the digits you haven't already used. There's 5-j of these.
That leads to this O(k) solution using dynamic programming:
def combos(k):
c = [[0] * (k + 1) for _ in xrange(5)]
c[0][0] = 1
for i in xrange(1, k+1):
c[0][i] = 6 * c[0][i-1]
for j in xrange(1, 5):
c[j][i] = (6 + j) * c[j][i-1] + (5-j) * c[j-1][i-1]
return c[4][k]
We can print combos(10):
print 'combos(10) =', combos(10)
This gives this output:
combos(10) = 1425878520
The solution above is already fast enough to compute combos(10000) in a fraction of a second. But it's possible to optimize the DP solution a little to use O(1) rather than O(k) space by observing that values of c depend only on the previous column in the table. With a bit of care (to make sure that we're not overwriting values before they're used), we can write the code like this:
def combos2(k):
c = [1, 0, 0, 0, 0]
for _ in xrange(k):
for j in xrange(4, 0, -1):
c[j] = (6+j)*c[j] + (5-j)*c[j-1]
c[0] *= 6
return c[4]
Matrix power: O(log k) time, O(1) space.
Ultimately, it's possible to get the result in O(log k) time and O(1) space, by expressing the recurrence relation as a matrix-by-vector multiply, and using exponentiation by squaring. That makes it possible to compute combos(k) modulo X even for massive k (here combos(10^12) modulo 2^31 - 1). That looks like this:
def mat_vec(M, v, X):
return [sum(M[i][j] * v[j] % X for j in xrange(5)) for i in xrange(5)]
def mat_mul(M, N, X):
return [[sum(M[i][j] * N[j][k] for j in xrange(5)) % X for k in xrange(5)] for i in xrange(5)]
def mat_pow(M, k, X):
r = [[i==j for i in xrange(5)] for j in xrange(5)]
while k:
if k % 2:
r = mat_mul(r, M, X)
M = mat_mul(M, M, X)
k //= 2
return r
def combos3(k, X):
M = [[6, 0, 0, 0, 0], [4, 7, 0, 0, 0], [0, 3, 8, 0, 0], [0, 0, 2, 9, 0], [0, 0, 0, 1, 10]]
return mat_vec(mat_pow(M, k, X), [1, 0, 0, 0, 0], X)[4]
print combos3(10**12, (2**31) - 1)
Given that your original code struggled for k=10, this is quite an improvement!
Testing
We can test each of the functions against each other (and combos_slow for small values). Since combos3 has an extra arg, we wrap it in a function that passes a modulo that's guaranteed to be larger than the result.
def combos3p(k):
return combos3(k, 10**k)
for c in [combos0, combos, combos2, combos3p]:
for i in xrange(40 if c == combos0 else 100):
assert c(i) == (combos_slow if i < 7 else combos)(i)
This tests all the implementations against combos_slow for i<7, and against each other for 7 <= i < 100 (except for the less efficient combos0 which stops at 40).

Why Won't Python Won't Do a Lot of Recursion?

I'm doing the Project Euler problems, and I'm on number two. The question is:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I'm trying to solve this in python. I think I have the correct code, but for some reason When I run it with n being anything greater than or equal to 27, it will wait like a minute and just return 0. However, for anything 26 or lower, it runs fine. Here's my code:
def fib_seq(n):
if n == 0:
return n
elif n == 1:
return n
else:
return fib_seq(n-1) + fib_seq(n-2)
def get_fib_sum(n):
x = n
sum = 0
for i in range(n):
if fib_seq(x) > 4000000:
pass
elif fib_seq(x) % 2 == 0:
pass
else:
sum += fib_seq(x)
x = i
return sum
print get_fib_sum(27)
Is there anyway to fix this or at least get it to work? If it makes a difference, I'm using Wing IDE 101 Student Edition.
In your loop, you are using fib_seq(x) and it should be fib_seq(i)
Also, if you want to reduce time a bit more, you can use memoization technique
def fib_seq(n):
if n == 0:
return n
elif n == 1:
return n
else:
return fib_seq(n-1) + fib_seq(n-2)
def memoize(fn, arg):
memo = {}
if arg not in memo:
memo[arg] = fn(arg)
return memo[arg]
fibm = memoize(fib_seq,27)
print fibm
Why are you using recursion? your code is recalculating the ENTIRE fibonnaci sequence over and over and over and over and over... The code just wants the sum of the even terms. There is NO need for recursion. In pseudo-code:
t1 = 1
t2 = 2;
sum = 2;
do {
t3 = t1 + t2;
if (t3 is even) {
sum += t3;
}
t1 = t2;
t2 = t3;
} while (t2 <= 4000000)
Fibonacci sequence is often used as an example of how to write recursive code, which is ridiculous because it has a very straight-forward iterative solution:
def fib(n):
if n < 2:
return n
else:
a, b = 1, 1
for _ in range(2, n): # O(n)
a, b = b, a+b
return b
What is less obvious is that it also has a matrix representation,
F = [[0, 1]] # initial state
T = [[0, 1], # transition matrix
[1, 1]]
fib(n) = (F * T**n)[0][0]
which is extremely useful because T**n can be computed in O(log(n)) steps.
(As an aside, the eigenvector of the log of the transition matrix leads to the analytic solution,
phi = (1 + 5**0.5) / 2 # golden ratio
fib(n) = round(phi**n / 5**0.5, 0)
but that's not where I'm going with this.)
Looking at the terms produced in terms of odd-or-even, you see
n: 0, 1, 2, 3, 4, 5, 6, 7, 8, ...
f(n): 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
e/o: even, odd, odd, even, odd, odd, even, odd, odd, ...
so what you need is fib(0) + fib(3) + fib(6) + ... and computing T**3 gives you the coefficients needed to step directly from term to term.
The rest is left as an exercise for the reader ;-)
It does a lot of recursion, that's why it's taking so long.
The get_fib_sum() will evaluate fib_seq(27) in a loop, which does a lot of recursion and takes a while. Since the result of fib_seq(27) is greater then 4000000 it will then will never add anything to sum, returning 0 in the end.

Summing consecutive third numbers in python

How would I solve this?
The program should contain the definition for the function sumTri(cutOff). The function adds Tri numbers into the sum.
Tri numbers are every third number: 1, 4, 7, 10, .... The function adds consecutive Tri numbers 1, 4, 7, ... into the sum so long as the Tri number is less than the cutOff. The function returns the sum of these numbers.
It's simple:
def sumTri(cutOff):
return sum(range(1,cutOff,3))
Or, when you need it lowlevel:
def sumTri(cutOff):
sum = 0
tri = 1
while tri < cutOff:
sum += tri
tri += 3
return sum
I'll try to explain both soultions a little bit.
In the first case you use two "highlevel" functions of Python, that make all work for you: sum and range. The range(a,b,c) function generates a list of numbers from a to b with the step c between. E.g.:
In [1]: range(1,10,3)
Out[1]: [1, 4, 7]
In [2]: range(1,22,3)
Out[2]: [1, 4, 7, 10, 13, 16, 19]
You must note here that range generates numbers until the number in the list is less than b, not less-or-equal. Exactly what you need for your task.
And sum obviously calculates and returns the sum of the numbers in the list that it has as its argument:
In [3]: sum([1])
Out[3]: 1
In [4]: sum([1,2])
Out[4]: 3
In [5]: sum([1,2,3])
Out[5]: 6
Now you need just to combine these two functions:
return sum(range(1,cutOff,3))
The second solution is more "lowlevel" and "algorithmic". You use no special python functions here and do everything yourself.
You use two variable to calculate the sum:
sum -- the variable where you store your sum
tri -- the variable with the current value of number that you add step by step
When you write something like:
a = a + 5
that means: "Now I want a to be equal to what a was before plus 5" or "increase a by 5". You can write it shorter:
a += 5
These two forms are equivalent.
But you need not simple add something. You need to do it for many times until something is happened. In python you do it using while:
while someting-is-true:
do-something
Every time while checks the something-is-true condition, and when it's True, it makes commands that are under while (indented) i.e. do-something.
Now you know all necessary to write the solution:
def sumTri(cutOff):
sum = 0 # we start the sum from 0
tri = 1 # and the first number to add is 1
while tri < cutOff: # next number to add < cutOff?
sum += tri # than add it to sum
tri += 3 # and increase the number by 3
return sum # now you have the result, return it
That was the function that makes the job. Now you can use the function.
How you do this?
def sumTri(cutOff):
...
# anywhere in you program:
# presuming a is the cutOff
print sumTri(a)
when you want to run the function and use its result you just write function_name(args).
This sequence is related to triangular numbers
Here is one that is O(1)
def sumTri(cutoff):
n = (cutoff+1)//3
return (3*n-1)*n//2

Categories

Resources