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.
Related
I was able to find several implementations of Newton's methods, for example, this link or maybe this one.
However, most of the time the examples are with simple functions such as:
x^2−9=0 or x^3-x^2-1=0. I am looking for something that would work for:
My question for that I am lost in how to use this code to solve my problem. For example, I am not sure how I would apply the derivative (dfdx) on my F(x) that contain matrices. Also, if I should direct input the matrices on my "def f(x)"
The code that I am using:
def Newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
except ZeroDivisionError:
print "Error! - derivative zero for x = ", x
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(f_value) > eps:
iteration_counter = -1
return x, iteration_counter
def f(x):
return x**2 - 9
def dfdx(x):
return 2*x
solution, no_iterations = Newton(f, dfdx, x=1000, eps=1.0e-6)
if no_iterations > 0: # Solution found
print "Number of function calls: %d" % (1 + 2*no_iterations)
print "A solution is: %f" % (solution)
else:
print "Solution not found!"
There aren't any special rules for deriving matrices - the derivative is just calculated for each element separately. I would suggest evaluating the $[x1,x2]' * M * [x1,x2]$ expression on paper to get a matrix of polynomials, and then calculating the derivative of each one.
[This image here is my python code for the Newton-Raphson method. The problem is with the mathematical function and the derivative. At the moment I am the one who specifies the function and its derivative. Is there any way to get the user to input the function that he/she desires?
import math
""" f: function, f_ : derivative of function, x0: initial guess, errortolerance: tolerance, maxIter: max number of iterations """
def newtonraphson(f, f_, x0, errortolerance=0.00001, maxIter=100):
"""
Take a function f, its derivative f_, initial value x0, TOL and NMAX,
and returns the root(s) of the equation using the NR method
"""
n = 1 #initial numebr of iterations
while n<=maxIter: # check while n less than maxIter
x1 = x0 - (f(x0)/f_(x0)) #newtonraphson formula
if x1 - x0 < errortolerance:
return x1
else:
x0 = x1
return False
if __name__ == "__main__":
def func(x): #initial function
return 5*math.pow(x,2) - 8*math.pow(x,1) + 4
def func_(x): #its derivative
return 10*math.pow(x,1) - 8
resNR = newtonraphson(func,func_,3) #result of newtonraphson
print(resNR)
You can use lambda and eval to let the user input the function and its derivative. I assume you are using Python 3. If you are using Python 2, replace input with raw_input.
if __name__ == '__main__':
f = lambda x : eval(input())
f_ = lambda x : eval(input())
print(newtonraphson(f, f_, 3))
Now, have your user enter an expression in x. Remember, only the already defined names are allowed in the input.
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
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
I was wondering if there was a function built into Python that can determine the distance between two rational numbers but without me telling it which number is larger.
e.g.
>>>distance(6,3)
3
>>>distance(3,6)
3
Obviously I could write a simple definition to calculate which is larger and then just do a simple subtraction:
def distance(x, y):
if x >= y:
result = x - y
else:
result = y - x
return result
but I'd rather not have to call a custom function like this.
From my limited experience I've often found Python has a built in function or a module that does exactly what you want and quicker than your code does it. Hopefully someone can tell me there is a built in function that can do this.
abs(x-y) will do exactly what you're looking for:
In [1]: abs(1-2)
Out[1]: 1
In [2]: abs(2-1)
Out[2]: 1
Although abs(x - y) and equivalently abs(y - x) work, the following one-liners also work:
math.dist((x,), (y,)) (available in Python ≥3.8)
math.fabs(x - y)
max(x - y, y - x)
-min(x - y, y - x)
max(x, y) - min(x, y)
(x - y) * math.copysign(1, x - y), or equivalently (d := x - y) * math.copysign(1, d) in Python ≥3.8
functools.reduce(operator.sub, sorted([x, y], reverse=True))
All of these return the euclidean distance(x, y).
Just use abs(x - y). This'll return the net difference between the two as a positive value, regardless of which value is larger.
If you have an array, you can also use numpy.diff:
import numpy as np
a = [1,5,6,8]
np.diff(a)
Out: array([4, 1, 2])
So simple just use abs((a) - (b)).
will work seamless without any additional care in signs(positive , negative)
def get_distance(p1,p2):
return abs((p1) - (p2))
get_distance(0,2)
2
get_distance(0,2)
2
get_distance(-2,0)
2
get_distance(2,-1)
3
get_distance(-2,-1)
1
use this function.
its the same convention you wanted.
using the simple abs feature of python.
also - sometimes the answers are so simple we miss them, its okay :)
>>> def distance(x,y):
return abs(x-y)
This does not address the original question, but I thought I would expand on the answer zinturs gave. If you would like to determine the appropriately-signed distance between any two numbers, you could use a custom function like this:
import math
def distance(a, b):
if (a == b):
return 0
elif (a < 0) and (b < 0) or (a > 0) and (b > 0):
if (a < b):
return (abs(abs(a) - abs(b)))
else:
return -(abs(abs(a) - abs(b)))
else:
return math.copysign((abs(a) + abs(b)),b)
print(distance(3,-5)) # -8
print(distance(-3,5)) # 8
print(distance(-3,-5)) # 2
print(distance(5,3)) # -2
print(distance(5,5)) # 0
print(distance(-5,3)) # 8
print(distance(5,-3)) # -8
Please share simpler or more pythonic approaches, if you have one.
If you plan to use the signed distance calculation snippet posted by phi (like I did) and your b might have value 0, you probably want to fix the code as described below:
import math
def distance(a, b):
if (a == b):
return 0
elif (a < 0) and (b < 0) or (a > 0) and (b >= 0): # fix: b >= 0 to cover case b == 0
if (a < b):
return (abs(abs(a) - abs(b)))
else:
return -(abs(abs(a) - abs(b)))
else:
return math.copysign((abs(a) + abs(b)),b)
The original snippet does not work correctly regarding sign when a > 0 and b == 0.
abs function is definitely not what you need as it is not calculating the distance. Try abs (-25+15) to see that it's not working. A distance between the numbers is 40 but the output will be 10. Because it's doing the math and then removing "minus" in front. I am using this custom function:
def distance(a, b):
if (a < 0) and (b < 0) or (a > 0) and (b > 0):
return abs( abs(a) - abs(b) )
if (a < 0) and (b > 0) or (a > 0) and (b < 0):
return abs( abs(a) + abs(b) )
print distance(-25, -15)
print distance(25, -15)
print distance(-25, 15)
print distance(25, 15)
You can try:
a=[0,1,2,3,4,5,6,7,8,9];
[abs(x[1]-x[0]) for x in zip(a[1:],a[:-1])]