I am trying to use the interpolation method in python (not the built-in one) to get the root of a function given an interval.
I have done the following and don't know where I am going wrong, I have done it with bisection and I though the only difference would be the test point.
x1 and x2 are the two ends of the interval, f is the function and epsilon is the tolerance
def interpolation (x1,x2,f,epsilon):
i = 1
n = 100
while i<n:
m = (f(x2)- f(x1))/(x2-x1)
b = f(x2) - m*(x2)
p = b
print (i,p,f(p))
if f(p) == 0 or b< epsilon:
print ('The root is at ',p,'after',i,'iterations')
break
i+= 1
if f(x1)*f(p) > 0: #Equal signs
x1 = p
else:
x2 = p
Running this with f = sin(x^2) simply returns 100 iterations oscillating as follows:
code
(80, 1.3266674970489443, 0.98214554271216425)
(81, 1.4900968376899661, 0.79633049173817871)
(82, 1.3266674970489443, 0.98214554271216425)
(83, 1.4900968376899661, 0.79633049173817871)
It looks like you are trying to solve this using the secant method. The interpolation method requires three initial values.
I am not quite sure the direction you were going with your code, but I was able to adjust it a bit as following:
i = 1
n = 100
while i<n:
print x1, x2
m = (f(x2)- f(x1))/(x2-x1)
b = f(x2) - m*(x2)
p = -b/m #root for this line
# are we close enough?
if abs(f(p)) < epsilon:
print ('The root is at ',p,'after',i,'iterations')
break
i+= 1
x1 = x2
x2 = p
It solved it in 4 iterations based on my starting positions of 1,2:
1 2
2 1.52648748495
1.52648748495 1.75820676726
1.75820676726 1.7754676477
('The root is at ', 1.7724406948343991, 'after', 4, 'iterations')
In case what you actually want is to solve the problem (instead of developing a solution for exercise), I recommend you to use a ready-made module.
My first choice would be scipy.optimize.bisect() (docs)
This module has other methods, too, like Newton-Raphson, etc.
Related
Need a better way to create a list of numbers, so that the run time is less. Or probably figure out a better approach to my problem.
I'm running a code to create a series of numbers based on 2 formulas. Starting from 1, the formulas create the following numbers. The idea is to return the number n from the list that is created at the end. Even tough the formulas create the same number in some cases, only unique values remain, and the list is sorted to match. I use a while loop to create the list, and I believe that reducing the number of repetitions can help with my problem, but I can't figure out a way to effectively reduce it, without ruining the purpose of my code.
def dbl_linear(n):
x = 1
y = 0
z = 0
i = 0
u = []
u.append(x)
while i <= n:
x = (u)[i]
y = 2 * x + 1
u.append(y)
z = 3 * x + 1
u.append(z)
i = i + 1
u.sort()
uFix = set(u)
uFix = list(uFix)
uFix.sort()
return uFix[n]
print(dbl_linear(50))
These are the expected results. Which I get, but it takes too long.
dbl_linear(10), 22)
dbl_linear(20), 57)
dbl_linear(30), 91)
dbl_linear(50), 175)
Your function can be considerably simplified to:
Code:
def dbl_linear(n):
u = [1]
for i in range(n):
x = u[i]
u.extend((2 * x + 1, 3 * x + 1))
return sorted(set(u))[n]
Test Code:
assert dbl_linear(10) == 22
assert dbl_linear(20) == 57
assert dbl_linear(30) == 91
assert dbl_linear(50) == 175
I have made a simulator using Python for a game called Final Fantasy XII. The purpose of this simulator is to see how much "gil" (in-game currency) you can get from one particular enemy.
This should output around 23000 from our experiance, but what happens with this is, it outputs 24000 usually, but sometimes 29000. Considering it takes 1000 samples, it is impossible for that to be coincident. I think this code has problems with random generator, but I have no idea.
Are there reasons python simulator sometimes goes wrong?
import random
# defining variables, dictionaries and functions here
for t in range (1, test + 1):
for n in range (1, dustia + 1):
c = c + 1 # first, increase the chain counter
r = random.random()
# deciding a thing using "if r < [probability]" here
# ....
# apparently this part caused the problem
r = random.random()
if m == 1 and r < 0.4:
m = 0
elif m == 0 and r < 0.05:
m = 1
r1 = random.random() # RNG for book
r2 = random.random() # RNG for staff
rr1 = random.random() # amount of books
rr2 = random.random() # amount of staff
# deciding another thing using r < [probability] here
#summing up samples and calculating average here
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.
I am trying to revamp a function that uses the Pollard Rho method to factor an integer but my attempt at using memoize has had no improvement in being able to factor a specific number (N=7331117) that this function should be able to facotr.
Before attempt:
import fractions
def pollard_Rho(n):
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
memoize attempt:
def pollard_Rho(n):
class memoize:
def __init__(self, function):
self.function = function
self.memoized = {}
def __call__(self, *args):
try:
return self.memoized[args]
except KeyError:
self.memoized[args] = self.function(*args)
return self.memoized[args]
#memoize
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
Now neither code produces any errors but both codes also do produce any results.
The output of
print pollard_Rho(7331117)
should be (641, 11437) (I know this because of another factorization function I have written) but what actually happens is the code runs through 3 iterations of the while loop and nothing happens afterwards. Does anyone have any suggestions?
Sorry for the vague question, does anyone have any suggestions on improving the the codes ability to factor in general? Maybe by a method more efficient than a recursive function? 7331116 and 7331118 factor perfectly fine and only 7331117 seems to be a tough nut to crack so far using this method.
Its possible I didn't use memoize right because even with looking at at on of stackoverflow examples I don't really understand how to use it. It seems every single instance of it I came across was drastically different.
It seems like your algorithm does not work for some reason. In order to see what is going on I went to wikipedia site of the algorithm and implemented regular version from there and it worked without a problem. Than I replaced my g function with your recursive version and I got following error
File "rho.py", line 25, in f_fun
return 2 if xn == 0 else f_fun(xn - 1) ** 2 + 1
RecursionError: maximum recursion depth exceeded
It seems like you cannot implement this with a regular recursion. I would suggest to convert your recursion to a fold or a generator.
Here is the code I tried:
https://gist.github.com/huseyinyilmaz/73c1ac42b2a20d24d3b5
UPDATE:
Here is your version with cache, it still have maximum depth problem. (python 2 implementation)
https://gist.github.com/huseyinyilmaz/bb26ac172fbec4c655d3
I have to write a function, s(x) = x * sin(3/x) in python that is capable of taking single values or vectors/arrays, but I'm having a little trouble handling the cases when x is zero (or has an element that's zero). This is what I have so far:
def s(x):
result = zeros(size(x))
for a in range(0,size(x)):
if (x[a] == 0):
result[a] = 0
else:
result[a] = float(x[a] * sin(3.0/x[a]))
return result
Which...doesn't work for x = 0. And it's kinda messy. Even worse, I'm unable to use sympy's integrate function on it, or use it in my own simpson/trapezoidal rule code. Any ideas?
When I use integrate() on this function, I get the following error message: "Symbol" object does not support indexing.
This takes about 30 seconds per integrate call:
import sympy as sp
x = sp.Symbol('x')
int2 = sp.integrate(x*sp.sin(3./x),(x,0.000001,2)).evalf(8)
print int2
int1 = sp.integrate(x*sp.sin(3./x),(x,0,2)).evalf(8)
print int1
The results are:
1.0996940
-4.5*Si(zoo) + 8.1682775
Clearly you want to start the integration from a small positive number to avoid the problem at x = 0.
You can also assign x*sin(3./x) to a variable, e.g.:
s = x*sin(3./x)
int1 = sp.integrate(s, (x, 0.00001, 2))
My original answer using scipy to compute the integral:
import scipy.integrate
import math
def s(x):
if abs(x) < 0.00001:
return 0
else:
return x*math.sin(3.0/x)
s_exact = scipy.integrate.quad(s, 0, 2)
print s_exact
See the scipy docs for more integration options.
If you want to use SymPy's integrate, you need a symbolic function. A wrong value at a point doesn't really matter for integration (at least mathematically), so you shouldn't worry about it.
It seems there is a bug in SymPy that gives an answer in terms of zoo at 0, because it isn't using limit correctly. You'll need to compute the limits manually. For example, the integral from 0 to 1:
In [14]: res = integrate(x*sin(3/x), x)
In [15]: ans = limit(res, x, 1) - limit(res, x, 0)
In [16]: ans
Out[16]:
9⋅π 3⋅cos(3) sin(3) 9⋅Si(3)
- ─── + ──────── + ────── + ───────
4 2 2 2
In [17]: ans.evalf()
Out[17]: -0.164075835450162