问题描述
我知道在MATLAB中是否已声明
syms x y
f=x^2+y^2
grad=gradient(f)
然后grad将存储值[2*x;2*y]
如果要评估[2;2]
处的梯度,请使用
subs(f,[x;y],[2,2])
这将返回[4;4]
x
和y
.我知道fminunc
和fmincon
内置的MATLAB要求将函数变量定义为x(1)
,x(2)
,x(3)
.....
我想知道如何使用syms和subs来获取具有变量x(1)
,x(2)
,...,x(n)
的函数的梯度?
看看函数symvar
.这将解析一个字符串并从中提取变量名(但不会将v(i)
解释为向量的元素;它将假定这是一个函数).例如,该函数用于解析自定义曲线拟合模型中的变量.
funstr = 'x^2+y^2';
varcell = symvar(funstr)
如果我没记错的话,
将以字典顺序返回该函数的独立变量作为一个单元格数组.幸运的是,您可以使用此单元格数组来计算梯度并随后替换为:
grad = gradient(sym(funstr),varcell);
varvec = rand(1,length(varcell));
gradval = subs(grad,varcell,varvec);
尽管gradient
会为您提供没有单元格数组输入的渐变(可能仍然使用symvar
).通过提供单元格数组varcell
到subs
,您可以严格控制变量的顺序(这对于替换很重要).
您仍然需要弄清楚背后的物流,以便将用户提供的变量的顺序与symvar
返回的顺序相匹配,但这似乎是可行的.您最好的机会可能是计算一次梯度,然后使用 matlabFunction :
matlabFunction(grad)
ans =
@(x,y)[x.*2.0;y.*2.0]
如果问题是输入数量可变,则可以强制matlabFunction
接受向量输入:
matlabFunction(grad,'vars',{sym(varcell)})
ans =
@(in1)[in1(1,:).*2.0;in1(2,:).*2.0]
出于某种原因,matlabFunction
仅在其单元格参数具有符号矢量元素的情况下才假定输入向量,这就是为什么我们需要{sym(varcell)}
将例如{'x', 'y'}
转换为{[sym('x'), sym('y')]}
的原因.
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)
?
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')]}
.
这篇关于MATLAB符号替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!