This link indicates that the analogue of Matlab's lsqnonlin is LsqFit.jl in Julia. However, matlab uses the notation
x = lsqnonlin(fun,x0)
But Julia uses notation
fit = curve_fit(model, xdata, ydata, p0)
So what is the analogue of the x in Matlab notation, if I'm using LsqFit in Julia? In Julia command
fieldnames(fit)
Gives
5-element Array{Symbol,1}:
:dof
:param
:resid
:jacobian
:converged
where converged is a boolean type, and fit.param corresponds to the parameters vector p.
So where is the independent variable x?Want to solve for x in F(x)=0 where x and F are column vectors and F is a nonlinear function.
fit = curve_fit(model, xdata, ydata, p0)
is more akin to a call like
[x,resnorm,residual,exitflag,output,lambda,jacobian] = lsqnonlin(___)
in Matlab. The resulting fit object contains some similar solver metadata:
# fit is a composite type (LsqFitResult), with some interesting values:
# fit.dof: degrees of freedom
# fit.param: best fit parameters
# fit.resid: residuals = vector of residuals
# fit.jacobian: estimated Jacobian at solution
So, fit.param should be the same as x.
Here is an MWE demonstrating the proper usage for finding y(x) that minimizes squares for function F(y(x)) = 0. It is modified in that the p0 "parameters" are now actually the y-values. The x-values are meant to be the underlying grid (so notation F(x)=0 is not correct for curve_fit), and it should be that we are solving F(y(x))=0 as follows.
using LsqFit
using PyPlot
# example model, could be nlin function or diff eq
# we will solve DE y' - y with init conds y'(0) = 1
# by using function F(y) = y' - y as follows
F(xs, ys) = [1; diff(ys)/xs[2];] - ys; # column vector
# note: function F above assumes xs[1] = 0 so that xs[2] = dx
# xs: independent variables, these values never change
dx = 0.02; # make smaller to get more accurate
xs = [0:dx:2;]; # column vector
len = length(xs);
# ys: initial guess for solution function y(x), will be optimized
ys = exp(xs)+rand(len,1)-0.5; # column vector
# modified usage for sum of squares to minimize F
fit = curve_fit(F,xs,0.0*xs[:],ys[:])
# note: original usage was
# fit = curve_fit(model, xdata, ydata, p0)
figure(1)
scatter(xs,ys,marker = "o") # initial noisy guess in blue
plot(xs,fit.param,color = "red") # optimized solution in red
plot(xs,exp(xs),linestyle = "--",color = "green") # exact sol
axis("tight")
display("sum of squares")
sum(abs(F(xs,fit.param)).^2)
In Julia I used the package LeastSquaresOptim to replace Matlab's lsqnonlin function and find the best (three) parameters abc for a custom cost-function:
using LeastSquaresOptim
# create closure to fun since we need more args in cost-function
function fun(abc) myCostFunction(abc, otherArg1, otherArg2, otherArg3) end
p0 = [0.0, 0.0, 0.0] # mind the float values for starting point!
p = optimize(fun, p0, LevenbergMarquardt())
a = p.minimizer[1]
b = p.minimizer[2]
c = p.minimizer[3]
Related
I have written a function that, given parameters, can apply a piecewise linear fit, with arbitrarily many piecewise sections, to some data.
I am trying to fit the function to my data using scipy.optimize.curve_fit, but I am receiving an "OptimizeWarning: Covariance of the parameters could not be estimated" error. I believe this may be because of the nested lambda functions I am using to define the piecewise sections.
Is there an easy way to tweak my code to get round this, or a different scipy optimisation function that might be more suitable?
#The piecewise function
def piecewise_linear(x, *params):
N=len(params)/2
if N.is_integer():N=int(N)
else:raise(ValueError())
c=params[0]
xbounds=params[1:N]
grads=params[N:]
#First we define our conditions, which are true if x is a member of a given
#bin.
conditions=[]
#first and last bins are a special case:
cond0=lambda x: x<xbounds[0]
condl=lambda x: x>=xbounds[-1]
conditions.append(cond0(x))
for i in range(len(xbounds)-1):
cond=lambda x : (x >= xbounds[i]) & (x < xbounds[i+1])
conditions.append(cond(x))
conditions.append(condl(x))
#Next we define our linear regression function for each bin. The offset
#for each bin depends on where the previous bin ends, so we define
#the regression functions recursively:
functions=[]
func0 = lambda x: grads[0]*x +c
functions.append(func0)
for i in range(len(grads)-1):
func = (lambda j: lambda x: grads[j+1]*(x-xbounds[j])\
+functions[j](xbounds[j]))(i)
functions.append(func)
return np.piecewise(x,conditions,functions)
#Some data
x=np.arange(100)
y=np.array([*np.arange(0,19,1),*np.arange(20,59,2),\
*np.arange(60,20,-1),*np.arange(21,42,1)]) + np.random.randn(100)
#A first guess of parameters
cguess=0
boundguess=[20,30,50]
gradguess=[1,1,1,1]
p0=[cguess,*boundguess,*gradguess]
fit=scipy.optimize.curve_fit(piecewise_linear,x,y,p0=p0)
Here is example code that fits two straight lines to a curved data set with a breakpoint, where the line parameters and breakpoint are all fitted. This example uses scipy's Differential Evolution genetic algorithm to determine initial parameter estimates for the regression. That module uses the Latin Hypercube algorithm to ensure a thorough search of parameter space, which requires bounds within which to search. In this example those search bounds are derived from the data itself. Note that it is much easier to find ranges for the initial parameter estimates than to give specific values.
import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.optimize import differential_evolution
import warnings
xData = numpy.array([19.1647, 18.0189, 16.9550, 15.7683, 14.7044, 13.6269, 12.6040, 11.4309, 10.2987, 9.23465, 8.18440, 7.89789, 7.62498, 7.36571, 7.01106, 6.71094, 6.46548, 6.27436, 6.16543, 6.05569, 5.91904, 5.78247, 5.53661, 4.85425, 4.29468, 3.74888, 3.16206, 2.58882, 1.93371, 1.52426, 1.14211, 0.719035, 0.377708, 0.0226971, -0.223181, -0.537231, -0.878491, -1.27484, -1.45266, -1.57583, -1.61717])
yData = numpy.array([0.644557, 0.641059, 0.637555, 0.634059, 0.634135, 0.631825, 0.631899, 0.627209, 0.622516, 0.617818, 0.616103, 0.613736, 0.610175, 0.606613, 0.605445, 0.603676, 0.604887, 0.600127, 0.604909, 0.588207, 0.581056, 0.576292, 0.566761, 0.555472, 0.545367, 0.538842, 0.529336, 0.518635, 0.506747, 0.499018, 0.491885, 0.484754, 0.475230, 0.464514, 0.454387, 0.444861, 0.437128, 0.415076, 0.401363, 0.390034, 0.378698])
def func(xArray, breakpoint, slopeA, offsetA, slopeB, offsetB):
returnArray = []
for x in xArray:
if x < breakpoint:
returnArray.append(slopeA * x + offsetA)
else:
returnArray.append(slopeB * x + offsetB)
return returnArray
# function for genetic algorithm to minimize (sum of squared error)
def sumOfSquaredError(parameterTuple):
warnings.filterwarnings("ignore") # do not print warnings by genetic algorithm
val = func(xData, *parameterTuple)
return numpy.sum((yData - val) ** 2.0)
def generate_Initial_Parameters():
# min and max used for bounds
maxX = max(xData)
minX = min(xData)
maxY = max(yData)
minY = min(yData)
slope = 10.0 * (maxY - minY) / (maxX - minX) # times 10 for safety margin
parameterBounds = []
parameterBounds.append([minX, maxX]) # search bounds for breakpoint
parameterBounds.append([-slope, slope]) # search bounds for slopeA
parameterBounds.append([minY, maxY]) # search bounds for offsetA
parameterBounds.append([-slope, slope]) # search bounds for slopeB
parameterBounds.append([minY, maxY]) # search bounds for offsetB
result = differential_evolution(sumOfSquaredError, parameterBounds, seed=3)
return result.x
# by default, differential_evolution completes by calling curve_fit() using parameter bounds
geneticParameters = generate_Initial_Parameters()
# call curve_fit without passing bounds from genetic algorithm
fittedParameters, pcov = curve_fit(func, xData, yData, geneticParameters)
print('Parameters:', fittedParameters)
print()
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
print()
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
print()
##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
# first the raw data as a scatter plot
axes.plot(xData, yData, 'D')
# create data for the fitted equation plot
xModel = numpy.linspace(min(xData), max(xData))
yModel = func(xModel, *fittedParameters)
# now the model as a line plot
axes.plot(xModel, yModel)
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
plt.show()
plt.close('all') # clean up after using pyplot
graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)
I have the situation like on this image below:
This plot is the result of two vectors:
fi = [41.309180589278, 41.8087915220215, 42.8081880760916, ...
43.8078181874395, 44.8076823745539, 45.8077808710707, 46.3079179803177]
m = [1.00047608139868, 1.00013712198767, 0.999680989440986, ...
0.999524195487826, 0.999671686649694, 1.00012913666266, 1.00047608139868]
I need to get the values of fi where m is equal to 1. So approximately that will be 42.2 and 42.5.
I tried to do spline interpolation:
xq = [fi(1):0.25:fi(7)];
vq1 = interp1(fi,m,xq);
[fi1, fi2] = interp1(m, xq, 1)
But that is not working. Can someone help me with this?
One way to find a zero crossing is to "turn the graph sideways", having fi be a function of m, and interpolate to find m=0. But interp1 requires the m input to be monotonic, which this is not. In fact, this function has two different values for each m.
MATLAB knows the fzeros function, which finds a zero crossing of a function numerically. It requires a function as input. We can define an anonymous function using interp1, which returns m-1 for any value of x. Here, x is defined by fi and f(x) by m:
fi = [41.309180589278, 41.8087915220215, 42.8081880760916, ...
43.8078181874395, 44.8076823745539, 45.8077808710707, 46.3079179803177];
m = [1.00047608139868, 1.00013712198767, 0.999680989440986, ...
0.999524195487826, 0.999671686649694, 1.00012913666266, 1.00047608139868];
fun = #(x)interp1(fi,m,x)-1;
x1 = fzero(fun,42)
x2 = fzero(fun,46)
This gives me:
x1 = 42.109
x2 = 45.525
Note that we needed to know the approximate locations for these two zeros. There is no easy way around this that I know of. If one knows that there are two zero crossings, and the general shape of the function, one can find the local minimum:
[~,fimin] = min(m);
fimin = fi(fimin);
and then find the zero crossings between each of the end points and the local minimum:
x1 = fzero(fun,[fi(1),fimin])
x2 = fzero(fun,[fimin,fi(end)])
You need to use an anonymous function so that you can pass additional arguments to interp1.
Try this
fi = [41.309180589278, 41.8087915220215, 42.8081880760916, ...
43.8078181874395, 44.8076823745539, 45.8077808710707, 46.3079179803177];
m = [1.00047608139868, 1.00013712198767, 0.999680989440986, ...
0.999524195487826, 0.999671686649694, 1.00012913666266, 1.00047608139868];
fzero(#(x) 1-interp1(fi,m,x), 43)
fzero(#(x) 1-interp1(fi,m,x), 45)
The 43 and 45 are the initialization for x for fzero. You need to run the fzero twice to find the two solutions.
I have a cubic expression here
I am trying to determine and plot δ𝛿 in the expression for P values of 0.0 to 5000. I'm really struggling to get the expression for δ in terms of the pressure P.
clear all;
close all;
t = 0.335*1e-9;
r = 62*1e-6;
delta = 1.2*1e+9;
E = 1e+12;
v = 0.17;
P = 0:100:5000
P = (4*delta*t)*w/r^2 + (2*E*t)*w^3/((1-v)*r^4);
I would appreciate if anyone could provide pointers.
I suggest two simple methods.
You evaluate P as a function of delta then you plot(P,delta). This is quick and dirty but if all you need is a plot it will do. The inconvenience is that you may to do some guess-and-trial to find the correct interval of P values, but you can also take a large enough value of delta_max and then restrict the x-axis limit of the plot.
Your function is a simple cubic, which you can solve analytically (see here if you are lost) to invert P(delta) into delta(P).
What you want is the functional inverse of your expression, i.e., δ𝛿 as a function of P. Since it's a cubic polynomial, you can expect up to three solutions (roots) for a give value of P. However, I'm guessing that you're only interested in real-valued solutions and nonnegative values of P. In that case there's just one real root for each value of P.
Given the values of your parameters, it makes most sense to solve this numerically using fzero. Using the parameter names in your code (different from equations):
t = 0.335*1e-9;
r = 62*1e-6;
delta = 1.2*1e9;
E = 1e12;
v = 0.17;
f = #(w,p)2*E*t*w.^3/((1-v)*r^4)+4*delta*t*w/r^2-p;
P = 0:100:5000;
w0 = [0 1]; % Bounded initial guess, valid up to very large values of P
w_sol = zeros(length(P),1);
for i = 1:length(P)
w_sol(i) = fzero(#(w)f(w,P(i)),w0); % Find solution for each P
end
figure;
plot(P,w_sol);
You could also solve this using symbolic math:
syms w p
t = 0.335*sym(1e-9);
r = 62*sym(1e-6);
delta = 1.2*sym(1e9);
E = sym(1e12);
v = sym(0.17);
w_sol = solve(p==2*E*t*w^3/((1-v)*r^4)+4*delta*t*w/r^2,w);
P = 0:100:5000;
w_sol = double(subs(w_sol(1),p,P)); % Plug in P values and convert to floating point
figure;
plot(P,w_sol);
Because of your numeric parameter values, solve returns an answer in terms of three RootOf objects, the first of which is the real one you want.
I have 4 grids:
kgrid which is [77x1]
x which is [15x1]
z which is [9x1]
s which is [2x1]
Then I have a function:
kprime which is [77x15x9x2]
I want to interpolate kprime at some points ksim (750 x 1) and zsim (750 x 1) (xsim is a scalar). I am doing:
[ks, xs, zs, ss] = ndgrid(kgrid, x, z, [1;2]);
Output = interpn(ks, xs, zs, ss, kprime, ksim, xsim, zsim, 1,'linear');
The problem with this interpolation is that the output given is for all combinations of ksim and zsim, meaning that the output is 750x750. I actually need an output of 750x1, meaning that instead of interpolation at all combinations of ksim and zsim I only need to interpolate at ksim(1,1) and zsim(1,1), then ksim(2,1) and zsim(2,1), then ksim(3,1) and zsim(3,1), etc.
In other words, after getting Output I am doing:
Output = diag(squeeze(Output));
I know I can use this output and then just pick the numbers I want, but this is extremely inefficient as it actually interpolates on all other points which I actually do not need. Any help appreciated.
tl;dr: Change xsim and (ssim) from scalars to vectors of the same size as ksim and zsim
Output = interpn (ks, xs, zs, ss, ...
kprime, ...
ksim, ...
repmat(xsim, size(ksim)), ... % <-- here
zsim, ...
repmat(1, size(ksim)), ... % <-- and here
'linear');
Explanation:
The ksim, xsim, zsim, and ssim inputs all need to have the same shape, so that at each common position in that shape, each input acts as an "interpolated subscript" component to the interpolated object. Note that while they all need to have the same shape, this shape can be arbitrary in terms of size and dimensions.
Conversely, if you pass vectors of different sizes (after all, a scalar is a vector of length 1), these get interpreted as the components of an ndgrid construction instead. So you were actually telling interpn to evaluate all interpolations on a grid defined by the vectors ksim, and zsim (and your singletons xsim and ssim). Which is why you got a 2D-grid-looking output.
Note that the same scheme applies with the constructing vectors as well (i.e. ks, xs, zs and ss) i.e. you could have used "vector syntax" instead of "common shape" syntax to define the grid instead, i.e.
Output = interpn(kgrid, x, z, s, kprime, % ...etc etc
and you would have gotten the same result.
From the documents:
Query points, specified as a real scalars, vectors, or arrays.
If Xq1,Xq2,...,Xqn are scalars, then they are the coordinates of a single query point in Rn.
If Xq1,Xq2,...,Xqn are vectors of different orientations, then Xq1,Xq2,...,Xqn are treated as grid vectors in Rn.
If Xq1,Xq2,...,Xqn are vectors of the same size and orientation, then Xq1,Xq2,...,Xqn are treated as scattered points in Rn.
If Xq1,Xq2,...,Xqn are arrays of the same size, then they represent either a full grid of query points (in ndgrid format) or scattered points in Rn.
Answer
You want the usage highlighted in bold. As such, you have to make sure that xsim and ssim ('1' in your code sample) are of size 750x1 also. Then all the query vectors are same length and orientation, such that it can be recognized as a vector of scattered points in Rn. The output will then be a 750x1 vector as needed.
This is to elaborate on #tvo/#Tasos answers, to test the fastest way to create a vector from a scalar:
function create_vector(n)
x = 5;
repm_time = timeit(#()repm(x,n))
repe_time = timeit(#()repe(x,n))
vrep_time = timeit(#()vrep(x,n))
onesv_time = timeit(#()onesv(x,n))
end
function A = repm(x,n)
for k = 1:10000
A = repmat(x,[n 1]);
end
end
function A = repe(x,n)
for k = 1:10000
A = repelem(x,n).';
end
end
function A = vrep(x,n)
v = ones(n,1);
for k = 1:10000
A = x*v;
end
end
function A = onesv(x,n)
for k = 1:10000
A = x*ones(n,1);
end
end
And the results are (for n = 750):
repm_time =
0.049847
repe_time =
0.044188
vrep_time =
0.0041342
onesv_time =
0.0024869
which means that the fastest way to create a vector from a scalar is simply writing x*ones(n,1).
I need to generate two chaotic sequences based on chen's hyperchaotic system.It has to be generated from the following four formulas
X=ay-x;
Y=-xz+dx+cy-q;
Y=xy-bz;
Q=x+k;
where a,b,c,d,x,y,z,q are all initialised as follows.
I need only X and Y
where
X=[x1,x2,...x4n]
Y=[y1,y2,...y4n]
a=36 ;
b=3 ;
c=28 ;
d=16 ;
k=0.2 ;
x=0.3 ;
y=-0.4 ;
z=1.2 ;
q=1 ;
n=256 ;
I tried the following code but i'm not able to get it properly.
clc
clear all
close all
w=imread('C:\Users\Desktop\a.png');
[m n]=size(w)
a=36;
b=3;
c=28;
d=16;
k=0.2;
x(1)=0.3;
y(1)=-0.4;
z(1)=1.2;
q(1)=1;
for i=1:1:4(n)
x(i+1)=(a*(y(i)-x(i)));
y(i+1)=-(x(i)*z(i))+(d*x(i))+(c*y(i))-q(i);
z(i+1)=(x(i)*y(i))-(b*z(i));
q(i+1)=x(i)+k;
end
disp(x);
disp(y);
pls help. thanks in advance.
Your code isn't even close to doing what you want it to. Fortunately, I'm vaguely interested in the problem and I have a bunch of spare time, so I thought I'd try and implement it step by step to show you what to do. I've left a few gaps for you to fill in.
It sounds like you want to integrate the hyperchaotic chen system, which has various definitions online, but you seem to be focusing on
So let's write a matlab function that defines that system
function vdot = chen(t, v, a, b, c, d, k)
% Here you unpack the input vector v -
x = v(1); y = v(2); z = v(3); q = v(4);
% Here you need to implement your equations as xdot, ydot etc.
% xdot = ...
% ydot = ...
% I'll leave that for you to do yourself.
% Then you pack them up into an output vector -
vdot = [xdot; ydot; zdot; qdot];
end
Save that in a file called chen.m. Now you need to define the values of the parameters a, b, c, d and k, as well as your initial condition.
% You need to define the values of a, b, c, d, k here.
% a = ...
% b = ...
% You also need to define the vector v0, which is a 4x1 vector of your
% initial conditions
% v0 = ...
%
This next line creates a function that can be used by Matlab's integration routines. The first parameter t is the current time (which you don't actually use) and the second parameter is a 4x1 vector containing x, y, z, q.
>> fun = #(t,v) chen(t,v,a,b,c,d,k)
Now you can use ode45 (which does numerical integration using a 4th order runge-kutta scheme) to integrate it and plot some paths. The first argument to ode45 is the function you want to be integrated, the second argument is the timespan to be integrated over (I chose to integrate from 0 to 100, maybe you want to do something different) and the third argument is your initial condition (which hopefully you already defined).
>> [t, v] = ode45(fun, [0 100], v0);
The outputs are t, a vector of times, and v, which will be a matrix whose columns are the different components (x, y, z, q) and whose rows are the values of the components at each point in time. So you can pull out a column for each of the x and y components, and plot them
>> x = v(:,1);
>> y = v(:,2);
>> plot(x,y)
Which gives a reasonably chaotic looking plot:
#Abirami Anbalagan and Sir #Chris Taylor, I have also studied hyperchaotic system up to some extent. According to me, for system to be chaotic, values should be like
a= 35; b= 3; c= 12; d= 7;
v(n) = [-422 -274 0 -2.4]transpose
where v(n) is a 4*1 Matrix.