I am using fsolve function in SciPy to solve certain non linear equation system, and I have noticed that comparing the results with MATLAB's fsolve for the exact input and initial condition I am getting different outcomes. Therefore, I was wondering how I could try to achieve same results with SciPy's fsolve as those in MATLAB.
Currently I have configured fsolve in Matlab like this
options = optimoptions('fsolve','Display','iter-detailed','PlotFcn',#optimplotfirstorderopt);
options.StepTolerance = 1e-14;
%options.OptimalityTolerance = 1e-14
options.FunctionTolerance = 1e-14;
options.MaxIterations = 100000;
options.MaxFunctionEvaluations = 400;
% options.Diagnostics = 'on'
options.Algorithm = 'levenberg-marquardt';%'trust-region'%
fun= #solveTransmissionLineForGAndC;
Whereas I have configure fsolve in SciPy like this
fsolve(self.CandGTransmissionLineDistributedE,[g0,c0],Yin,xtol=1e-14,maxfev= 100000,epsfcn=1e-14)
So, as an example, the output I get from both, MATLAB and SciPy, for same four inputs is
SciPy: [0.0263397261951065,0.0255996001756125,0.0255996001756125,0.0248335970729323]
MATLAB:
[0.036897213114754,0.036897213114754,0.036897213114754,0.036897213114754,0.036897213114754]
How can I select the solver algorithm (or how) in SciPy's fsolve?
EDIT: adding MWE
def WandG(GW,Zin):
G,W = GW # define real variables to be used for the function
R = (G**2)*(Zin.real - 0.1164) +(( 70e-12 * ( W/100 ) )**2)*( 2.9036155068866304e+16*(Zin.real - 0.1164) ) - G
I = (G**2)*( Zin.imag - 18.743998408378143 * (1-W/200) ) + (((W/100)*70e-12)**2)*( 2.9036155068866304e+16*(Zin.imag - 18.743998408378143 * (1-W/200)) ) + 170399985.53071037*(70e-12*(W/100) )
return R,I
sol = optimize.root(WandG, [0.136879496, 47.04],(12.652884410928804+14.632724423763523j), jac=False, method='lm',tol=1e-14)
The solution using Scipy would be
sol.x[0] = 0.0795283512113496 # G
sol.x[1] = 36.53727146377749 # W
Whereas with MATLAB for the same initial conditions, solver and Zin, it returns, which I trust more since it resembles better to the final result of W which is W=50
G = 0.0794
W = 44.5234
Related
I am trying to optimize lambda that maximize Equation to maximize, where Z_A is {|0><0|,|1><1|}, Gamma is {Id_4, |01><01|,|10><10|}, and gamma is [1,0.5,0.5]. I change these quantum object to cp.bmat object using:
Gamma_cp = np.array([cp.bmat([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]),cp.bmat([[0,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,0]]),cp.bmat([[0.5,0,0,-0.5],[0,0.5,-0.5,0],[0,-0.5,0.5,0],[-0.5,0,0,0.5]])])
Z_A_cp = np.array([cp.bmat([[1,0,0,0],[0,1,0,0],[0,0,0,0],[0,0,0,0]]),cp.bmat([[0,0,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,1]])])
Identity4 = cp.bmat([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])
The objective I want to optimize is coded as:
def Theta_total_cvx(Q):
gamma = np.array([1,Q,Q])
l = cp.Variable(shape=len(Gamma_cp))
r = cp.exp(Identity4-sum([l[i]*Gamma_cp[i] for i in range(3)]))
obj = cp.Maximize(-cp.lambda_max(sum(Z_A_cp[i]#r#Z_A_cp[i] for i in range(2))-np.dot(l,gamma)))
constraints = []
results = cp.Problem(obj, constraints)
results.solve(verbose=True)
return results.value/np.log(2) - h(Q)
The problem is python compile the obj using more than 10000 minutes, and still running.
Is there anything wrong with this code?
I'm currently learning how to use FiPy and eventually want to use it to solve some biological problems. I have been trying to implement the following PDE system which describes hyphal growth of fungi:
PDE system
I can implement the system without problems, as long as I ignore that the change of si over time depends on the absolute change of p over space abs(dp/dx) in the fourth equation dsi/dt. Here is my code without abs():
from fipy import *
##### produce mesh
nx= 100.
ny= nx
dx = 1/100
dy = dx
L = nx*dx
mesh = Grid2D(nx=nx,ny=ny,dx=dx,dy=dy)
x,y = mesh.cellCenters
##### parameters
b=1e+7 # branching rate (no. branches * cm^-1 * hyphae * day^-1 * (mol glucose)^-1)
f = 10. # fusion rate (no. fusions in cm * day^-1)
v = 1e+5 # cm * mol^-1 * day^-1
d = 0.5 # day^-1
r = 0. # degradation of hyphae
c1 = 9e+2 # cm * mol^-1 * day^-1
c2 = 1e-7 # mol * cm^-1
c3 = 1e+3 # cm * mol^-1 * day^-1, c1/c3 = 90% efficiency
c4 = 1e-8 # cm^-1
De = 1e-3 # diffusion of external substrate (cm² * s^-1)
Di = 1e-2 # diffusion of internal substrate (cm³ * day^-1)
Da = 0.
##### define state variables:
m = CellVariable(name="m",mesh=mesh,hasOld=True,value=0.)
mi = CellVariable(name="mi",mesh=mesh,hasOld=True,value=0.)
p = CellVariable(name="p",mesh=mesh,hasOld=True,value=0.)
si = CellVariable(name="si",mesh=mesh,hasOld=True,value=0.)
se = CellVariable(name="se",mesh=mesh,hasOld=True,value=0.)
##### differential equations
eqm = (TransientTerm(var=m)== si*v*p - ImplicitSourceTerm(var=m,coeff=d))
eqmi = (TransientTerm(var=mi)==m*d - ImplicitSourceTerm(var=mi,coeff=r))
eqp = (TransientTerm(var=p)== - ConvectionTerm(var=p,coeff=[[v]]*si) + b*si*m - ImplicitSourceTerm(var=p,coeff=f*m))
eqsi = (TransientTerm(var=si)== DiffusionTerm(var=si,coeff=Di*m)- DiffusionTerm(var=p,coeff=Da*m*si) + ImplicitSourceTerm(var=si,coeff=c1*m*se) - ImplicitSourceTerm(var=si,coeff=c2*v*p) - ConvectionTerm(var=p,coeff=[[c4*Da]]*(m*si)))
eqse = (TransientTerm(var=se) == DiffusionTerm(var=se,coeff=De) - ImplicitSourceTerm(var=se,coeff=c3*m*si))
# initial values
m0 = 100.
mi0 = 0.
p0 = 500.
si0 = 1e-5
se0 = 3e-5
r = 3. # radius of initial plug
m.setValue(m0,where=((x>(L/2-(r*dx)))&(x<(L/2+(r*dx)))&(y>(L/2-(r*dy)))&(y<(L/2+(r*dy)))))
mi.setValue(mi0,where=((x>(L/2-(r*dx)))&(x<(L/2+(r*dx)))&(y>(L/2-(r*dy)))&(y<(L/2+(r*dy)))))
p.setValue(p0,where=((x>(L/2-(r*dx)))&(x<(L/2+(r*dx)))&(y>(L/2-(r*dy)))&(y<(L/2+(r*dy)))))
si.setValue(si0,where=((x>(L/2-(r*dx)))&(x<(L/2+(r*dx)))&(y>(L/2-(r*dy)))&(y<(L/2+(r*dy)))))
se.setValue(se0)
# boundary conditions
#----------------
# simulation
eq = eqm & eqmi & eqp & eqsi & eqse
vi = Viewer((m))
from builtins import range
for t in range(100):
m.updateOld()
mi.updateOld()
p.updateOld()
si.updateOld()
se.updateOld()
eq.solve(dt=0.1)
print(t)
vi.plot()
Now, I tried to simply write
eqsi = (TransientTerm(var=si)== DiffusionTerm(var=si,coeff=Di*m)- DiffusionTerm(var=p,coeff=Da*m*si) + ImplicitSourceTerm(var=si,coeff=c1*m*se) - ImplicitSourceTerm(var=si,coeff=c2*v*p) - abs(ConvectionTerm(var=p,coeff=[[c4*Da]]*(m*si))))
which (expectedly) gives out an error: "bad operand type for abs(): 'PowerLawConvectionTerm'"
I tried to work my way around it by adding another CellVariable dpdx:
dpdx= CellVariable(name="dpdx",mesh=mesh,hasOld=True,value=0.)
eqdpdx= (dpdx == ConvectionTerm(var=p,coeff=[[1]]))
eqsi = (TransientTerm(var=si)== DiffusionTerm(var=si,coeff=Di*m)- DiffusionTerm(var=p,coeff=Da*m*si) + ImplicitSourceTerm(var=si,coeff=c1*m*se) - ImplicitSourceTerm(var=si,coeff=c2*v*p) - abs(dpdx)*c4*Da*m*si)
which then gives the error "ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()", which is probably caused by the fact that eqdpdx is not a derivative function?
My question is: Is it possible at all to perform mathematical operations with a ConvectionTerm? Can I somehow express the absolute change of p?
And also, how can I express non derivative function that change over space like eqdpdx (or any dynamic parameters)?
I looked through the FiPy manual and could not find a solution - I am sorry if my question is trivial or has been answered elsewhere.
It's important to understand what FiPy Terms are. They are human-readable expressions of parts of PDEs that can be discretized to linear algebra. If you apply some potentially non-linear function to that linear algebra, then it's not linear algebra anymore. This use is not supported and I'm not sure how it even could be.
Fortunately, you don't need it. dp/dx is not a ConvectionTerm, it's a gradient. I would write this term as
- ImplicitSourceTerm(coeff=c4*Da*m*p.grad.mag, var=si)
As a side note, 1D equations are the Devil's work. They will lead you astray every single time. You can use nabla notation like we do in the manual or you can use Einstein notation, but always keep clear in your head whether your expression is scalar or vector (or tensor or ...).
I am looking to solve a diffusion equation using FiPy and have read some of their documentation, but can't seem to find anything that relates to writing a diffusion term that includes additional terms that are functions of the independent variable (i.e. space). The closest thing that I found was on the FAQ, where they suggest rewriting additional terms as a ConvectionTerm. However, I believe this only applies to the case where the additional terms are functions of the solution variable rather than the independent variable. For example, I am trying to solve a 1D diffusion equation with the following diffusion term (where derivatives are w.r.t. to the independent variable x, and y is the solution variable):
D * sin(x) * Div_x {sin(x) * Grad_x {y}}
I feel that this is a pretty simple expression, but I can't find how to express it in FiPy notation. Any help would be hugely appreciated!
Exact Code:
from fipy import Variable,FaceVariable,CellVariable,Grid1D,ImplicitSourceTerm,TransientTerm,DiffusionTerm,Viewer,ConvectionTerm
from fipy.tools import numerix
D = 1
c0 = 1
ka = 1
r0 = 1
nx = 100
dx = 2*math.pi/100
mesh = Grid1D(nx=nx, dx=dx)
conc = CellVariable(name="concentration", mesh=mesh, value=0.) # This is the "phi" in the docs
valueLeft = c0
valueRight = 0
conc.constrain(valueRight, mesh.facesRight)
conc.constrain(valueLeft, mesh.facesLeft)
timeStepDuration = 0.9 * dx**2 / (2 * D)
steps = 100
show_per_steps = 50
A = 1 / (r0**2 * numerix.sin(mesh.x)[0])
dA = -(numerix.cos(mesh.x)[0])/(r0**2 * numerix.sin(mesh.x)[0]**2)
dsindA = (numerix.cos(mesh.x)[0])**3/(numerix.sin(mesh.x)[0])**2
eqX = TransientTerm() + ImplicitSourceTerm(ka) == DiffusionTerm(D*A*numerix.sin(mesh.x)[0]) - ConvectionTerm(D*dA*numerix.cos(mesh.x)[0])+ D*conc*dsindA
from builtins import range
for step in range(steps):
eqX.solve(var=conc, dt=timeStepDuration)
if __name__ == '__main__' and step % show_per_steps == 0:
viewer = Viewer(vars=(conc), datamin=0., datamax=c0)
viewer.plot()
FiPy allows the terms' coefficients to be functions of space. For example, the following works in FiPy,
from fipy import Grid1D, CellVariable, Viewer
from fipy import TransientTerm, numerix, DiffusionTerm
from fipy import LinearLUSolver
m = Grid1D(nx=100, Lx=numerix.pi / 4.)
v = CellVariable(mesh=m)
v[:] = m.x**2
eqn = TransientTerm() == DiffusionTerm(numerix.sin(m.x))
vi = Viewer(v, colorbar=None)
vi.plot()
solver = LinearLUSolver()
for i in range(10):
eqn.solve(v, dt=0.1, solver=solver)
vi.plot()
print('step', i)
input('stopped')
In the above, the diffusion coefficient is a function of space. The m.x is a CellVariable that holds the cell center positions. numerix is used which enables operations on FiPy variables in the same way as Numpy does for Numpy arrays.
Now, in the above question there is a sin(x) outside of the derivative which is not allowed in FiPy. Everything needs to fit inside of the derivative to work with FiPy. So, we need to rewrite the term so that all the coefficients are inside of the derivative. For any general case, we can write
which allows us to use a diffusion, convection and source to represent the term in FiPy. If f=sin(x) and g=sin(x) then the FiPy code would be
s = numerix.sin(m.cellCenters)
c = numerix.cos(m.cellCenters)
eqn = ... + DiffusionTerm(D * s[0] * s[0]) - ConvectionTerm(D * s * c) + D * y * (c[0] * c[0] - s[0] * s[0])
The ... are included as I don't know the full equation.
Let us assume I have an ODE with x'(t) = f(x) with the respective solution x(t) = ϕ(x(0),t) of a initial condition x(0). Now I intend to calculate numerically the equilibria as a function of their initial condition: eq(x0) := ϕ(x0, ∞). The ODEs are such that these equilibria exist unambiguously for all initial conditions (including eq = ∞).
My poor man's approach would be to integrate the ODE up to a late time and fetch that value (for brevity I do not show the plotting):
import numpy as np
from scipy.integrate import odeint
# ODE
def func(X,t):
return [ X[2]**2 * (X[0] - X[1]),
X[2]**3 * (X[0] + 3 * X[1]),
-X[2]**2]
# Forming a grid
n = 15
x0 = x1 = np.linspace(0,1,n)
x0_,x1_ = np.meshgrid(x0,x1)
eq = np.zeros([n,n,3])
t = np.linspace(0,100,1000)
x2 = 1
for i in range(n):
for j in range(n):
X = odeint(func,[x0_[j,i],x1_[j,i],x2], t)
eq[j,i,:] = X[-1,:]
Naive example above:
The problem with that approach is that you can never be sure if it converged. I know that you can just find the roots of f(x), but this would not yield the equilibria as a function of their initial conditions (You could trace them back, but since this function is not injective, you will not find values for all initial values). I somehow need a ODE solver which integrates until an equilibria is reached (or stops integrating if it goes beyond a limit). Do you have any ideas?
I am looking for a Python Lasso solver that works with complex numbers to use in beamforming problems. The objective function is affine, XW - Y. I believe that there at least one such solver implemented for Matlab,
http://www.cs.ubc.ca/~schmidtm/Software/code.html
I have tried to use scikit-learn MultiTaskLasso, following a suggestion from
Is it possible to use complex numbers as target labels in scikit learn?
The matrix 21 norm in the MultiTaskLasso is the correct way to handle the L1 norm for complex numbers. However, my approach requires some gymnastics to force the solver to follow the rules of complex multiplication. Essentially, I need to minimize the L2 norm of
[Re{X}, Im{X}] * [[Re{W}, Im{W}], [-Im{W}, Re{W}]] - [Re{Y}, Im{Y}]
I attempted to enforce the relationship between the two columns of W by adding another row to the X matrix, [-Im{X}, Re{X}], and the row [-Im{Y}, Re{Y}] to Y. This ideally would equate the cost of a change a value each column of W with the corresponding value in the other column
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import MultiTaskLasso
# experiment specifications
numEl = 20
numLook = 1e2
arrayPosition = np.arange(numEl) * np.pi
thetaLook = np.r_[0 : np.pi : numLook * 1j] - (np.pi / 2)
thetaSource = -0.3758
# Make grid of look vectors
W = np.exp(1j * np.sin(thetaLook)[:,None] * arrayPosition)
data = np.exp(1j * np.sin(thetaSource) * arrayPosition).T
# Bartlet beamformer
bartlet = np.abs(np.dot(W.conj(), data))**2
B_bart = 10 * np.log10(np.abs(bartlet)); B_bart-=np.max(B_bart)
# Lasso setup
X = W.T
XSplit = np.vstack((np.hstack((X.real, X.imag)),\
np.hstack((-X.imag, X.real))))
YSplit = np.hstack((np.vstack((data.real, data.imag)),\
np.vstack((-data.imag, data.real)))).T
lasso_solver = MultiTaskLasso(alpha=0.1)
lasso = lasso_solver.fit(XSplit, YSplit).coef_
# Manipulate result back into complex values
stack1 = np.squeeze(lasso[0,:])
stack1 = np.squeeze(stack1[:numLook] + 1j * stack1[numLook:])
B_lasso = 10 * np.log10(np.abs(stack1) + np.spacing(1)); B_lasso -= np.max(B_lasso)
# stack1 ?= stack2 (Should be exact)
stack2 = np.squeeze(lasso[1,:])
stack2 = np.squeeze(-1j * stack2[:numLook] + stack2[numLook:])
np.testing.assert_almost_equal(stack1, stack2, decimal=1)
# Plot both beamformer results
_ = plt.plot(np.rad2deg(thetaLook), B_bart)
_ = plt.plot(np.rad2deg(thetaLook), B_lasso, 'r.')
_ = plt.ylim(-40,3); plt.ylabel('Beamformer Output, dB')
_ = plt.xlabel('Look Direction, deg')
While this approach seems to work for simple problems like the one above, it fails when the problems get more complicated. I define failure when the relationship between the first and second column of W no longer holds. A simple way to create small divergent behavior in the above example is to substitute a Ridge solver for the MultiTaskLasso.
Does anyone know of a Lasso solver that can solve the complex valued problem with rigorous treatment of complex numbers?