Python - Modify dictionary from function - python

Okay, this question is a little strange, but I was wondering if I could do it like this.
I'm working on a simple Fibonacci number generator for fun since I was interested in programming it.
So I wrote this out:
def f(n):
if n == 1: return 1
if n == 2: return 2
else:
return f(n-1) + f(n-2)
and that ran very slowly, taking 15 seconds to do f(30) on my computer.
So then I wrote this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
which basically stores previous results in a dictionary like so:
{'f(1)':1,'f(2)':2,'f(3)':3,'f(4)':5} and so on. In the function it would check if that result was in that dictionary, then just use that instead of having to redo all the calculations.
This made it tons faster. I could do f(100) and it instantly appear. Going by intervals of 500, I got to f(4000) and it was still instantaneous. The one problem was that the dictionary was getting stupidly big.
So I added a = {} to the end of the function, and that didn't work; it still left a as a massive dict.
So doing this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
a = {}
didn't work. but if I do this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
# now run the function
f(100)
a = {}
a gets reset to an empty dictionary. Why does this happen and how can I fix it?

Your a = {} statement inside the function was never being executed; every possible path of execution reaches a return before then. If it WAS executed, you wouldn't have liked the results - it would have executed in every single recursive call to the function, meaning that your dictionary would never hold more than one item! You would somehow have to detect the outermost call and only clear the dict there, or (much simpler) clear it outside of the recursion as in your second example.
Note that much of the size of your dictionary is coming from the strange decision to use a long string key. Keying it with the number itself (as in a[n] = z) would make it much more compact.
(For future reference: the technique you've come up with here, of saving the results from previous function calls, is known as "memoization".)

Despite your question, what you really want is a faster way of calculating Fibonacci sequence, right? The problem with your original approach is that recurrence, despite being very elegant and quick to code, is quite slow. Fibonacci sequence has a close form solution. You should do this math directly to speed up your code.
As convention, consider the Fibonacci sequence F(i) as: F(0) = 0, F(1) = 1, F(k) = F(k-1) + F(k-2) k = 2, 3, ... The solution for this sequence is (I will not demonstrate it here, because is not the place for that) F(k) = (1/sqrt(5))*(a^k - b^k), where a = (1 + sqrt(5))/2 and b = (1 - sqrt(5))/2.
Thus, you code could be implemented like this:
def f(n):
a = (1 + 5**.5)/2
b = (1 - 5**.5)/2
F = (a**n - b**n)/5**.5
F = int(round(F)) #necessary to get an integer without the decimal part of the approximation. Afterall, you are working with irrational numbers.
return F
This code scale very well for large values of n.

Related

python for loop to evaluate equation

I'm asked to write a function that should return the sum of the following series 1000 + 1/1**2 + 1/2**2 + 1/3**2 + 1/4**2 + ... + 1/n**2
for the given integer n.
For example, for n = 0, the function should return 1000, for n = 1,
the function should return 1001, for n = 2, the function should return 1001.25, for n = 3, the function should return 1001.3611111111111, etc.
I know for sure this needs to be done by for loops and range functions.
Here's my code
if n<0:
return None
if n>0 or n==0:
for i in range(1,n-1):
result=1000+1/(i**2)
return result
But it keeps return None when n=o,1,2,3
I'm not sure how to fix this code...
In each iteration, you are not updating result using the previous value of it. (Also you are returning result prematurely.) Update the variable by using result = result + 1 / (i ** 2), or equivalently, result += 1 / (i ** 2).
def foo(n):
result = 1000
for i in range(1, n+1):
result += 1 / (i ** 2)
return result
print(foo(0), foo(1), foo(2), foo(3)) # 1000 1001.0 1001.25 1001.3611111111111
Or, using (generator) comprehension,
def foo(n):
return 1000 + sum(1 / (i ** 2) for i in range(1, n + 1))
You don't need any if statements. What you're doing right now is calculating result, then immediately returning the result on step 1.
result = 1000
for i in range(1,n+1):
result += 1/(i**2)
return result
Comment if anything doesn't make sense
First, you can only return from within a function, but your code has no function definition included - maybe you forgot. Second, if this code is part of a function, the first iteration of the loop will throw you out of the function as soon as it hits return, so this function, if implemented, will not complete the intended loop iterations. Since this is a homework question, I will not complete the code, but I hope this gives you a start.

Is there an efficient way of invoking this recursive function only once?

Here is a code that finds the value of the function T given by the recurrence relation for a given value of n:
def T(n):
if n <= 0:
return 1
else:
return T(n-1) + (n-1) * T(n-2)
print T(3)
#output
2
However, the code invokes the function T twice. I have added the print statement before the second return to show this:
def T(n):
if n <= 0:
return 1
else:
print (T(n-1) + (n-1) * T(n-2))
return T(n-1) + (n-1) * T(n-2)
print T(3)
#output
1
2
1
2
Is there an efficient way of invoking the function T only once? I'm using Python 2. I'd like something short and simple, nothing too complicated.
You're going to call T 2^(n-1) times, for n >1, and there is no way to reduce that to only once without removing the recursion.
If you meant to say that you want to reduce the repetitive calls, such as T(3) calls T(2) and T(1) while T(2) also calls T(1), then you need to use a process called memoization
For example, using a dictionary of inputs to results.
seen = dict()
def T(n):
if n <= 0:
return 1
else:
if n in seen:
return seen[n]
else:
result = T(n-1) + (n-1) * T(n-2)
seen[n] = result
return result
print(T(3))
You can redefine the function from T(n) = T(n-1) + (n-1)*T(n-2) to T(n+1) = T(n) + n*T(n-1) which will allow the recursion to move forward rather than backward provided you give it the current n and previous values. By only needing the previous value instead of the two previous values, the recursive progression is easier to grasp.
def T(N,n=1,Tm=1,Tn=1): # n,Tm,Tn represent n,T(n-1),T(n)
if n>N: return Tm # stop at n=N+1 and return T(n-1)
return T(N,n+1,Tn,Tn+n*Tm)
note: the function returns a when n>N in order to cover the case where N is zero.
Actually, this could also have been written without transposing the function by moving the stop condition to N+2 instead of N+1:
def T(N,n=2,Tn_2=1,Tn_1=1): # n,Tn_2,Tn_1 represent n,T(n-2),T(n-1)
if n==N+2: return Tn_2 # stop at n=N+2 and return T(n-2)
return T(N,n+1,Tn_1,Tn_1+(n-1)*Tn_2)
which can be further simplified to:
def T(N,n=1,a=1,b=1): return T(N-1,n+1,b,a*n+b) if N else a

This program i am creating for Fibonacci but it return none.Kindly solve this problem

def fibonacci(n):
for i in range(n,1):
fab=0
if(i>1):
fab=fab+i
i=i-1
return fab
elif i==0:
return 0
else:
return 1
n1 = int(input("enter the nth term: "))
n2=fibonacci(n1)
print(n2)
The only way your code can return none is if you enter an invalid range, where the start value is greater than or equal to the stop value (1)
you probably just need range(n) instead of range(n, 1)
You can do this too:
def fibonacci(n):
return 0 if n == 1 else (1 if n == 2 else (fibonacci(n - 1) + fibonacci(n - 2) if n > 0 else None))
print(fibonacci(12))
You may need to use recursion for for nth Fibonacci number:
ex:
def Fibonacci(n):
if n==1:
return 0
elif n==2:
return 1
else:
return Fibonacci(n-1)+Fibonacci(n-2)
print(Fibonacci(9))
# output:21
If you do not plan to use large numbers, you can use the easy and simple typical recursive way of programming this function, although it may be slow for big numbers (>25 is noticeable), so take it into account.
def fibonacci(n):
if n<=0:
return 0
if n==1:
return 1
return fibonacci(n-1)+fibonacci(n-2)
You can also add a cache for the numbers you already stepped in, in order to make it run much faster. It will consume a very small amount of extra memory but it allows you to calculate larger numbers instantaneously (you can test it with fibonacci(1000), which is almost the last number you can calculate due to recursion limitation)
cache_fib = {}
def fibonacci(n):
if n<=0:
return 0
if n==1:
return 1
if n in cache_fib.keys():
return cache_fib[n]
result = fibonacci(n-1)+fibonacci(n-2)
cache_fib[n] = result
return result
In case you really need big numbers, you can do this trick to allow more recursion levels:
cache_fib = {1:1}
def fibonacci(n):
if n<=0:
return 0
if n in cache_fib.keys():
return cache_fib[n]
max_cached = max(cache_fib.keys())
if n-max_cached>500:
print("max_cached:", max_cached)
fibonacci(max_cached+500)
result = fibonacci(n-1)+fibonacci(n-2)
cache_fib[n] = result
return result
range(n,1) creates a range starting with n, incrementing in steps of 1 and stopping when n is larger or equal to 1. So, in case n is negative or zero, your loop will be executed. But in case n is 1 or larger, the loop will never be executed and the function just returns None.
If you would like a range going from n downwards to 1, you can use range(n,1,-1) where -1 is the step value. Note that when stepping down, the last number is included range(5,1,-1) is [5,4,3,2,1] while when stepping upwards range(1,5) is [1,2,3,4] the last element is not included. range(n) with only one parameter also exists. It is equivalent to range(0, n) and goes from 0 till n-1, which means the loop would be executed exactly n times.
Also note that you write return in every clause of the if statement. That makes that your function returns its value and interrupts the for loop.
Further, note that you set fab=0 at the start of your for loop. This makes that it is set again and again to 0 each time you do a pass of the loop. Therefore, it is better to put fab=0 just before the start of the loop.
As others have mentioned, even with these changes, your function will not calculate the Fibonacci numbers. A recursive function is a simple though inefficient solution. Some fancy playing with two variables can calculate Fibonacci in a for loop. Another interesting approach is memorization or caching as demonstrated by #Ganathor.
Here is a solution that without recursion and without caching. Note that Fibonacci is a very special case where this works. Recursion and caching are very useful tools for more real world problems.
def fibonacci(n):
a = 0
b = 1
for i in range(n):
a, b = a + b, a # note that a and b get new values simultaneously
return a
print (fibonacci(100000))
And if you want a really, really fast and fancy code:
def fibonacci_fast(n):
a = 1
b = 0
p = 0
q = 1
while n > 0 :
if n % 2 == 0 :
p, q = p*p + q*q, 2*p*q + q*q
n = n // 2
else:
a, b = b*q + a*q + a*p, b*p + a*q
n = n - 1
return b
print (fibonacci_fast(1000000))
Note that this relies on some special properties of the Fibonacci sequence. It also gets slow for Python to do calculations with really large numbers. The millionth Fibonacci number has more than 200,000 digits.

Avoid variable recomputation?

I have a line code like this -
while someMethod(n) < length and List[someMethod(n)] == 0:
# do something
n += 1
where someMethod(arg) does some computation on the number n. The problem with this code is that I'm doing the same computation twice, which is something I need to avoid.
One option is to do this -
x = someMethod(n)
while x < length and List[x] == 0:
# do something
x = someMethod(n + 1)
I am storing the value of someMethod(n) in a variable x and then using it later. However, the problem with this approach is that the code is inside a recursive method which is called multiple times. As a result, a lot of excess instances of variables x are being created which slows the code down.
Here's the snipped of the code -
def recursion(x, n, i):
while someMethod(n) < length and List[someMethod(n)] == 0:
# do something
n += 1
# some condition
recursion(x - 1, n, someList(i + 1))
and this recursion method is called many times throughout the code and the recursion is quite deep.
Is there some alternative available to deal with a problem like this?
Please try to be language independent if possible.
You can use memoization with decorators technique:
def memoize(f):
memo = dict()
def wrapper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return wrapper
#memoize
def someMethod(x):
return <your computations with x>
As i understand your code correctly you are looking for some sort of memorization.
https://en.wikipedia.org/wiki/Memoization
it means that on every recursive call you have to save as mush as possible past calculations to use it in current calculation.

How do I return the product of a while loop

I don't get the concept of loops yet. I got the following code:
x=0
while x < n:
x = x+1
print x
which prints 1,2,3,4,5.
That's fine, but how do I access the computation, that was done in the loop? e.g., how do I return the product of the loop( 5*4*3*2*1)?
Thanks.
Edit:
That was my final code:
def factorial(n):
result = 1
while n >= 1:
result = result *n
n=n-1
return result
You want to introduce one more variable (total) which contains accumulated value of a bunch of actions:
total = 1
x = 1
while x <= 5:
total *= x
x += 1
print x, total
print 'total:', total
Actually, more pythonic way:
total = 1
n = 5
for x in xrange(1, n + 1):
total *= x
print total
Note, that the initial value of total must be 1 and not 0 since in the latter case you will always receive 0 as a result (0*1*.. is always equals to 0).
By storing that product and returning that result:
def calculate_product(n):
product = 1
for x in range(n):
product *= x + 1
return product
Now we have a function that produces your calculation, and it returns the result:
print calculate_product(5)
A "one-liner"
>>> import operator
>>> reduce(operator.mul, xrange(1, n + 1))
120
>>>
Alternately you could use the yield keyword which will return the value from within the while loop. For instance:
def yeild_example():
current_answer = 1
for i in range(1,n+1):
current_answer *= i
yield current_answer
Which will lazily evaluate the answers for you. If you just want everything once this is probably the way to go, but if you know you want to store things then you should probably use return as in other answers, but this is nice for a lot of other applications.
This is called a generator function with the idea behind it being that it is a function that will "generate" answers when asked. In contrast to a standard function that will generate everything at once, this allows you to only perform calculations when you need to and will generally be more memory efficient, though performance is best evaluated on a case-by-case basis. As always.
**Edit: So this is not quite the question OP is asking, but I think it would be a good introduction into some of the really neat and flexible things about python.
use a for loop:
sum_ = 1
for i in range(1, 6):
sum_ *= i
print sum_
If you prefer to keep your while loop structure, you could do it like (there are 1000 +1 ways to do it ...):
x=1
result = 1
while x <= n:
x += 1
result *= x
Where result will store the factorial. You can then just return or print out result, or whatever you want to do with it.
to access the computation done in the loop, you must use counter(with useful and understandable name), where you will store the result of computation. After computation you just return or use the counter as the product of the loop.
sum_counter=0
x=0
while x < 10:
sum_counter +=x
x+=1
print sum_counter

Categories