Gradient of implicit symbolic expression in Matlab - matlab

The situation I have is as follows:
I have a symbolic expression like:
syms X Y Z K
Ra=51.7;
P=[0 0 200];
Sa=sym('Ra^2==(Z-P(3))^2+(Y-P(2))^2')
Where Y and Z are defined as symbolic. Ra and P are vectors.
I need to get the gradient of Sa but I get an error:
G=gradient(Sa,[Y Z]);
Error using symengine (line 59)
The first argument must be of type 'Type::Arithmetical'.
Error in sym/gradient (line 39)
res = mupadmex('symobj::gradient',fsym.s,x.s);
But if I write the same expression as:
Sa(Y,Z)=((Z-P(3))^2+(Y-P(2))^2-Ra^2);
I get the expected result
G=gradient(Sa,[Y Z])
G(X, Y, Z) =
2*Y
2*Z - 400
Does anyone knows why this is so and if there's any way of using the implicit expression as this is a particular case but in general I have different implicit expressions and my code should be able to deal with them.
I've read the documentation on gradient and some sites, but if I found the answer I didn't notice.
I believe I could use the second form but still, I am curious about this subject.
Thanks for your time.

In the first one Sa is the entire equation, including the ==, while in the second one its a symbolic function depending on 2 variables.
Ultimately the way MATLAB seems to be handle this is that the first one is not derivable (also its dependent in another 2 sym variables, that doesn't know if they are related or not to the derived ones), while the second one gets identified as a function (symbolic) and can get derived.

Related

In MATLAB, how can I declare an implicit variable, y(t), after I have used it in a symbolically defined function?

I'm writing a scheme that solves an ODE and in doing so I declare a symbolic function:
syms t y(t)
f = t^(-2) * (sin(2*t) - 2*t*y)
At one point I have to take a total derivative, so I need y(t) to be be implicit in the expression, but I also need to evaluate f(t,y) at a specific value of t and y. I attempt to do this in the following lines.
y(t) = wi;
out(1) = f(ti);
However, I am prompted with the following error.
The following error occurred converting from sym to double:
Unable to convert expression containing remaining symbolic function calls into double array.
Argument must be expression that evaluates to number.
Error in DiffEq_alt (line 13)
out(1) = f(ti);
Ultimately, I need to be able to be able to declare y explicitly, but also treat it implicitly for when I differentiate the function f(t,y(t)) with respect to t.
Note: This exact question was also posted on MathWorks.

Set complicated assumptions on symbolic function

I am trying to find the roots of a nonlinear function that depends on several symbolic variables and a symbolic function. To guarantee the existence of a solution I need to set some assumptions on the symbolic function b(x).
By using the Matlab function assume I can set simple assumptions like
syms b(x) d
assume(b(0)==0 & b(x)>=0);
Now I am looking for a way to include this assumption: (symbolic function b(x), symbolic variable d)
There is a value y such that b(x) < d*x for x < y and b(x) > d*x for x > y.
To make it easier we can fix for example d=0.1 and b(10)=1 such that y=10. However I would prefer leaving d and y symbolic.
I tried to write a function that checks the assumption but unsurprisingly Matlab does not seem to accept a symbolic function as an input variable.
Do you know a solution to this problem or have an idea?
Update 2017-01-03:
While having fixed d=0.1,b(10)=1 and y=10 I am trying to check the above assumption by using
syms b(x)
d=0.1;
assume(x, 'real');
assume(x>=0);
assume(b(0)==0 & b(x)>=0 & b(10)==1);
checkAssumption(x)= mySign(x)*(d*x-b(x));
assume(checkAssumption(x)>=0);
where
function sign=mySign(x)
if x<10
sign=-1;
else if x==10
sign=0;
else if x>10
sign=-1;
end
end
end
Then I get the error "Conversion to logical from sym is not possible." in mySign. Using double(x) as the input variable of mySign leads to the error "DOUBLE cannot convert the input expression into a double array".
Do you know a way to get mySign and checkAssumptions evaluated or have an other idea how to assume the above assumption?

Computing mixed derivatives in MATLAB using syms and diff

I'm using MATLAB 2012b.
I want to get d²/dxdy of a simple function:
f(x,y) = (x-1)² + 2y²
The documentation states that I can use syms and diff as in the following example:
> syms x y
> diff(x*sin(x*y), x, y)
ans =
2*x*cos(x*y) - x^2*y*sin(x*y)
But doing the same I got the wrong answer:
> syms x y
> f = (x-1)^2 + 2*y^2;
> diff(f,x,y)
ans =
4*y
The answer is right if I use diff like this:
diff(diff(f,x),y)
Well, it's not a problem for me to use it this way, but nevertheless why is the first variant not working? Is it a version issue?
The actual documentation from R2010a:
diff(expr) differentiates a symbolic expression expr with respect to its free variable as determined by symvar.
diff(expr, v) and diff(expr, sym('v')) differentiate expr with respect to v.
diff(expr, n) differentiates expr n times. n is a positive integer.
diff(expr, v, n) and diff(expr, n, v) differentiate expr with respect to v n times.
So, the command diff(f,x,y) is the last case. It would be equal to differentiating f w.r.t. x, y times, or w.r.t y, x times.
For some reason I don't quite understand, you don't get a warning or error, but one of the syms variables gets interpreted as n = 1, and then the differentiation is carried out. In this case, what diff seems to do is basically diff(f, y, 1).
In any case, it seems that the behavior changed from version to version, because in the documentation you link to (R2016b), there is an additional case:
diff(F,var1,...,varN) differentiates F with respect to the variables var1,...,varN
So I suspect you're running into a version issue.
If you want to differentiate twice, both w.r.t x and y, your second attempt is indeed the correct and most portable way to do that:
diff( diff(f,x), y )
or equivalently
diff( diff(f,y), x )
NB
I checked the R2010a code for symbolic/symbolic/#sym/diff.m and indeed, n is defaulted to 1 and only changed if one of the input variables is a double, and the variable to differentiate over is set equal to the last syms variable in the argument list. The multiple syms variable call is not supported, nor detected and error-trapped.
Syms is only creating symbolic variables.
The first code you execute is only a single derivative. The second code you provided differentiates two times. So I think you forgot to differentiate a second time in the first piece of code you provided.
I am also wondering what answer you expect? If you want 4*y as answer, than you should use
diff(f,y)
and not
diff(f,x,y)
Performing the second derivative is giving me zero?
diff(diff(f,x),y)
If you want 4 as answer than you have to do following:
diff(diff(f,y),y)

Can I change the formula of a symbolic function in MATLAB?

I have the following code:
syms t x;
e=symfun(x-t,[x,t]);
In the problem I want to solve x is a function of t but I only know its value at the given t,so I modeled it here as a variable.I want to differentiate e with respect to time without "losing" x,so that I can then substitute it with x'(t) which is known to me.
In another question of mine here,someone suggested that I write the following:
e=symfun(exp(t)-t,[t]);
and after the differentiation check if I can substitute exp(t) with the value of x'(t).
Is this possible?Is there any other neater way?
I'm really not sure I understand what you're asking (and I didn't understand your other question either), but here's an attempt.
Since, x is a function of time, let's make that explicit by making it what the help and documentation for symfun calls an "abstract" or "arbitrary" symbolic function, i.e., one without a definition. In Matlab R2014b:
syms t x(t);
e = symfun(x-t,t)
which returns
e(t) =
x(t) - t
Taking the derivative of the symfun function e with respect to time:
edot = diff(e,t)
returns
edot(t) =
D(x)(t) - 1
the expression for edot(t) is a function of the derivative of x with respect to time:
xdot = diff(x,t)
which is the abstract symfun:
xdot(t) =
D(x)(t)
Now, I think you want to be able to substitute a specific value for xdot (xdot_given) into e(t) for t at t_given. You should be able to do this just using subs, e.g., something like this:
sums t_given xdot_given;
edot_t_given = subs(edot,{t,xdot},{t_given, xdot_given});
You may not need to substitute t if the only parts of edot that are a function of time are the xdot parts.

Function works with lsqcurvefit but not nlinfit

I'm attempting to get a nonlinear least squares fit for the following function:
Nloc = 250;
d = 1 / Nloc;
m = 0.5; %Initial guess
ncmfun = #(m, p) arrayfun(#(p) betainc(d, Nloc*m .* p, Nloc*m .* (1 - p), 'upper'), p);
Where m is the parameter being fit, Nloc and d are constants, and p and freq are vectors of positive real numbers and of the same length (I triple checked). When I use lsqcurvefit everything works fine:
[mfit,resnorm,] = lsqcurvefit(ncmfun, m, p, freq, 0, 1)
Also, if I use any m to evaluate the function, everything works fine as well. However when I use nlinfit:
[mfit,R,Jac,CovB,MSE,ErrorModelInfo] = nlinfit(p, freq, ncmfun, m)
I get the following error(s):
Error using betainc
Z must be real and non-negative.
Error in #(p)betainc(d,Nloc*m.*p,Nloc*m.*(1-p),'upper')
Error in
#(m,p)arrayfun(#(p)betainc(d,Nloc*m.*p,Nloc*m.*(1-p),'upper'),p)
Error in nlinfit>#(b,x)w.*model(b,x) (line 206)
modelw = #(b,x) w.*model(b,x);
Error in nlinfit>LMfit (line 486)
yfit = model(beta,X);
Error in nlinfit (line 207)
[beta,J,~,cause,fullr] = LMfit(X,yw,
modelw,beta,options,verbose,maxiter);
Error in Sloan_NCM_Parameterize_Nm (line 37)
[mfit,R,Jac,CovB,MSE,ErrorModelInfo] = nlinfit(p, freq,
ncmfun, m);
What's especially frustrating was this same script was working a couple weeks ago. I then tried to use it again and it no longer works. I tried to go through and see if I accidentally changed something and didn't remember, but I can't find any errors. Furthermore, I'm confused as to why lsqcurvefit works but not nlinfit. I'd like to use nlinfit because it provides me with more statistical information about the error.
Thanks in advance for any help you can provide!
They both use the same algorithm to identify a solution, however, you are explicitly stating an upper and lower bound for your solution in lsqcurvefit which ensures your incomplete beta function behaves. You don't have this option in nlinfit. I'm not sure what you did before (you can always look at the command history)
You have a few options from this point:
1 - programatically intercept every value that goes to ncmfun, by either expending your anonymous functions in what my nightmares are made of, or creating your own m-file for it. If the value is outside of [0,1] return progressively higher error value (with the boundaries being >>> then any possible value within the set)
2 - Try to force a quicker convergence by playing with some of the parameters (perhaps by using a robust fitting option (cf documentation))