FOIWATER
FOIWATER

Reputation: 63

MATLAB symbolic substitution

I know that in MATLAB if it is declared

syms x y
f=x^2+y^2
grad=gradient(f)

Then grad will store value [2*x;2*y]

If I want to evaluate the gradient at [2;2] I use

subs(f,[x;y],[2,2])

This returns [4;4]

I am coding a steepest descent algorithm that needs to be generic enough to take any function. I am wondering how to generically make use of syms and subs. Considering that some functions might not use the variables I have declared, like x and y.

I know that MATLAB built in fminunc and fmincon require that the function variables be defined as x(1),x(2),x(3).... for that reason.

I am wondering how to use syms and subs to take the gradient of a function with variables x(1),x(2),...,x(n)?

Upvotes: 0

Views: 633

Answers (1)

Have a look at the function symvar. This will parse a string and extract variable names from it (but it will not interpret v(i) as an element of a vector; it will assume that's a function). This is the same function used, for instance, to parse the variables in a custom curve fitting model.

funstr = 'x^2+y^2';
varcell = symvar(funstr)

will return the independent variables of the function as a cell array, in lexicographical order if I'm not mistaken. Fortunately you can use this cell array to both compute the gradient and subsequently substitute:

grad = gradient(sym(funstr),varcell);
varvec = rand(1,length(varcell));
gradval = subs(grad,varcell,varvec);

although gradient will give you a gradient without the cell array input (probably using symvar anyway). By providing the cell array varcell to subs, you can have a tight control on the order of variables (which is probably important for substitution).

You still have to figure out the logistics behind it, in order to match the order of variables provided by the user with the order returned by symvar, but it seems feasible. Your best chance is probably computing the gradient once, then constructing an anonymous function from it to be used in the actual (numerical) descent using matlabFunction:

matlabFunction(grad)

ans = 

    @(x,y)[x.*2.0;y.*2.0]

If the problem is with variable number of inputs, you can force matlabFunction to accept vector input:

matlabFunction(grad,'vars',{sym(varcell)})

ans = 

    @(in1)[in1(1,:).*2.0;in1(2,:).*2.0]

For reasons, matlabFunction only assumes vector input if its cell argument has a symbolic vector element, this is why we need {sym(varcell)} to convert, for instance, {'x', 'y'} into {[sym('x'), sym('y')]}.

Upvotes: 3

Related Questions