Transforming Symbolic Derivatives into Actual Symbols - matlab

I need to take derivatives in Matlab of a lot of equations w.r.t. generic functions, which will provide me with generic derivatives, of the type:
diff(f(x,y),x)
or
D([1],f(x,y)).
What I need is to transform these derivatives into actual symbolic variables, in order to be able to use solve, etc. What I am doing now, but which is highly inefficient, is brute force string replacement. Here is a minimal working example of what I am doing:
syms x y
f(x,y) = sym('f(x,y)')
jacobian(f)
first_d = jacobian(f)
strrep(char(first_d),'D([1], f)(x, y)','fx')
In my real application, I have lots of derivatives to take from lots of equations, so looping such replacements is not the smartest thing to do. Can anybody shed some light into a more efficient solution?

Note: I'm using R2014b. Symbolic Math functionality has changed greatly in recent versions and continues to do so. Users on different versions may need to do slightly different things to achieve the results below, which relies on accessing undocumented functionality.
First, since this is about performance, it is sufficient to simply declare
syms f(x,y)
which also defines x and y as symbolic variables.
As I mention in my comments above, Matlab/MuPAD's symbolic math is all about manipulating strings. Doing this more directly and and adding in you own knowledge of the problem can help speed things up. You want to avoid unnecessary conversions between strings and the sym/symfun types.
1. The first thing to do is investigate how a particular symbolic math function is handling input and output and what lower level private functions it is calling. In the case of your jacobian function example, type edit jacobian in your command window to view the code in the Editor. Much of what you see may be confusing, but you should see this line:
res = mupadmex('symobj::jacobian',Fsym.s,v.s);
This calls the low level 'symobj::jacobian' function and passes in string versions of the function and variables. To call this yourself, you can do (this also assumes you know your variables are x and y):
syms f(x,y)
first_d = mupadmex('symobj::jacobian',char(f),char([x,y]))
This returns [ diff(f(x, y), x), diff(f(x, y), y)]. The undocumented mupadmex function is a direct way of calling MuPAD function from within Matlab – there are others, which are documented.
2. You'll notice that that the first_d output above is symfun class. We actually don't want want the output to be converted back to a symbolic function. To avoid this, we can pass an addition argument to mupadmex:
syms f(x,y)
first_d = mupadmex('symobj::jacobian',char(f),char([x,y]),0)
with now returns the string matrix([[diff(f(x, y), x), diff(f(x, y), y)]]). (I only know this trick of adding the additional 0 argument from having browsed through a lot of Symbolic Math toolbox code.)
3. From this string, we can now find and replace various patterns for partial derivatives with simple variables. The strrep function that you're using is generally a good choice for this. It is much faster than regexprep. However, if you have a large number of different, but similar, patterns to replace, you might do a performance comparison between the two. That would probably be the subject of a separate question.
I'm not sure what your overall goal is or the full extent of your problem, but here is my final code for your example:
syms f(x,y)
first_d = mupadmex('symobj::jacobian',char(f),char([x,y]),0)
first_d = strrep(first_d(9:end-2),'diff(f(x, y), x)','fx');
first_d = sym(strrep(first_d,'diff(f(x, y), y)','fy'));
This returns the symbolic vector [ fx, fy]. If you want a symfun, you'll need to modify the last line slightly. In some simple testing, this basic example is about 10% faster than calling jacobian and converting the result back to a string. If you directly specify the inputs as strings instead of allocating a symbolic function, the result is about 30% faster then your original:
first_d = mupadmex('symobj::jacobian','f(x,y)','[x,y]',0)
first_d = strrep(first_d(9:end-2),'diff(f(x, y), x)','fx');
first_d = sym(strrep(first_d,'diff(f(x, y), y)','fy'));
Using subs, as in this answer, while convenient, is the slowest approach. Converting back and forth to and from strings is costly.

Related

How do I pass a polynomial variable into a matlab function?

