I have two equations f1(b,bb) = 0 and f2(b,bb) = 0 defined in the following code. I am trying to find the set of (b,bb) that satisfy both.
import sympy as sp
from sympy import symbols, simplify, factor
a, b, aa, bb, q, l, h = symbols('a b aa bb q l h')
pb = l*q+h*(1-q)
pb0 = (l*(1-l)*q+h*(1-h)*(1-q))/((1-l)*q+(1-h)*(1-q))
pb1 = (l**2*q+h**2*(1-q))/(l*q+h*(1-q))
a = b*bb/(2*b*bb*l**2 - 3*b*bb*l + b*bb - 2*b*l**2 + 2*b*l - 2*bb*l**2 + 2*bb*l + 2*l**2 - 2)
aa = 2/(l*(2*b*bb*l - b*bb - 2*b*l - 2*bb*l + 2*l + 2))
f1 = 1/pb*((1+(1-aa)/(2*aa*pb1))*q*l*b - (1-(1-aa)/(2*aa*pb1))*(1-q)*h*bb) - 1
f2 = 1/(1-pb)*(1+(1-a)/(2*a*pb0))*(q*(1-l)*b+(1-q)*(1-h)*bb) - 1
sp.solvers.solve((f1,f2), (b,bb))
The solver is taking a prohibitively long time (no solution yet).
I believe the above system is bilinear.
Are there any tricks to speed things up, i.e., python packages that exploit the bilinear structure? Maybe an alternate solver that is more efficient? I am hoping that I don't have to resort to a numerical solution.
If you solve f1 for b and substitute it into f2 you end up with an expression that has a numerator that is cubic in bb and does not factor. Solving a symbolic cubic is not going to be fast. About the best you can do is identify the coefficients and substitute them into the general solutions of the cubic equation.
>>> gen = Tuple(*solve(A*x**3+B*x**2+C*x+D,x))
>>> bbexpr = f2.subs(b, solve(f1, b)[0])
>>> n = bbexpr.as_numer_denom()[0].expand()
Then for each coefficient, something like this (for the first coeff):
>>> eA = n.coeff(bb**3)
>>> gen = gen.subs(A, eA)
Spoiler alert: it's going to be unwieldy.
Related
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.
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
Why it does not calculate properly?
Correct solution is c=25.672 and b2=10.24.
Here solver returns the input values.
Thanks for help!
from numpy import *
from scipy.optimize import *
#UNITS:
psi = 6895.
ft=0.3048
inch=0.0254
psisqin=psi*sqrt(inch)
#DATA:
K_Ict=1500.*psisqin
K_Icb=1700.*psisqin
sigma_2=6700.*psi
sigma_1=6000.*psi
sigma_3=7200.*psi
hp=105.*ft
P = 6500*psi
def f(p):
b2,c= p
F1 = sqrt(pi*c)*(K_Icb-K_Ict)/2 - ( (sigma_2-sigma_1)*sqrt(c**2-b2**2) - (sigma_3-sigma_1)*sqrt(c**2-(hp-b2)**2) )
F2 = sqrt(pi)*(K_Icb+K_Ict)/(2*sqrt(c)) - ( (sigma_2-sigma_1)*arcsin(b2/c) + (sigma_3-sigma_1)*arcsin((hp-b2)/c) - (sigma_2+sigma_3-2*P)*pi/2 )
return (F1,F2)
b2, c = fsolve(f,(16.002,30))
print b2, c
Not entirely sure why but I think it's because you are leaving one of the roots out of the range, so it just returns the boundaries you gave. The true reason depends on whatever method is using to find the roots. The documentation states:
fsolve is a wrapper around MINPACK’s hybrd and hybrj algorithms.
These algorithms are a bit beyond my expertise but you'll find documentation about them easily. This link is one example.
In any case if you change the boundaries to contain both your roots you should obtain the correct results (within a tolerance):
from numpy import *
from scipy.optimize import *
#UNITS:
psi = 6895.
ft=0.3048
inch=0.0254
psisqin=psi*sqrt(inch)
#DATA:
K_Ict=1500*psisqin
K_Icb=1700*psisqin
sigma_2=6700*psi
sigma_1=6000*psi
sigma_3=7200*psi
hp=105.*ft
P = 6500*psi
def f(p):
b2,c= p
F1 = sqrt(pi*c)*(K_Icb-K_Ict)/2
F1 = sqrt(pi*c)*(K_Icb-K_Ict)/2 - ( (sigma_2-sigma_1)*sqrt(c**2-b2**2) - (sigma_3-sigma_1)*sqrt(c**2-(hp-b2)**2) )
F2 = sqrt(pi)*(K_Icb+K_Ict)/(2*sqrt(c)) - ( (sigma_2-sigma_1)*arcsin(b2/c) + (sigma_3-sigma_1)*arcsin((hp-b2)/c) - (sigma_2+sigma_3-2*P)*pi/2 )
return (F1,F2)
b2, c = fsolve(f,(9.002,30))
print(b2, c)
This results in:
10.2613616029 25.63857432
I'm trying to symbolically solve a polynomial with complex numbers and their conjugates with SymPy. I think I've come a long way, but solve does not give me any solutions although the polynomial is solveable.
from sympy import *
# set up symbols
a, b = symbols("a b", real=True)
t = a+I*b
T = functions.conjugate(t)
# set up polynomial
a1=0.005+I*0.0009
a2=0.9+I*-0.9
a3=0.4+I*0.5
a4=8+I*-80
a5=284+I*-1.5
a6=27100+I*-11500
poly=t**2 * T * a1 + t * T * a2 + t**2 * a3 + T * a4 + t * a5 + a6
# Trying to solve symbolically...
solve([re(poly), im(poly)], a, b)
# Output: []
# Solving numerically works, but only finds one solution...
nsolve((re(poly), im(poly)), (a, b), (0, 0))
# Output: matrix(
# [['-137.962596090596'],
# ['52.6296963395752']])
# verify with two solutions obtained in Maxima
poly.subs({a:-137.9625935162095, b:52.6296992481203}).n()
# Output: 0.000540354631040322 + 0.00054727003909351*I
poly.subs({a:-332.6474382554614+I*-185.9848818313149, b:258.0065640091016+I*-272.3344263478699}).n()
# Output: -6.55448222470652e-12 - 1.41238056784605e-12*I
Any ideas?
One problem could be that your coefficients contain floating point numbers. This often does not work with symbolic software.
Using f=10000*simplify(re(poly)) and g=10000*simplify(im(poly)) and editing the results gives polynomials with integer coefficients. The CAS (Magma in my case) then can produce a triangular representation of the ideal of f and g, which is given as the polynomials
a - 2483798807340123709959247/13545514719183259347425004828125*b^4
+ 66732206412048596386372283/541820588767330373897000193125*b^3
- 3849759933277117021785191063/86691294202772859823520030900*b^2
+ 9245906471290310401430681453/1733825884055457196470400618*b
- 31414499425567273751868164900/866912942027728598235200309,
b^5 - 189465979625/206648369*b^4
+ 330827538698125/826593476*b^3
- 17645868534640625/206648369*b^2
+ 1724106750659765625/206648369*b
- 52548859891484375000/206648369
which tells us that 5 solutions exist. The numerical solutions for the second polynomial are
174.10461010682254746847015187264557067610513554291323564643772
+ 63.402741884833821878468926640811609033267039765104756747285816*i
174.104610106822547468470151872645570676105135542913235646437738
- 63.402741884833821878468926640811609033267039765104756747285804*i
258.006564009101655109715962546854008929462784282347754971379392
+ 272.334426347869856080204881056671278679761260094680345276069337*i
258.006564009101655109715962546854008929462784282347754971379382
- 272.334426347869856080204881056671278679761260094680345276069359*i
52.62969633957523864698147679803879873180829265956656342643376
resulting in exactly one real solution. The numerical result of sympy was correct and complete.
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