how to use a piecewise function with fsolve?

I want to use piecewise objective function with fsolve. If i define the objective function using an if statement I get 'Conversion to logical from sym is not possible.'. When I use piecewise built-in function it returns an error when I try convert the objective function to a matlabFunction.
Actually, the objective function consists of 3 functions, for a region i need fsolve to consider only two of the functions. I was thinking of doing this by defining one of the functions as NaN in a certain region. Is this possible?

 Accepted Answer

It is not possible to use piecewise with fsolve. It is possible to use piecewise with vpasolve.
Also I discovered earlier today that if you have a symbolic expression that contains piecewise, that if you use matlabFunction() with the 'file' option then the code written will use 'if' to decide the case and do the appropriate computation. Unfortunately the generated code is not vectorized (which would require logical indexing rather than if), but provided you used the matlabFunction 'vars' option to put all of variables into a single argument, you would be able to use it with fsolve.

7 Comments

Thanks for your answer.
Do I need to do logical indexing if I use 'file' and 'vars' options?
However I don't get why it returns the error about if statement. 'Illegal use of reserved keyword "if".'
syms param1 param2 param3;
param=[param1,param2,param3];
n=numel(peakdata);
p1=piecewise(param(1)~=0 & param(1)<1, param(2)+param(3)/param(1)*(gamma(1-param(1))-1),...
param(1)==0,param(2)+param(3)*(-psi(1)),...
param(1)>1,NaN);
p2=piecewise(param(1)~=0 & param(1)<0.5, (param(3)^2)*((gamma(1-2*param(1)))-(gamma(1-2*param(1)))^2)/(param(1))^2,...
param(1)==0, (param(3)^2)*(pi^2)/6,...
param(1)>0.5,NaN);
p3=piecewise(param(1)==0, 12*(6^0.5)*zeta(3)/pi^3,...
sign(param(1))*(gamma(1-3*param(1))-3*gamma(1-param(1))*gamma(1-2*param(1))+2*(gamma(1-param(1)))^3)/((gamma(1-2*param(1))-(gamma(1-param(1)))^2)^(3/2)));
mean=(1/n)*sum(peakdata(1:end));
f1=piecewise(param(1)<1,p1-mean,param(1)>1,NaN);
a2=0;
for l=1:n
a2=a2+(peakdata(l)-((1/n)*sum(peakdata(1:end))))^2;
end
variance=(1/(n-1))*a2;
f2=piecewise(param(1)<0.5,p2-variance,param(1)>0.5,NaN);
a3=0;
for l=1:n
a3=a3+((peakdata(l)-((1/n)*sum(peakdata(1:end))))/(((1/(n-1))*a2)^0.5))^3;
end
skewness=1/n*a3;
f3=p3-skewness;
f=matlabFunction([f1;f2;f3],'vars',{param},'File','mom_gev');
param0=[0.2,2,1];
options=optimoptions('fsolve','MaxFunctionEvaluations',500,'Display','iter-detailed')
[xfinal,fval,exitflag,output] = fsolve(f,param0,options);
I notice that you did not specify a .m file extension in the matlabFunction. I do not know if it would be assumed.
You do not need to convert the generated code to logical indexing for use with fsolve.
I see that there is a bug in the code that is generated for the situation where you ask for an array output and there is a piecewise involved. I will file a bug report later today. In the meantime, ask to generate for f1, f2, f3 separately, and then create another anonymous function that puts them together in a vector
F1 = matlabFunction...
F2 = matlabFunction...
f = @(x) [f1(x); f2(x); f3(x) ]
This works, thank you.
(I just submitted the bug report.)
Has this bug been fixed? Thanks.
Unfortunately no, if you use matlabFunction with 'file' and piecewise() then although it generates appropriate if to handle the piecewise, it still does so assuming the input is a scalar. For example
F = [a, a^2, piecewise(a<0, -(-a)^(1/3), a^(1/3))]
is currently still turned into code that has
if (a < 0.0)
t0 = -(-a).^(1.0./3.0);
else
t0 = a.^(1.0./3.0);
end
F = [a,a.^2,t0];
instead of generating logical indexing or a loop.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!