I am just getting started with MATLAB and I have written a function to produce the binomial expansion of (x-a)^n when given x, a and n. As far as I can tell my code should work, but I do not seem to be using the function variables correctly.
function expand(a,n,x)
f = 0;
for k = 0:1:n
f = f + nchoosek(n,k).*x.^(n-k).*(-a).^k;
end
end
I need to be able to call the function and have it output f as the expanded polynomial in x, for example calling expand(1,3,x) should return x^3-3*x^2+3*x-1, but instead, calling it gives this error:
Unrecognized function or variable 'x'. It seems like it wants me to call the function with x being another number but I in fact need it to be able to be any letter to be used as the variable in the polynomial.
I know in Maple I would specify the variable type in the function to be x::name so I'm assuming there's something similar in MATLAB that I don't yet know.
Thanks for any help.
There are two ways to go about this:
Create x as a symbolic variable. For example, syms x; expand(a,n,x). This gives you the power of using the symbolic toolbox features like simplify(), but comes with a bit of a performance penalty. You should avoid using the symbolic toolbox in intensive calculations.
Return an anonymous function, f=#(X)sum(arrayfun(#(k)nchoosek....,1:n). This has better performance and does not require double(subs(...)) when you want an actual numeric value, but may be too difficult to implement for a beginner.

Matlab: Solving a linear system of anonymous functions

