Using the BFGS method to find roots of few equations - python

I am trying to use the BFGS method to find the roots of these equations.
ax[0]^2 - bx[1]^2
a = 35; b = 25; d = 15
import numpy as np
from scipy import optimize
def f(x):
return a*x[0]^2 - b*x[1]^2
optimize.fmin_bfgs(f,[0.55,0.65])
The output I am getting is,
Warning: Desired error not necessarily achieved due to precision loss.
Current function value: -2791745.308471
Iterations: 3
Function evaluations: 196
Gradient evaluations: 46
array([ 300.41455833, 2439.35586751])
The output is of course not desirable. I want to add two more equations and want the roots x[0], x[1], x[2]. Is it possible in BFGS, if so, how?
The two more equations are like,
b*x[2]^2 - x[1]^2 == 0
d *x[0]x[2](x[2] + x[0]) - x[1]^2 == 0

The BFGS algorithm tries to find a local minimum of the given function, as the method name fmin_bfgs indicates. You can use scipy.optimize.root to find the root of the function F: R^n -> R^n of n variables:
import numpy as np
from scipy.optimize import root
a = 35; b = 25; d = 15
def F(x):
return np.array([a*x[0]**2 - b*x[1]**2, 0])
# res.x contains your root
res = root(F, x0=np.ones(2))
In order to solve a*x[0]**2 - b*x[1]**2 == 0 we added the equation 0 == 0, since root expects 2 equations for a function of 2 variables. When adding your two other equations, we have a function of three variables, i.e:
def F(x):
eq1 = a*x[0]**2 - b*x[1]**2
eq2 = b*x[1]**2 - x[0]**2
eq3 = d*x[0]*x[2]*(x[2] + x[0]) - x[1]**2
return np.array([eq1, eq2, eq3])
# res.x contains your root
res = root(F, x0=np.ones(3))
Note also that in Python, the ^ operator denotes the bitwise XOR. Use x[0]**2 to denote the power of two of x[0].

Related

How to get repeating roots in sympy?

from sympy import Symbol
from sympy.solvers import solveset
x = Symbol('x')
equation = x**2 - 2*x + 1
result = solveset(equation, x)
Here, result evaluates to FiniteSet(1).
Since this is a quadratic equation, there must be 2 roots.
But also, since the two roots are the same (1 in this case), the result returns it only once.
For the purpose of solving linear recurrences, I need to know the repeated roots, and how many times did each one of them repeat.
How to do that?
You can convert it into a polynomial and then use the roots function, which will return a dictionary that has the roots as keys and the multiplicities as values, like so:
from sympy import roots
poly = equation.as_poly()
roots(poly)
# returns {1: 2}
Unlike nroots, this works with polynomials with symbolic coefficients as well:
from sympy.abc import a, b, c
poly = (a * x ** 2 - 2 * sqrt(a * c) * x + c).as_poly(x)
roots(poly, x)
# returns {sqrt(a*c)/a: 2}

I am newbie in python and doing coding for my physics project which requires to generate a matrix with a variable E

