【问题标题】:Problem of creating function handle from the result of symbolic differentiation从符号微分的结果创建函数句柄的问题
【发布时间】:2020-09-06 08:12:20
【问题描述】:

假设我有一个简单的函数句柄定义为

Eq.1    F = @(t,A) A(1) + A(2)*t + A(3)*t^2;

而我想从F的微分中定义另一个函数句柄,比如

Eq.2:  dF = @(t,A) diff( F(t,A), t );

但是,似乎禁止在某些特定的t 上评估dF,例如dF(0,A),并且发生错误

“第二个参数必须是变量或变量”

然后我尝试使用如下所示的表达式:

Eq.3   dF(t,A) = diff( F(t,A), t );

这样,它允许在t=0 直接评估

但是,它必须采用dF( 0, A(1), A(2), A(3) ) 的形式来评估Eq.3 而不是dF(0,A)

我的问题是:

有没有一种更简单的方法可以使用直接形式 dF(0,A) 而不是 dF(0, A(1), ... ) 进行这种直接评估

为了省去在dF( 0, A(1), A(2), ..., A(100) ) 中逐一键入A(...) 的工作,假设有100 个参数

PS: 不使用matlabFunction


测试代码如下:

syms t A a0 a1 a2

A = [a0,a1,a2];

F = @(t,A) A(1) + A(2)*t + A(3)*t^2;

dF1      =          @(t,A) diff( F(t,A), t );

dF2(t,A) =                 diff( F(t,A), t );                   % Same as using symfun

dF3      = matlabFunction( diff( F(t,A), t ), 'Vars', {t,A} );

现在,在命令窗口中输入,

>> dF1(t,A)
>> ans = a1 + 2*a2*t

>> dF1(0,A)
>> ans = a0               % This is wrong

>> dF3(t,A)
>> ans = a1 + 2*a2*t

>> dF3(0,A)
>> ans = a1               % This is correct

>> dF2(t,A)
   Error using symfun/subsref (line 141)
   Symbolic function expected 4 inputs and received 2.

>> dF2(t,a0,a1,a2)
>> ans = a1 + 2*a2*t

>> dF2(0,a0,a1,a2)
>> ans = a1               % This is correct

很明显,只有dF2是一个符号函数。 但是,input 的形式似乎不是那么友好。

matlabFunction 的运行速度比symfun 慢得多,并且@(x,A) diff(...) 不能接受数值结果。这就是为什么我想使用symfun 来定义一个参数太多的函数。然而符号函数的输入形式似乎并不那么直接和友好。

【问题讨论】:

  • 有两个不同的diff 函数。符号微分需要使用 syms 参数调用,以便调用 Symbic Toolbox 中的 diff 函数。当使用数字输入调用时,它会计算数组中后续元素之间的差异。
  • @CrisLuengo 抱歉,我没有说清楚。 Eq.3 是可用的,但我必须输入 dF( 1.0, A(1), A(2), ... ) 来获得结果,而不是直接输入 dF( 1.0, A )。我的问题是可以避免键入 A 的所有元素,而不使用 matlabFunction(花费太多时间)
  • 我不明白你在说什么,也不明白为什么你必须输入 A 的所有元素。能否请edit 你的帖子包含一些实际代码?这将使谈论这个问题变得容易得多。
  • @CrisLuengo 我添加了一些测试代码。我正在使用 MATLAB 2015b,不知道最新版本是否出现类似问题。我只想以一种有效的方式定义一个具有许多参数的符号函数,并使其更容易评估具有太多输入的函数。非常感谢你教我!
  • 我已经重写了我的答案。

标签: matlab symbolic-math derivative


【解决方案1】:

您的问题已回答over at MATLAB Answers。简而言之:这是做不到的。 您不能创建使用数组作为输入的符号函数:

这一切都反映了符号引擎的一个基本的内部限制:符号引擎的内部没有提供描述或操作“数组”的规定,其内容将在以后填充。

链接的帖子非常详细地解释了 MATLAB 中符号引擎的工作原理和方式。我建议你阅读它。


您的代码对符号函数和匿名函数存在一些误解。当你这样做时

F = @(t,A) A(1) + A(2)*t + A(3)*t^2;

您正在创建匿名函数的函数句柄。它与符号变量tA 完全无关,也不是符号函数。这里tA只是输入参数,可以任意填写。

接下来,

dF1 = @(t,A) diff( F(t,A), t );

为匿名函数创建另一个函数句柄,这次函数将评估x=F(t,A),然后调用diff(x,t),其中diffthe normal function,而不是符号工具箱中的那个。它计算后续数组元素之间的差,t 次。

要创建一个符号函数,你可以这样做:

clear
syms t
A = sym('a', [1,3]);        % A = [a1, a2, a3]
F = symfun(A(1) + A(2)*t + A(3)*t^2, [t, A]);
dF = diff(F, t);
dF(0, A(1), A(2), A(3))     % returns a2

但是,这会创建一个符号函数,其中A 的每个元素都是一个单独的输入参数,这不是您想要的。没有办法解决这个问题,除非,正如我在顶部链接的帖子的答案中所建议的那样,创建一个匿名函数来评估您的符号表达式:

clear
syms t
A = sym('a', [1,3]);
F = symfun(A(1) + A(2)*t + A(3)*t^2, [t, A]);
dF_sym = diff(F, t);
dF = @(t,A)dF_sym(t, A(1), A(2), A(3));
dF(0, A)                    % returns a2

PS:请注意,上面的symfun 调用等同于:

clear
syms t F(t,a1,a2,a3)
F(t,a1,a2,a3) = a1 + a2*t + a3*t^2;

这就是您通常创建符号函数的方式。我在上面使用了symfun,以便能够使用A 而不是a1a2a3

【讨论】:

  • 非常感谢! 'dF = @(t,A)dF_sym(t, A(1), A(2), A(3))' 解决了我的问题。
【解决方案2】:

看来你只是把一些事情搞混了。 您anonymous function 的定义很好,但我认为它们不代表您的预期用途。

函数diff 计算向量中的差异 或者这样做 n 次第二个参数指定后者:

Y = diff(X,n) 通过应用 diff(X) 计算第 n 个差异 运算符递归 n 次。实际上,这意味着 diff(X,2) 是 与 diff(diff(X)) 相同。

所以很明显diff(...,0) 会引发错误(“计算某物的第 0 个差异”)。 我不禁想到这不是你想要的(因为在原始函数F 中使用t 没有意义......)。我假设t 是一个时间(向量)

也许这更适合你的问题:

F = @(t,A) A(:,1) + A(:,2).*t + A(:,3).*t.^2; % vector-wise
dF = @(t,A) diff(F(t,A),[],1)./diff(t,[],1); % row-wise difference

所以你可以这样做

t = (1:10).'; % 10 rows = 10 time steps
A = rand(length(t),3);

% call dF: approximating the 1st derivative as finite difference (row-wise)
dF(t,A)

PS:那些不是 symbolic 函数,而只是 匿名函数句柄,即指向函数的指针(有一个单独的 Symbolic Math Toolbox 和要获取函数句柄的符号数学函数,可以使用matlabFunction 函数)

【讨论】:

  • 赞成对问题的解释。建议的解决方案虽然不是很好。它需要 F 来接受数组输入,并且它不会产生非常精确的导数估计(当然取决于函数的陡度)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 2014-01-31
  • 1970-01-01
  • 2012-05-09
相关资源
最近更新 更多