I have a system of equations...
dF(a,b,c)/da = 0;
dF(a,b,c)/db = 0;
dF(a,b,c)/dc = 0;
where a,b,c are unknown variable constants and dF/d* are anonymous functions of the variables. I have to solve for a,b and c in an optimization problem. When the system reduces to just one equation, I use Matlab's fzero to solve for the variable and it works. For example
var_a = fzero(#(a) dF(a)/da,0);
After noticing that fzero and fsolve give dramatically different answers for some cases I did some searching. From what I gather, fzero only works for a single equation of a single variable? So moving to a system of equations, I'd like to choose the most appropriate method. I've used Matlab's solve in the past, but I believe that is for symbolic expressions only? What is the best method for solving a linear system of anonymous functions, which all equal zero?
I tried the following, and got back results
vars = fsolve(#(V)[dF(V)/da;dF(V)/db;dF(V)/dc],zeros(1,3));
where vars contains all 3 variables, but after reading the examples in the previous link, Fsolve couldn't exactly find the zeros for x^2 and x^3. The solution vector in the system I presented above is all zeros and the functions are polynomials. Putting this all together, I'm wondering if fsolve isn't the best choice?
Can I build a system of calls to fzero? Something along the lines of
vars = [fzero(#(a) dF(a,b,c)/da,0);
fzero(#(b) dF(a,b,c)/db,0);
fzero(#(c) dF(a,b,c)/dc,0)];
which I don't think would work (how would each dF/d* get the other 2 variable inputs?) or would it?
Any thoughts?
You can numerically solve to minimize any function using 'lsqnonlin'. To adopt this for a system of equations, simply turn them into a single function with a vector input. Something like this:
fToMinimize = #(abc) ...
(dF(ABC(1),ABC(2),ABC(3))/da)^2 +...
(dF(ABC(1),ABC(2),ABC(3))/db)^2 +...
(dF(ABC(1),ABC(2),ABC(3))/dc)^2 ;
abcSolved = lsqnonlin(fToMinimize, [0 0 0])
If you have a guess for the values of a, b, and c, you can (and should) use those instead of the [0 0 0] vector. There are also many options within the lsqnonlin function to adjust behavior. For example how close to the best answer you want to get. If the functions are well behaved, you should be able to tighten the tolerance down a lot, if you are looking for a near exact answer.

How to find the intersections of two functions in MATLAB?

Lets say, I have a function 'x' and a function '2sin(x)'
How do I output the intersects, i.e. the roots in MATLAB? I can easily plot the two functions and find them that way but surely there must exist an absolute way of doing this.
If you have two analytical (by which I mean symbolic) functions, you can define their difference and use fzero to find a zero, i.e. the root:
f = #(x) x; %defines a function f(x)
g = #(x) 2*sin(x); %defines a function g(x)
%solve f==g
xroot = fzero(#(x)f(x)-g(x),0.5); %starts search from x==0.5
For tricky functions you might have to set a good starting point, and it will only find one solution even if there are multiple ones.
The constructs seen above #(x) something-with-x are called anonymous functions, and they can be extended to multivariate cases as well, like #(x,y) 3*x.*y+c assuming that c is a variable that has been assigned a value earlier.
When writing the comments, I thought that
syms x; solve(x==2*sin(x))
would return the expected result. At least in Matlab 2013b solve fails to find a analytic solution for this problem, falling back to a numeric solver only returning one solution, 0.
An alternative is
s = feval(symengine,'numeric::solve',2*sin(x)==x,x,'AllRealRoots')
which is taken from this answer to a similar question. Besides using AllRealRoots you could use a numeric solver, manually setting starting points which roughly match the values you have read from the graph. This wa you get precise results:
[fzero(#(x)f(x)-g(x),-2),fzero(#(x)f(x)-g(x),0),fzero(#(x)f(x)-g(x),2)]
For a higher precision you could switch from fzero to vpasolve, but fzero is probably sufficient and faster.

How to solve an equation with piecewise defined function in Matlab?

I have been working on solving some equation in a more complicated context. However, I want to illustrate my question through the following simple example.
Consider the following two functions:
function y=f1(x)
y=1-x;
end
function y=f2(x)
if x<0
y=0;
else
y=x;
end
end
I want to solve the following equation: f1(x)=f2(x). The code I used is:
syms x;
x=solve(f1(x)-f2(x));
And I got the following error:
??? Error using ==> sym.sym>notimplemented at 2621
Function 'lt' is not implemented for MuPAD symbolic objects.
Error in ==> sym.sym>sym.lt at 812
notimplemented('lt');
Error in ==> f2 at 3
if x<0
I know the error is because x is a symbolic variable and therefore I could not compare x with 0 in the piecewise function f2(x).
Is there a way to fix this and solve the equation?
First, make sure symbolic math is even the appropriate solution method for your problem. In many cases it isn't. Look at fzero and fsolve amongst many others. A symbolic method is only needed if, for example, you want a formula or if you need to ensure precision.
In such an old version of Matlab, you may want to break up your piecewise function into separate continuous functions and solve them separately:
syms x;
s1 = solve(1-x^2,x) % For x >= 0
s2 = solve(1-x,x) % For x < 0
Then you can either manually examine or numerically compare the outputs to determine if any or all of the solutions are valid for the chosen regime – something like this:
s = [s1(double(s1) >= 0);s2(double(s2) < 0)]
You can also take advantage of the heaviside function, which is available in much older versions.
syms x;
f1 = 1-x;
f2 = x*heaviside(x);
s = solve(f1-f2,x)
Yes, the Heaviside function is 0.5 at zero – this gives it the appropriate mathematical properties. You can shift it to compare values other than zero. This is a standard technique.
In Matlab R2012a+, you can take advantage of assumptions in addition to the normal relational operators. To add to #AlexB's comment, you should convert the output of any logical comparison to symbolic before using isAlways:
isAlways(sym(x<0))
In your case, x is obviously not "always" on one side or the other of zero, but you may still find this useful in other cases.
If you want to get deep into Matlab's symbolic math, you can create piecewise functions using MuPAD, which are accessible from Matlab – e.g., see my example here.

Fast integration technique in matlab?

So I have the following function that I need to code:
Lm = 1/d Integral[exp(-i(a(x)t+mKx)) dx (from 0 to d)
What I have right now is:
L = (1/period) * int(exp(- 1i*(ax*t+(m*K*x))),x,0,period);
subs(L,[t,m],[beta0,tt]);
Where everything is symbolic. This takes a very long time if ax is anything challenging (sin(x)). So I would like to figure out a way to simplify this. I have an array a_x(xi) and I have been referred by colleagues to look into the quad function, but so far I am not sure how to use that.
thanks
If your integrand doesn't change (variables not a function of x) then I see no reason why you couldn't take the output of the symbolic integration and use it numerically without performing the integration:
kmp = K.*m.*period/2
L = exp(-1i*(ax.*t+kmp)).*sin(kmp)./kmp
Otherwise, yes, you should look into Matlab's quadrature integration methods – they work vary similary to sym/int, but are for numerical values and functions. In newer versions of Matab try integral or use quadgk. Something like this:
fun = #(x)exp(-1i*(ax*t+(m*K*x)));
L = (1/period)*integral(fun,0,period);
Note that for highly oscillatory functions, most quadrature methods have difficulty. You should check that your results are actually correct in such cases. If Matlab's built-in quadrature routines have trouble, you could look into Levin integration schemes or maybe this.