I am newbie in python and doing coding for my physics project which requires to generate a matrix with a variable E for which first element of the matrix has to be solved. Please help me. Thanks in advance.
Here is the part of code
import numpy as np
import pylab as pl
import math
import cmath
import sympy as sy
from scipy.optimize import fsolve
#Constants(Values at temp 10K)
hbar = 1.055E-34
m0=9.1095E-31 #free mass of electron
q= 1.602E-19
v = [0.510,0,0.510] # conduction band offset in eV
m1= 0.043 #effective mass in In_0.53Ga_0.47As
m2 = 0.072 #effective mass in Al_0.48In_0.52As
d = [-math.inf,100,math.inf] # dimension of structure in nanometers
'''scaling factor to with units of E in eV, mass in terms of free mass of electron, length in terms
of nanometers '''
s = (2*q*m0*1E-18)/(hbar)**2
#print('scaling factor is ',s)
E = sy.symbols('E') #Suppose energy of incoming particle is 0.3eV
m = [0.043,0.072,0.043] #effective mass of electrons in layers
for i in range(3):
print ('Effective mass of e in layer', i ,'is', m[i])
k=[ ] #Defining an array for wavevectors in different layers
for i in range(3):
k.append(sy.sqrt(s*m[i]*(E-v[i])))
print('Wave vector in layer',i,'is',k[i])
x = []
for i in range(2):
x.append((k[i+1]*m[i])/(k[i]*m[i+1]))
# print(x[i])
#Define Boundary condition matrix for two interfaces.
D0 = (1/2)*sy.Matrix([[1+x[0],1-x[0]], [1-x[0], 1+x[0]]], dtype = complex)
#print(D0)
#A = sy.matrix2numpy(D0,dtype=complex)
D1 = (1/2)*sy.Matrix([[1+x[1],1-x[1]], [1-x[1], 1+x[1]]], dtype = complex)
#print(D1)
#a=eye(3,3)
#print(a)
#Define Propagation matrix for 2nd layer or quantum well
#print(d[1])
#print(k[1])
P1 = 1*sy.Matrix([[sy.exp(-1j*k[1]*d[1]), 0],[0, sy.exp(1j*k[1]*d[1])]], dtype = complex)
#print(P1)
print("abs")
T= D0*P1*D1
#print('Transfer Matrix is given by:',T)
#print('Dimension of tranfer matrix T is' ,T.shape)
#print(T[0,0]
# I want to solve T{0,0} = 0 equation for E
def f(x):
return T[0,0]
x0= 0.5 #intial guess
x = fsolve(f, x0)
print("E is",x)
'''
y=sy.Eq(T[0,0],0)
z=sy.solve(y,E)
print('z',z)
'''
**The main part i guess is the part of the code where i am trying to solve the equation.***Steps I am following:
Defining a symbol E by using sympy
Generating three matrices which involves sum formulae and with variable E
Generating a matrix T my multiplying those 3 matrices,note that elements are complex and involves square roots of negative number.
I need to solve first element of this matrix T[0,0]=0,for variable E and find out value of E. I used fsolve for soving T[0,0]=0.*
Just a note for future questions, please leave out unused imports such as numpy and leave out zombie code like # a = eye(3,3). This helps keep the code as clean and short as possible. Also, the sample code would not run because of indentation problems, so when you copy and paste code, make sure it works before you do so. Always try to make your questions as short and modular as possible.
The expression of T[0,0] is too complex to solve analytically by SymPy so numerical approximation is needed. This leaves 2 options:
using SciPy's solvers which are advanced but require type casting to float values since SciPy does not deal with SymPy objects in any way.
using SymPy's root solvers which are less advanced but are probably simpler to use.
Both of these will only ever produce a single number as output since you can't expect numeric solvers to find every root. If you wanted to find more than one, then I advise that you use a list of points that you want to use as initial values, input each of them into the solvers and keep track of the distinct outputs. This will however never guarantee that you have obtained every root.
Only mix SciPy and SymPy if you are comfortable using both with no problems. SciPy doesn't play at all with SymPy and you should only have list, float, and complex instances when working with SciPy.
import math
import sympy as sy
from scipy.optimize import newton
# Constants(Values at temp 10K)
hbar = 1.055E-34
m0 = 9.1095E-31 # free mass of electron
q = 1.602E-19
v = [0.510, 0, 0.510] # conduction band offset in eV
m1 = 0.043 # effective mass in In_0.53Ga_0.47As
m2 = 0.072 # effective mass in Al_0.48In_0.52As
d = [-math.inf, 100, math.inf] # dimension of structure in nanometers
'''scaling factor to with units of E in eV, mass in terms of free mass of electron, length in terms
of nanometers '''
s = (2 * q * m0 * 1E-18) / hbar ** 2
E = sy.symbols('E') # Suppose energy of incoming particle is 0.3eV
m = [0.043, 0.072, 0.043] # effective mass of electrons in layers
for i in range(3):
print('Effective mass of e in layer', i, 'is', m[i])
k = [] # Defining an array for wavevectors in different layers
for i in range(3):
k.append(sy.sqrt(s * m[i] * (E - v[i])))
print('Wave vector in layer', i, 'is', k[i])
x = []
for i in range(2):
x.append((k[i + 1] * m[i]) / (k[i] * m[i + 1]))
# Define Boundary condition matrix for two interfaces.
D0 = (1 / 2) * sy.Matrix([[1 + x[0], 1 - x[0]], [1 - x[0], 1 + x[0]]], dtype=complex)
D1 = (1 / 2) * sy.Matrix([[1 + x[1], 1 - x[1]], [1 - x[1], 1 + x[1]]], dtype=complex)
# Define Propagation matrix for 2nd layer or quantum well
P1 = 1 * sy.Matrix([[sy.exp(-1j * k[1] * d[1]), 0], [0, sy.exp(1j * k[1] * d[1])]], dtype=complex)
print("abs")
T = D0 * P1 * D1
# did not converge for 0.5
x0 = 0.75
# method 1:
def f(e):
# evaluate T[0,0] at e and remove all sympy related things.
result = complex(T[0, 0].replace(E, e))
return result
solution1 = newton(f, x0)
print(solution1)
# method 2:
solution2 = sy.nsolve(T[0,0], E, x0)
print(solution2)
This prints:
(0.7533104353644469-0.023775286117722193j)
1.00808496181754 - 0.0444042144405285*I
Note that the first line is a native Python complex instance while the second is an instance of SymPy's complex number. One can convert the second simply with print(complex(solution2)).
Now, you'll notice that they produce different numbers but both are correct. This function seems to have a lot of zeros as can be shown from the Geogebra plot:
The red axis is Re(E), green is Im(E) and blue is |T[0,0]|. Each of those "spikes" are probably zeros.

