Newton’s method on functions that contains matrices using Python - python

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.

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()

Trouble with derivation- how to fix "TypeError: 'Add' object is not callable"

Programming in python with numpy and sympy, and my attempts to use derivatives in my code are falling flat. I frequently get either
"TypeError: 'Add' object is not callable"
and,
"ValueError: First variable cannot be a number: 1".
This is for a program meant to define Newton's Method for solving a root-finding problem. The sample equation I've used is 1/x+log(x)-2. I mention this because I've had a few issues with numpy's log function, as well. I think my problem has to do with the diff I'm using, as I'm not entirely certain how to use it to return an actual value, and the literature I've read on it isn't incredibly helpful.
def newton(p0, f, n, t):
global p
p = 0
for i in range(1, n+1):
p = p0 - f(p0)/diff(f(x),p0)
if abs(p-p0) < t:
return p
p0 = p
i = i + 1
return f"The method failed after {n} iterations. The procedure was unsuccessful."
print(newton(p0=1, f=1/x+log(x)-2, n=10, t=5e-324))
I'm at least expecting a number, but I'm getting the errors I describe above.
there are two problems in your code,
the first is the parameter f in your function should have a 'function' input, which means f=lambda x: 1/x+log(x)-2,
the second is p = p0 - f(p0)/diff(f(x),p0). If I understand correctly, you are expecting the diff function to perform as a derivation function, however, it's not. Maybe you can define your own derivation function:
def df(f, x):
h = 1e-5
return (f(x+h)-f(x))/h
then you can write p = p0 - f(p0)/df(f, p0)
so the whole code can be written as below:
def newton(p0, f, n, t):
global p
p = 0
for i in range(1, n+1):
def df(f, x):
h = 1e-5
return (f(x+h)-f(x))/h
p = p0 - f(p0)/df(f, p0)
if abs(p-p0) < t:
return p
p0 = p
i = i + 1
return f"The method failed after {n} iterations. The procedure was unsuccessful."
print(newton(p0=1, f=lambda x: 1/x+log(x)-2, n=10, t=5e-324))

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.

Writing a function for x * sin(3/x) in python

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

