Runtime error - where is the mistake in my code - python

My former problem (which is solved now) was:
As an input, I have a list of nonnegative whole numbers which are supposed to be the coefficients of a polynomial. But I also want to evaluate the polynomial for a certain number x.
For example:
If we have L=[2,3,1] as an input and x=42 we get 2x^2+3x+1=3655
What I want is for example:
>>>p=polynomial([2,3,1])
>>>p(O)
1
>>>p(42)
>>>3655
The code is
def polynomial(coef):
def poly(x):
result = 0
x_n = 1
for a in reversed(coef):
result += a * x_n
x_n *= x
return result
return poly
What I wanted to do now is to find the inverse , that means the input the is a monotone polynomial and the positive whole number y and I want to find a whole number x such that p(x)=y, and x should be only in [1,10**10], for example:
>>>p=polynomial([2,3,1])
>>>p(O)
1
>>>p(42)
>>>3655
>>>invert(3655,p)
42
This is what I have so far, but what I get is a runtime error:
def polynomial(coef):
def poly(x):
result = 0
xn = 1
for c in reversed(coef):
result += c * xn
xn *= x
return result
return poly
def invert(y,p):
test=10**10
if p(2)>p(1):
if p(test)>y:
test=test//2 +(test%2)
return invert(y,p)
elif p(test)<y:
test=test+(test//2)
return invert(y,p)
else:
return test
if p(2)<p(1):
if p(test)<y:
test=test//2 +(test%2)
return invert(y,p)
elif p(test)>y:
test=test+(test//2)
return invert(y,p)
else:
return test
The error that occurs is
...
File "poly.py", line 17, in invert
return invert(y,p)
File "poly.py", line 14, in invert
if p(2)>p(1):
File "poly.py", line 5, in poly
for c in reversed(coef):
RuntimeError: maximum recursion depth exceeded while calling a Python object
What am I doing wrong?

Your invert function recurses forever because you never modify the arguments that you pass to the next call. You do modify test, but that doesn't do you any good, since the inner call will have its own copy of test.
There are a few ways you could fix the issue. You could pass test as an argument to the invert function, with your initial value a default that will be used the first time:
def invert(y, p, test=10**10):
# ...
# later, when you recurse:
test = test // 2 # or whatever
return invert(y, p, test) # pass on the modified test value
Another (probably better) approach would be to abandon recursion, and use a loop instead. A while loop seems like it would be appropriate here:
def invert(y, p):
test = 10**10
sign = (-1)**(p(2) < p(1))
while True:
if p(test) > y:
test -= sign * (test // 2)
elif p(test) < y:
test += sign * (test // 2)
else:
return test # this is the only case that returns
I've left the overall algorithm the same as what your original code does (just streamlined a bit). That algorithm may not be correct if your polynomial isn't strictly increasing or strictly decreasing. You should really compute the derivative of the polynomial at test to determine which direction to adjust in, but I'll leave that to you to figure out.

I took the liberty to fix the indention of the code you posted. Please verify that the below code is actually what you have, regarding indentions The following code does return your desired output..
def polynomial(coef):
def poly(x):
result = 0
x_n = 1
for a in reversed(coef):
result += a * x_n
x_n *= x
return result
return poly
def invert(y,p,test): # updated
# test=10**10 # This was the problem
# You reset 'test' for every recursive call
# which means you will stand still without
# any progress until the max num of allowed
# recursive calls are reached.
if p(2)>p(1):
if p(test)>y:
test=test//2 +(test%2)
return invert(y,p,test) # updated
elif p(test)<y:
test=test+(test//2)
return invert(y,p,test) # updated
else:
return test
if p(2)<p(1):
if p(test)<y:
test=test//2 +(test%2)
return invert(y,p,test) # updated
elif p(test)>y:
test=test+(test//2)
return invert(y,p,test) # updated
else:
return test
p = polynomial([2,3,1])
t = 10**10
print(invert(3655,p,t))

I wrote the code myself now, limiting everything to the knowledge/skill I only have so far, and it works:
def polynomial(coef):
def poly(x):
result = 0
x_n = 1
for a in reversed(coef):
result += a * x_n
x_n *= x
return result
return poly
def invert(y,p):
x=10**10
while p(x)!=y:
if p(x)>y:
w=x
x=x//2
elif p(x)<y:
x=(x+w)//2
return x

Related

How to fix TypeError: 'Add' object is not callable?

def f(x):
f='exp(x)-x-2'
y=eval(f)
print(y)
return y
def bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2):
x=a
result_a=f(a)
x=b
result_b=f(b)
if (f.evalf(a)*f.evalf(b)>=0):
print("Interval [a,b] does not contain a zero ")
exit()
zeta=min(epsilon1,epsilon2)/10
x=a
while(f_line(x)>0):
if(x<b or x>-b):
x=x+zeta
else:
stop
ak=a
bk=b
xk=(ak+bk)/2
k=0
if (f(xk)*f(ak)<0):
ak=ak
bk=xk
if (f(xk)*f(bk)<0):
ak=xk
bk=bk
k=k+1
from sympy import *
import math
x=Symbol('x')
f=exp(x)-x-2
f_line=f.diff(x)
f_2lines=f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a=int(input('Beginning of interval: '))
b=int(input('End of interval: '))
epsilon1=input('1st tolerance: ')
epsilon2=input('2nd tolerance: ')
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
This program is an attempt to implement the Bissection Method. I've tried writing two functions:
The first one, f, is supposed to receive the extremes of the interval that may or may not contain a root (a and b) and return the value of the function evaluated in this point.
The second one, bissection, should receive the function, the function's first and second derivatives, the extremes of the interval (a,b) and two tolerances (epsilon1,epsilon2).
What I want to do is pass each value a and b, one at a time, as arguments to the function f, that is supposed to return f(a) and f(b); that is, the values of the function in each of the points a and b.
Then, it should test two conditions:
1) If the function values in the extremes of the intervals have opposite signs. If they don't, the method won't converge for this interval, then the program should terminate.
if(f.evalf(a)*f.evalf(b)>=0)
exit()
2)
while(f_line(x)>0): #while the first derivative of the function evaluated in x is positive
if(x<b or x>-b): #This should test whether x belongs to the interval [a,b]
x=x+zeta #If it does, x should receive x plus zeta
else:
stop
At the end of this loop, my objective was to determine whether the first derivative was strictly positive (I didn't do the negative case yet).
The problem: I'm getting the error
Traceback (most recent call last):
File "bissec.py", line 96, in <module>
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
File "bissec.py", line 41, in bissection
result_a=f(a)
TypeError: 'Add' object is not callable
How can I properly call the function so that it returns the value of the function (in this case, f(x)=exp(x)-x-2), for every x needed? That is, how can I evaluate f(a) and f(b)?
Ok, so I've figured it out where your program was failing and I've got 4 reasons why.
First of all, and the main topic of your question, if you want to evaluate a function f for a determined x value, let's say a, you need to use f.subs(x, a).evalf(), as it is described in SymPy documentation. You used in 2 different ways: f.evalf(2) and f_line(a); both were wrong and need to be substituted by the correct syntax.
Second, if you want to stop a while loop you should use the keyword break, not "stop", as written in your code.
Third, avoid using the same name for variables and functions. In your f function, you also used f as the name of a variable. In bissection function, you passed f as a parameter and tried to call the f function. That'll fail too. Instead, I've changed the f function to f_calc, and applied the correct syntax of my first point in it.
Fourth, your epsilon1 and epsilon2 inputs were missing a float() conversion. I've added that.
Now, I've also edited your code to use good practices and applied PEP8.
This code should fix this error that you're getting and a few others:
from sympy import *
def func_calc(func, x, val):
"""Evaluate a given function func, whose varible is x, with value val"""
return func.subs(x, val).evalf()
def bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2):
"""Applies the Bissection Method"""
result_a = func_calc(f, x, a)
result_b = func_calc(f, x, b)
if (result_a * result_b >= 0):
print("Interval [a,b] does not contain a zero")
exit()
zeta = min(epsilon1, epsilon2) / 10
x_val = a
while(func_calc(f_line, x, a) > 0):
if(-b < x_val or x_val < b):
x_val = x_val + zeta
else:
break # the keyword you're looking for is break, instead of "stop"
print(x_val)
ak = a
bk = b
xk = (ak + bk) / 2
k = 0
if (func_calc(f, x, xk) * func_calc(f, x, ak) < 0):
ak = ak
bk = xk
if (func_calc(f, x, xk) * func_calc(f, x, bk) < 0):
ak = xk
bk = bk
k = k + 1
def main():
x = Symbol('x')
f = exp(x) - x - 2
f_line = f.diff(x)
f_2lines = f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a = int(input('Beginning of interval: '))
b = int(input('End of interval: '))
epsilon1 = float(input('1st tolerance: '))
epsilon2 = float(input('2nd tolerance: '))
bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2)
if __name__ == '__main__':
main()

Calculating Napier constant (e) using recursion

I am attempting to approximate the value of e (~2.7)
Defined by this, for each nth term
using a recursive function in python.
So far I have gotten this,
def NapierConstant(runs):
return 2 + 1/contfrac(1, 2, runs)
def contfrac(v1, v2, limit):
if v1 == limit:
return (v1/v2)
else:
return v1+(v1/contfrac(v1+1, v2+1, limit))
print(NapierConstant(2))
this should output 2.72727 here, but instead I get 2.4, and the error margin get's worse for each following step. I have googled, and I can't manage to figure out how to set up the function recursively so that it outputs the expected values.
def get_e(lim):
return 2 + 1/r(1, lim)
def r(v1, lim):
if v1 == lim:
return v1 + v1/(v1+1)
else:
return v1 + v1/(r(v1+1, lim))

Wting reversed function using bisection method in logarithmic run time

I'm trying to write a function that can take any function and return the a parameter that if put in the function, will return answer close to 0 (close to epsilon), the function will look something like this:
def solve(f, x0=-10000, x1=10000, epsilon=EPSILON):
the x0, x1 are the range in which to look for the answer.
another thing I know is that it applies only to the function that can be both positive and negative ( for example f(X) = x^2+1 is not a good function to solve).
I found an answer here Bisection method
def solve(f, x0=-10000, x1=10000, epsilon=EPSILON):
""" return the solution to f in the range between x0 and x1\
use an algorithm to check if a solution can be found so f(x)<epsilon
iterates in a while loop until either a solution is found or if the abs
the value of the midpoint is smaller than epsilon (return None)"""
# make sure the function is in the type that can be solved
if (f(x1) * f(x0)) >= 0:
return None
while True:
mid = (x0 + x1) / 2
sol = f(mid)
if abs(sol) < epsilon:
return mid
if mid == 0 or (abs(f(x1) - f(x0)) / 2) < epsilon:
return None
elif sol * f(x0) < 0:
x1 = mid
elif sol * f(x1) < 0:
x0 = mid
edit:
so far so good. now I have the main function I need to write - a function that gives the revered value for function. the function itself gets the function that needs to be reversed and an epsilon to which the answer suppose to be close to.
for example, for f(x) = x+2, I want the inverse_func(f(100)) to return 100.
the hint I have is that I can use the prev function that I showed. I tryied doing so like this:
def inverse(g, epsilon=EPSILON):
"""return f s.t. f(g(x)) = x"""
def ret_function(x):
return find_x(x, g, epsilon)
return ret_function
def find_x(x, g, epsilon):
x0, x1 = -10000, 1001
g_sol = x
sent_epsilone = EPSILON
while True:
def f(x):
g_val = g(x)
ans = g_sol - g_val
return ans
sol = solve(f, x0, x1, sent_epsilone)
if sol == None:
pass
else:
return sol
x0, x1 = x0 * 10, x1 * 10
what I tried to give "solve" function to solve the problem for me. I'm giving it a function that calculates the given value from f(x) minus a value that solve function needs to find.
for example for f(x) = x+2, then a call to
minus_func = inverse(g(100)) =inverse(102)
print(minus_func)
is suppos to return
100
because it the function inside "solve" is 102-f(x) and of course "solve" can find the right value for this.
and I tried this in my code, and it work fine, but not good enough. for some functions, it works fine. but for others, it doesn't work at all.
for the functions:
math.e**x
x**-3
and probably others, it doesn't work. does someone has an idea how to solve this?.
p.s - I'm writing the code in python so it'll be great if the answer is also in python. but anything else is ok (I know java also and anything that will explain the logic is, of course, great)
thanks!
The condition
if mid == 0 or (abs(f(x1) - f(x0)) / 2) < epsilon:
return None
does not make sense. Why is 0 excluded as a possible root? With the default initial values the method will fail in the first loop. And if the function values are that close, they either have the same sign, which was excluded, or they represent a root of the function since both values are small enough.
It should be replaced by the missing
if abs(x1-x0) < epsilon:
return mid
Try this implementation of binary search:
def solve(f, x0=-10000, x1=10000, epsilon=EPSILON):
if f(x0) * f(x1) > 0: # predicate of binary search
return None
while x1 - x0 > epsilon: # while search interval is bigger than EPS
mid = (x0 + x1) / 2 # take middle of interval
sol = f(mid) # take function value in mid point
if sol * f(x0) > 0: # one of roots is located in [mid, x1] interval
x0 = mid
else: # one of roots is located in [x0, mid] interval
x1 = mid
return (x0 + x1) / 2
Feel free to ask questions about it.

Project Euler #15 in Python

I am newbie in Python. I'm stuck on doing Problem 15 in Project-Euler in reasonable time. The problem in memoize func. Without memoize all working good, but only for small grids. I've tried to use Memoization, but result of such code is "1" for All grids.
def memoize(f): #memoization
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
global route
if node[0] >= k and node[1] >= k:
route += 1
return route
else:
if node[0] < k + 1 and node[1] < k + 1:
search((node[0] + 1, node[1]))
search((node[0], node[1] + 1))
return route
k = 2 #grid size
route = 0
print(search((0, 0)))
If commenting out code to disable memoize func:
##memoize
all works, but to slow for big grids. What am i doing wrong? Help to debbug. Thx a lot!
Update1:
Thank for your help, I've found answer too:
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
n = 0
if node[0] == k and node[1] == k:
return 1
if node[0] < k+1 and node[1] < k+1:
n += search((node[0] + 1, node[1]))
n += search((node[0], node[1] + 1))
return n
k = 20
print(search((0, 0)))
Problem was not in memoize func as i thought before. Problem was in 'search' function. Whithout globals it wroiking right i wished. Thx for comments, they was really usefull.
Your memoization function is fine, at least for this problem. For the more general case, I'd use this:
def memoize(f):
f.cache = {} # - one cache for each function
def _f(*args, **kwargs): # - works with arbitrary arguments
if args not in f.cache: # as long as those are hashable
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
return _f
The actual problem -- as pointed out by Kevin in the comments -- is that memoization only works if the function does not work via side effects. While your function does return the result, you do not use this in the recursive calculation, but just rely on incrementing the global counter variable. When you get an earlier result via memoization, that counter is not increased any further, and you do not use the returned value, either.
Change your function to sum up the results of the recursive calls, then it will work.
You can also simplify your code somewhat. Particularly, the if check before the recursive call is not necessary, since you check for >= k anyway, but then you should check whether the x component or the y component is >= k, not both; once either has hit k, there's just one more route to the goal. Also, you could try to count down to 0 instead of up to k so the code does not need k anymore.
#memoize
def search(node):
x, y = node
if x <= 0 or y <= 0:
return 1
return search((x - 1, y)) + search((x, y - 1))
print(search((20, 20)))
Try this code. It works fast even with grids over 1000x1000! Not nessesarily square.
But I didn't know about memoization yet...
import time
def e15():
x=int(input("Enter X of grid: "))
y=int(input("Enter Y of grid: "))
start = time.time()
lst=list(range(1,x+2))
while lst[1]!=y+1:
i=0
for n in lst[1:]:
i+=1
lst[i]=n+lst[i-1]
print(f"There are {lst[-1]} routes in {x}x{y} grid!")
end = time.time() - start
print("Runtime =", end)
e15()
This problem can be solved in O(1) time by using the code below:
from math import factorial as f
n, m = map(int, input("Enter dimensions (separate by space)?").split())
print ("Routes through a", n, "x", m, "grid", f(n+m) // f(n) // f(m))
Here's a link for a proof of the equation:
Project Euler Problem 15 Solution

How to define codependent functions in Python?

I need to plot the position of a particle at time t, given the following formulae: s(t) = -0.5*g(s)*t^2+v0*t, where g(s) = G*M/(R+s(t))^2 (G, M, and R are constants, s being a value, not the function s(t)). The particle is being shot up vertically, and I want to print its current position every second until it hits the ground. But I can't figure out how to define one function without using the other before it's defined. This is my code so far:
G = 6.6742*10^(-11)
M = 5.9736*10^24
R = 6371000
s0 = 0
v0 = 300
t = 0
dt = 0.005
def g(s):
def s(t):
s(t) = -0.5*g(s)*t^2+v0*t
g(s) = G*M/(R+s(t))^2
def v(t):
v(t) = v(t-dt)-g(s(t-dt))*dt
while s(t) >= 0:
s(t) = s(t-dt)+v(t)*dt
t = t+dt
if t == int(t):
print s(t)
When I run the function, it says that it can't assign the function call.
The error means that you can't write s(t) = x, because s(t) is a function, and assignment on functions is performed with def .... Instead, you'll want to return the value, so you'd rewrite it like this:
def g(s):
def s(t):
return -0.5*g(s)*t^2+v0*t
return G*M/(R+s(t))^2
However, there are other issues with that as well. From a computational standpoint, this calculation would never terminate. Python is not an algebra system and can't solve for certain values. If you try to call s(t) within g(s), and g(s) within s(t), you'd never terminate, unless you define a termination condition. Otherwise they'll keep calling each other, until the recursion stack is filled up and then throws an error.
Also, since you defined s(t) within g(s), you can't call it from the outside, as you do several times further down in your code.
You seem to be confused about several syntax and semantic specifics of Python. If you ask us for what exactly you'd like to do and provide us with the mathematical formulae for it, it might be easier to formulate an answer that may help you better.
Edit:
To determine the position of a particle at time t, you'll want the following code (reformatted your code to Python syntax, use ** instead of ^ and return statements):
G = 6.6742*10**(-11)
M = 5.9736*10**24
R = 6371000
s0 = 0
v0 = 300
t = 0
dt = 0.005
sc = s0 # Current position of the particle, initially at s0
def g(s):
return -G*M/(R+s)**2
def s(t):
return 0.5*g(sc)*t**2 + v0*t + s0
count = 0
while s(t) >= 0:
if count % 200 == 0:
print(sc)
sc = s(t)
count += 1
t = dt*count
Python functions can call each other, but that's not how a function returns a value. To make a function return a particular value, use return, e.g.,
def v(t):
return v(t - dt) - g(s(t - dt)) * dt
Furthermore, I don't really understand what you're trying to do with this, but you'll probably need to express yourself differently:
while s(t) >= 0:
s(t) = s(t-dt)+v(t)*dt
t = t+dt

Categories

Resources