Find root of monotone function: newton fails

I have a function of the shape $$f(x) = \sum_i a_i \cdot x^{e_i} - c$$, where all parameters are positive.
Now I want to (numerically) compute a root of this function.
f is monotone
$$f(0) = -c$$
so the root must be positive
I thought to apply Newton's method/secant method, as in scipy.optimize.newton, but sometimes it fails.
#secant method
f1 = (lambda a: 6.75304970913061 * a**2.37142857142857 - 1.91006495309903)
scipy.optimize.newton(f1,0)
fails to converge in 50 steps and after 100, or 1000 iterations the result gets even worse (which should not happen).
Alternatively, I can compute
#Newton
f2 = (lambda a: 0.672716686237341 * a **0.0624999999999993 + 0.87283444645141 * a ** 0.134615384615384 - 1.34775906114245)
f2prime = (lambda a: 0.0420447928898333 * a ** -0.937500000000001 + 0.117496944714613 * a ** -0.865384615384615)
scipy.optimize.newton(f2,1,fprime = f2prime)
Since I have negative powers, I start at 1, but then I get Failed to converge after 50 iterations, value is (2.9502746750095213e+29-7.147769018388161e+29j).
What do I have to call, to solve each instance of the above type?
The SciPy documentation of scipy.optimize.newton recommends using scipy.optimize.brentq for intervals [a,b] where the function changes sign. For monotone functions such as described, a=0 and b can be found by trying large enough numbers.
import scipy.optimize
f1 = (lambda a: 6.75304970913061 * a**2.37142857142857 - 1.91006495309903)
f1(0) # -1.91006495309903
f1(1) # 4.84298475603158
scipy.optimize.brentq(f1,0.,1.) # 0.5871176550428887
f2 = (lambda a: 0.672716686237341 * a **0.0624999999999993 + 0.87283444645141 * a ** 0.134615384615384 - 1.34775906114245)
f2(0) # -1.34775906114245
f2(1) # 0.19779207154630107
scipy.optimize.brentq(f2,0.,1.) # 0.2624501197238087