Basics of Simulated Annealing in Python [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have to use simulated annealing for a certain optimization problem. To get a 'feel' of the technique, I wrote a small python code and tried to run it. However, it doesn't seem to be giving satisfactory results.
import random;
import math;
from math import *;
LIMIT=100000;
def update_temperature(T,k):
T1=T/log(k+1);
# print "temp now is " + str(T1);
return T1;
def get_neighbors(i,l):
if(l>1):
if(0<=i and i<l):
if(i==0):
return [1];
if(i==l-1):
return [l-2];
return [i-1,i+1];
return [];
def make_move(x,A,T):
nhbs=get_neighbors(x,len(A));
nhb=nhbs[random.choice(range(0,len(nhbs)))];
delta=A[nhb]-A[x];
if(delta < 0):
return nhb;
else:
r=random.random();
if(r <= (e**(-1*delta)/(T*1.0))):
return nhb;
return x;
def simulated_annealing(A):
l=len(A);
init_pos=random.choice(xrange(0,l));
T=10000**30;
k=1;
x_best=init_pos;
x=x_best;
while(T>0.0000001 ):
x=make_move(x,A,T);
if(A[x] < A[x_best]):
x_best=x;
T=update_temperature(T,k);
k+=1;
return [x,x_best,init_pos];
def isminima_local(p,A):
l=len(A);
if(l==1 and p==0):
return True;
if(l>1):
if(p==0):
if(A[0] <=A[1]):
return True;
if(p==l-1):
if(A[p-1] >=A[p]):
return True;
if(0<=p and p<l and A[p-1]>=A[p] and A[p]<=A[p+1]):
return True;
return False;
def func(x):
F=sin(x);
return F;
def initialize(l):
A=[0]*l;
for i in xrange(0,l):
A[i]=func(i);
return A;
def main():
A=initialize(LIMIT);
local_minima=[];
for i in xrange(0,LIMIT):
if( isminima_local(i,A)):
local_minima.append([i,A[i]]);
sols=simulated_annealing(A);
m,p=A[0],0;
for i in xrange(1,LIMIT):
if(m>A[i]):
m=A[i];
p=i;
print "Global Minima at \n";
print p,m;
print "After annealing\n";
print "Solution is " + str(sols[0]) + " " + str(A[sols[0]]);
print "Best Solution is " + str(sols[1]) + " " + str(A[sols[1]]);
print "Start Solution is " + str(sols[2]) + " " + str(A[sols[2]]);
for i in xrange(0,len(local_minima)):
if([sols[0],A[sols[0]]]==local_minima[i]):
print "Solution in local Minima";
if([sols[1],A[sols[1]]]==local_minima[i]):
print "Best Solution in local Minima";
for i in local_minima:
print i;
main();
I am unable to understand where I am going wrong. Is there something wrong with the implementation or is there something wrong in my understanding about simulated annealing ? Please point out the error..
My rough idea about SA:
Pick a random neighbor
If neighbor improves your condition, move there,
Else, move there with certain probability.
The probability is such that initially bad moves are 'allowed' but they are 'prohibited' later on. Finally you will converge to your solution.
I have found the set of local minima and global minima using brute force. Then I run SA. I was expecting that SA will atleast converge to a local minima but that doesn't seem to be the case always. Also, I am not sure if at every step I choose a neighbor randomly and then try to move or I choose the best neighbor ( even if none of the neighbors improve my condition) and then try to move there.
For the most part, your code seems to work well. The main reason that it's slow to converge is that you only look at the two neighbors on either side of your current point: if you expand your search to include any point in A, or even just a wider neighborhood around your current point, you'll be able to move around the search space much more quickly.
Another trick with simulated annealing is determining how to adjust the temperature. You started with a very high temperature, where basically the optimizer would always move to the neighbor, no matter what the difference in the objective function value between the two points. This kind of random movement doesn't get you to a better point on average. The trick is finding a low enough starting temperature value such that the optimizer will move to better points significantly more often than it moves to worse points, but at the same time having a starting temperature that is high enough to allow the optimizer to explore the search space. As I mentioned in my first point, if the neighborhood that you select points from is too limited, then you'll never be able to properly explore the search space even if you have a good temperature schedule.
Your original code was somewhat hard to read, both because you used a lot of conventions that Python programmers try to avoid (e.g., semicolons at ends of lines), and because you did a few things that programmers in general try to avoid (e.g., using lowercase L as a variable name, which looks very similar to the numeral 1). I rewrote your code to make it both more readable and more Pythonic (with the help of autopep8). Check out the pep8 standard for more information.
In make_move, my rewrite picks one random neighbor from across the whole search space. You can try rewriting it to look in an expanded local neighborhood of the current point, if you're interested in seeing how well that works (something between what you had done above and what I've done here).
import random
import math
LIMIT = 100000
def update_temperature(T, k):
return T - 0.001
def get_neighbors(i, L):
assert L > 1 and i >= 0 and i < L
if i == 0:
return [1]
elif i == L - 1:
return [L - 2]
else:
return [i - 1, i + 1]
def make_move(x, A, T):
# nhbs = get_neighbors(x, len(A))
# nhb = nhbs[random.choice(range(0, len(nhbs)))]
nhb = random.choice(xrange(0, len(A))) # choose from all points
delta = A[nhb] - A[x]
if delta < 0:
return nhb
else:
p = math.exp(-delta / T)
return nhb if random.random() < p else x
def simulated_annealing(A):
L = len(A)
x0 = random.choice(xrange(0, L))
T = 1.
k = 1
x = x0
x_best = x0
while T > 1e-3:
x = make_move(x, A, T)
if(A[x] < A[x_best]):
x_best = x
T = update_temperature(T, k)
k += 1
print "iterations:", k
return x, x_best, x0
def isminima_local(p, A):
return all(A[p] < A[i] for i in get_neighbors(p, len(A)))
def func(x):
return math.sin((2 * math.pi / LIMIT) * x) + 0.001 * random.random()
def initialize(L):
return map(func, xrange(0, L))
def main():
A = initialize(LIMIT)
local_minima = []
for i in xrange(0, LIMIT):
if(isminima_local(i, A)):
local_minima.append([i, A[i]])
x = 0
y = A[x]
for xi, yi in enumerate(A):
if yi < y:
x = xi
y = yi
global_minumum = x
print "number of local minima: %d" % (len(local_minima))
print "global minimum #%d = %0.3f" % (global_minumum, A[global_minumum])
x, x_best, x0 = simulated_annealing(A)
print "Solution is #%d = %0.3f" % (x, A[x])
print "Best solution is #%d = %0.3f" % (x_best, A[x_best])
print "Start solution is #%d = %0.3f" % (x0, A[x0])
main()

Categories

Resources