MATLAB fminsearch optimization error - matlab

I want to optimize x value in the following equation
formula_1=((x(1)+x(2).*exp(-TR./x(3)))./(1+cos(time_stamps).* exp(-TR./x(3))));
diff =#(x)sum((formula_1-img_vol).^2);
[pa,fval,exfl]= fminsearch(diff,startingvals,opts);
startingvals=[1,1,0.1];
opts = optimset('Display','off','TolFun',1e-9,'TolX',1e-9);
img_vol = 32x32x11 vector.
These all I am doing in the main script file. But the error comes out is
Error in fminsearch (line 191)
fv(:,1) = funfcn(x,varargin{:});
Error in biexp_main (line 65)
[pa,fval,exfl]=fminsearch(diff,startingvals,opts);
Kindly help me what I suppose to do??

It is rather difficult to reproduce your error since there is many information missing. (What is the exact error? What are the sizes of TR and time_stamps?).
What should help is:
change your function diff so that it returns a scalar if this is currently not the case (check with diff(startginvals)). Maybe change it to sum(sum(sum(.))).
As indicated in the comments: diff is independent from x in the current form. The 'indirect contribution' you mention does not work: it considers formula_1 and hence x as constant.
Putting this together, try:
TR = rand; %?
time_stamps = rand; %?
img_vol = rand(32,32,11);
formula_1 = #(x) (x(1)+x(2).*exp(-TR./x(3))) ./ (1+cos(time_stamps).*exp(-TR./x(3)));
diff = #(x) sum(sum(sum((formula_1(x)-img_vol).^2)));
opts = optimset('Display','off','TolFun',1e-9,'TolX',1e-9);
startingvals=[1,1,0.1];
[xOpt,diffOpt] = fminsearch(diff,startingvals,opts);

Related

How can I get around this error using deval with dde23 in MATLAB?