Solving Non-Linear Differential Equation Sympy

This code only works for solving the differential equation v_equation if v(t) isn't squared. When I squared it it returned the error PolynomialDivisionFailed. Is there another way of doing this with Sympy or should I find a different python package for doing these sorts of calculations.
from sympy import *
from matplotlib import pyplot as plt
import numpy as np
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f1 = g * m
t = Symbol('t')
v = Function('v')
v_equation = dsolve(f1 - k * (v(t) ** 2) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(v_equation.rhs.subs({t:0}),C1)[0]
v_equation = v_equation.subs({C1:C1_ic})
func = lambdify(t, v_equation.rhs,'numpy')
From my experience with symbolic math packages, I would not recommend performing (symbolic) calculations using floating point constants. It is better to define equations using symbolic constants, perform calculations as far as possible, and then substitute with numerical values.
With this approach, Sympy can provide a solution for this D.E.
First, define symbolic constants. To aid calculations, note that we can provide additional information about these constants (e.g., real, positive, e.t.c)
import sympy as sp
t = sp.symbols('t', real = True)
g, k, m = sp.symbols('g, k, m', real = True, positive = True)
v = sp.Function('v')
The symbolic solution for the DE can be obtained as follows
f1 = g * m
eq = f1 - k * (v(t) ** 2) - m * sp.Derivative(v(t))
sol = sp.dsolve(eq,v(t)).simplify()
The solution sol will be a function of k, m, g, and a constant C1. In general, there will be two, complex C1 values corresponding to the initial condition. However, both values of C1 result in the same (real-valued) solution when substituted in sol.
Note that if you don't need a symbolic solution, a numerical ODE solver, such as Scipy's odeint, may be used. The code would be the following (for an initial condition 0):
from scipy.integrate import odeint
def fun(v, t, m, k, g):
return (g*m - k*v**2)/m
tn = np.linspace(0, 10, 101)
soln = odeint(fun, 0, tn, args=(1000, 0.2, 9.8))
soln is an array of samples v(t) corresponding to the tn elements

numpy.poly1d , root-finding optimization, shifting polynom on x-axis

it is commonly an easy task to build an n-th order polynomial
and find the roots with numpy:
import numpy
f = numpy.poly1d([1,2,3])
print numpy.roots(f)
array([-1.+1.41421356j, -1.-1.41421356j])
However, suppose you want a polynomial of type:
f(x) = a*(x-x0)**0 + b(x-x0)**1 + ... + n(x-x0)**n
Is there a simple way to construct a numpy.poly1d type function
and find the roots ? I've tried scipy.fsolve but it is very unstable as it depends highly on the choice of the starting values
in my particular case.
Thanks in advance
Best Regards
rrrak
EDIT: Changed "polygon"(wrong) to "polynomial"(correct)
First of all, surely you mean polynomial, not polygon?
In terms of providing an answer, are you using the same value of "x0" in all the terms? If so, let y = x - x0, solve for y and get x using x = y + x0.
You could even wrap it in a lambda function if you want. Say, you want to represent
f(x) = 1 + 3(x-1) + (x-1)**2
Then,
>>> g = numpy.poly1d([1,3,1])
>>> f = lambda x:g(x-1)
>>> f(0.0)
-1.0
The roots of f are given by:
f.roots = numpy.roots(g) + 1
In case x0 are different by power, such as:
f(x) = 3*(x-0)**0 + 2*(x-2)**1 + 3*(x-1)**2 + 2*(x-2)**3
You can use polynomial operation to calculate the finally expanded polynomial:
import numpy as np
import operator
ks = [3,2,3,2]
offsets = [0,2,1,2]
p = reduce(operator.add, [np.poly1d([1, -x0])**i * c for i, (c, x0) in enumerate(zip(ks, offsets))])
print p
The result is:
3 2
2 x - 9 x + 20 x - 14

Categories

Resources