I am trying to plot a graph between k(t) and k(t-1) of the solution of my delay differential equation. I am pasting the code:
% Defining the variables:
X = 0.2;
M_C = 1.523;
a = 15;
sol = dde23(#(k,t,KL) new_func(k,t,KL,X,M_C,a),1,0.5, [1,10] );
t = linspace(1,10);
p_t = deval(sol,t);
p_lagt = deval(sol,t-1);
% Stability boundary for M/C:
M_C_Stab = 1.523;
function dk = new_func(k,t,KL,X,M_C,a)
dk = X*((1-M_C*(1-KL^a))/(M_C*(1-KL^a)))*k;
end
This is the error I am getting:
>> new_defined_function
Error using deval (line 132)
Attempting to evaluate the solution outside the interval [1.000000e+00, 1.000000e+01] where it is defined.
Error in new_defined_function (line 12)
p_lagt = deval(sol,t-1);
Example 2 in this tutorial is what I am referring to but even that code is giving an error. Maybe because its old as ddeval which has been used here has already become deval.
I am fairly new to MATLAB and have no idea how to resolve this error. If anyone could help, I'll be more than grateful.
The error is caused by
p_lagt = deval(sol,t-1)
t-1 is equivalent to linspace(0,9), and so trying to evaluate the solution at time 0 causes an error as the solution was calculated on the time interval [1,10].
You could fix the error by changing the p_lagt so that it is evaluated on an interval contained in [1,10], for example
p_lagt = deval(sol,max(t-1,1))
Note in the example you linked to, the solution is calculated on the time interval [0,100], while t = linspace(2,100). To mirror this in your code try
sol = dde23(#(k,t,KL) new_func(k,t,KL,X,M_C,a),1,0.5, [0,10] ); % note change in time interval
t = linspace(1,10);
p_t = deval(sol,t);
p_lagt = deval(sol,t-1);

`fzero` function in matlab fails to find the root and keeps on generating error

I am using MATLAB and I want to find the root of an equation F(x)-u=0. Here u=0.2861 and
F=normcdf(sqrt(lambda/t)*(t/mu-1))+exp(2*lambda/mu)*normcdf(-sqrt(lambda/t)*(t/mu+1)).
The value of lambda and mu are both 1.
I typed the following code
[x,fval] = fzero(#(t) normcdf(sqrt(lambda/t)*(t/mu-1))+exp(2*lambda/mu)*normcdf(-sqrt(lambda/t)*(t/mu+1))-u, 10);
and hope this can help me find the root. I can show mathematically that this equation has unique root. However, I keep on getting the following error
Error using erfc Input must be real and full.
Error in normcdf>localnormcdf (line 128) p(todo) = 0.5 * erfc(-z ./
sqrt(2));
Error in normcdf (line 50) [varargout{1:max(1,nargout)}] =
localnormcdf(uflag,x,varargin{:});
Error in
Test>#(t)normcdf(sqrt(lambda/t)*(t/mu-1))+exp(2*lambda/mu)*normcdf(-sqrt(lambda/t)*(t/mu+1))-u
Error in fzero (line 363)
a = x - dx; fa = FunFcn(a,varargin{:});
Then I did a "brutal force" method.
t = [0:0.001:20];
F = normcdf(sqrt(lambda./t).*(t/mu-1))+exp(2*lambda/mu).*normcdf(-sqrt(lambda./t).*(t/mu+1))-u;
plot(t,F)
I can clearly eyeball that F(t)-u is increasing in t and the root is around 0.4. My question is why fzero does not work in this case and is there a way to make fzero work?
The problem is that the function does not change sign, which is required as the docs say:
x = fzero(fun,x0) tries to find a point x where fun(x) = 0. This
solution is where fun(x) changes sign — fzero cannot find a root of a
function such as x^2.
I broke up your code to make it a bit clearer (at least for me).
lambda = 1;
mu = 1;
u = 1;
% break up function code
arg1 = #(t) +sqrt(lambda./t).*(t./mu-1);
arg2 = #(t) -sqrt(lambda./t).*(t./mu+1);
fnc = #(t) normcdf(arg1(t))+exp(2*lambda/mu).*normcdf(arg2(t))-u;
% call fzero to find the root
% [x,fval] = fzero(fnc, 10);
% plot
x = 0:0.01:10;
plot(x,fnc(x))
The function is not defined for any input t < 0 due to the sqrt in my function handle arg. So if you plot it for values t > 0, you see that it never passes zero.
EDITED: sign mix-up in the arguments. Thx flxx for pointing this out. Plot & code updated. The argument still holds.

Fitting model to data in matlab

i have some experimental data and a theoretical model which i would like to try and fit. i have made a function file with the model - the code is shown below
function [ Q,P ] = RodFit(k,C )
% Function file for the theoretical scattering from a Rod
% R = radius, L = length
R = 10; % radius in Å
L = 1000; % length in Å
Q = 0.001:0.0001:0.5;
fun = #(x) ( (2.*besselj(1,Q.*R.*sin(x)))./...
(Q.*R.*sin(x)).*...
(sin(Q.*L.*cos(x)./2))./...
(Q.*L.*cos(x)./2)...
).^2.*sin(x);
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
end
with Q being the x-values and P being the y-values. I can call the function fine from the matlab command line and it works fine e.g. [Q,P] = RodFit(1,0.001) gives me a result i can plot using plot(Q,P)
But i cannot figure how to best find the fit to some experimental data. Ideally, i would like to use the optimization toolbox and lsqcurvefit since i would then also be able to optimize the R and L parameters. but i do not know how to pass (x,y) data to lsqcurvefit. i have attempted it with the code below but it does not work
File = 30; % the specific observation you want to fit the model to
ydata = DataFiles{1,File}.data(:,2)';
% RAdius = linspace(10,1000,length(ydata));
% LEngth = linspace(100,10000,length(ydata));
Multiplier = linspace(1e-3,1e3,length(ydata));
Constant = linspace(0,1,length(ydata));
xdata = [Multiplier; Constant]; % RAdius; LEngth;
L = lsqcurvefit(#RodFit,[1;0],xdata,ydata);
it gives me the error message:
Error using *
Inner matrix dimensions must agree.
Error in RodFit (line 15)
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
Error in lsqcurvefit (line 199)
initVals.F = feval(funfcn_x_xdata{3},xCurrent,XDATA,varargin{:});
Caused by:
Failure in initial user-supplied objective function evaluation. LSQCURVEFIT cannot continue.
i have tried i) making all vectors/matrices the same length and ii) tried using .* instead. nothing works and i am giving the same error message
Any kind of help would be greatly appreciated, whether it is suggestion regading what method is should use, suggestions to my code or something third.
EDIT TO ANSWER Osmoses:
A really good point but i do not think that is the problem. just checked the size of the all the vectors/matrices and they should be alright
>> size(Q)
ans =
1 1780
>> size(P)
ans =
1 1780
>> size(xdata)
ans =
2 1780
>> size([1;0.001]) - the initial guess/start point for xdata (x0)
ans =
2 1
>> size(ydata)
ans =
1 1780
UPDATE
I think i have identified the problem. the function RodFit works fine when i specify the input directly e.g. [Q,P] = RodFit(1,0.001);.
however, if i define x0 as x0 = [1,0.001] i cannot pass x0 to the function
>> x0 = [1;0.001]
x0 =
1.0000
0.0010
>> RodFit(x0);
Error using *
Inner matrix dimensions must agree.
Error in RodFit (line 15)
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
The same happens if i use x0 = [1,0.001]
clearly, matlab is interpreting x0 as input for k only and attempts to multiplay a vector of length(ydata) and a vector of length(x0) which obviously fails.
So my problem is that i need to code so that lsqcurvefit understands that the first column of xdata and x0 is the k variable and the second column of xdata and x0 is the C variable. According to the documentation - Passing Matrix Arguments - i should be able to pass x0 as a matrix to the solver. The solver should then also pass the xdata in the same format as x0.
Have you tried (that's sometimes the mistake) looking at the orientation of your input data (e.g. if xdata & ydata are both row/column vectors?). Other than that your code looks like it should work.
I have been able to solve some of the problems. One mistake in my code was that the objective function did not use of vector a variables but instead took in two variables - k and C. changing the code to accept a vector solved this problem
function [ Q,P ] = RodFit(X)
% Function file for the theoretical scattering from a Rod
% R = radius, L = length
% Q = 0.001:0.0001:0.5;
Q = linspace(0.11198,4.46904,1780);
fun = #(x) ( (2.*besselj(1,Q.*R.*sin(x)))./...
(Q.*R.*sin(x)).*...
(sin(Q.*L.*cos(x)./2))./...
(Q.*L.*cos(x)./2)...
).^2.*sin(x);
P = (integral(fun,0,pi/2,'ArrayValued',true))*X(1)+X(2);
with the code above, i can define x0 as x0 = [1 0.001];, and pass that into RodFit and get a result. i can also pass xdata into the function and get a result e.g. [Q,P] = RodFit(xdata(2,:));
Notice i have changed the orientation of all vectors so that they are now row-vectors and xdata has size size(xdata) = 1780 2
so i thought i had solved the problem completely but i still run into problems when i run lsqcurvefit. i get the error message
Error using RodFit
Too many input arguments.
Error in lsqcurvefit (line 199)
initVals.F = feval(funfcn_x_xdata{3},xCurrent,XDATA,varargin{:});
Caused by:
Failure in initial user-supplied objective function evaluation. LSQCURVEFIT cannot continue.
i have no idea why - does anyone have any idea about why Rodfit recieves to many input arguments when i call lsqcurvefit but not when i run the function manual using xdata?

correct function handle for integral2 in matlab

I created a function in matlab that returns a vector like
function w = W_1D(x,pos,h)
w=zeros(1,length(x));
if (h~=0)
xmpos = x-pos;
inds1 = (-h <= xmpos) & (xmpos < 0);
w(inds1) = xmpos(inds1)./h + 1;
inds2 = (0 <= xmpos) & (xmpos <= h);
w(inds2) = -xmpos(inds2)./h + 1;
else
error('h shouldn't be 0')
end
end
Thus, in the end, there is a vector w of size length(x).
Now i created a second function like
function f = W_2D(x,y,pos_1,pos_2,h)
w_x = W_1D(x,pos_1,h);
w_y = W_1D(y,pos_2,h);
f = w_x'*w_y;
end
where length(x)=length(y). Thus, the function W_2D obviously returns a matrix.
But when I now try to evaluate the integral over a rectangular domain like e.g.
V = integral2(#(x,y) W_2D(x,y,2,3,h),0,10,0,10);
matlab returns some errors:
Error using integral2Calc>integral2t/tensor (line 242)
Integrand output size does not match the input size.
Error in integral2Calc>integral2t (line 56)
[Qsub,esub] = tensor(thetaL,thetaR,phiB,phiT);
Error in integral2Calc (line 10)
[q,errbnd] = integral2t(fun,xmin,xmax,ymin,ymax,optionstruct);
Error in integral2 (line 107)
Q = integral2Calc(fun,xmin,xmax,yminfun,ymaxfun,opstruct);
I also tried to vary something in the W_2D-function: instead of f = w_x'*w_y;
I tried f = w_x.'*w_y;
or w_y = transpose(w_y); f = kron(w_x,w_y);, but there is always this error with the Integrand output size-stuff.
Can anyone explain, where my fault is?
EDIT: After Werner's hint with the keyboard debugging method, I can tell you the following.
The first step returns w_x of type <1x154 double>, w_y is <1x192 double>, x and y are both <14x14 double>. In the next step, f appears with a value of <154x192 double>. Then everything disappears, except x and y and the matlab-function integral2Calc.m appears in the editor and it jumps to the Function Call Stack integral2t/tensor and after some more steps, the error occurs here
Z = FUN(X,Y); NFE = NFE + 1;
if FIRSTFUNEVAL
if ~isfloat(Z)
error(message('MATLAB:integral2:UnsupportedClass',class(Z)));
end
% Check that FUN is properly vectorized. This is important here
% because we (otherwise) always pass in square matrices, which
% reduces the probability of the user generating an error by
% using matrix functions instead of elementwise functions.
Z1 = FUN(X(VTSTIDX),Y(VTSTIDX)); NFE = NFE + 1;
if ~isequal(size(Z),size(X)) || ~isequal(size(Z1),size(VTSTIDX))
% Example:
% integral2(#(x,y)1,0,1,0,1)
error(message('MATLAB:integral2:funSizeMismatch'));
end
Hope that information is detailed enough...I have no idea what happenes, because my example is exact as it is given on the mathworks site about integral2, isn't it?
Maybe I should precise a bit more, what I wanna do: since W_2D gives me a surface w(x,y) of a compactly supported 2-dimensional hat-function, stored in a matrix w, I want to calculate the volume between the (x,y)-plane and the surface z=w(x,y)...
EDIT2: I still do not understand how to handle the problem, that integral2 creates matrices as inputs for my W_1D-functions, which are called in W_2D and intended to have a <1xn double>-valued input and return a <1xn double> output, but at least I can simply use the following to solve the integration over the tensor product by using two one-dimensional integral-calls, that is
V = integral(#(x)integral(#(y)W_1D(y,3,h),0,10).*W_1D(x,2,h),0,10);
This first function is quite wrong. You are not indexing the array positions while you are doing w = x inside for.
Besides, if that would work, you are returning a line vector, that is, size 1xlength(x) and when you do w_x'*w_y you are doing length(x)x1 times 1xlength(y), which would give you a matrix length(x)*length(y).
Consider correcting your function:
function w = W_1D(x,pos)
w = zeros(length(x),1); % Allocate w as column vector, so that the product gives a scalar (as I suppose that it is what you want.
for ii=1:length(x) % Here, so that is indexes w and x elements as you need
w(ii)=x(ii) - pos; % I changed your code to something that makes sense, but I don't know if that is what you want to do, you have to adapt it to work correctly.
end
end
You may also want to debug your functions, consider adding keyboard before your operations and check what they are returning using dbstep. I.e:
function f = W_2D(x,y,pos_1,pos_2)
w_x = W_1D(x,pos_1);
w_y = W_1D(y,pos_2);
keyboard
f = w_x'*w_y;
end
Execution will stop at keyboard, then you can check w_x size, w_y size, and do dbstep to go after f = w_x'*w_y and see what it returned. After you finish debug, you can do dbcont so that it will continue execution.
This answer is a draft as it is quite difficult to help you with the information you have provided. But I think you can start working the things out with this. If you have more doubts feel free to ask.

MATLAB: evaluation of a piecewise polynomial (pchip) with ppval

I am trying to do a pchip interpolation in MATLAB. The interpolation works fine, but when I use the ppval function to check the curve (for plotting) I get an error message, and I cannot figure out what the problem is.
I have previously used the pchip function in this way: yi = pchip(x,y,xi), and that worked ok. However, I now want only the coefficients (pp.coefs). The problem is that they seem to make no sense when I try to check them with the ppval function.
This is an example:
x = [1.4771 1.9031 2.3802 2.9031 3.3979];
y = [6.1727 5.1242 3.4537 1.8528 0];
pp = pchip(x,y);
xs = linspace(x(1),x(end),200);
yy = ppval(pp.coefs,xs);
Error using unmkpp (line 19)
The input array does not seem to describe a pp function.
Error in ppval (line 63)
[b,c,l,k,dd]=unmkpp(pp);`
Can anyone help me figure out where I am doing something wrong? Thanks!
Do not just pass the coefficients to ppval but the entire structure that is returned by pchip.
This should work:
pp = pchip(x,y);
xs = linspace(x(1),x(end),200);
yy = ppval(pp,xs);