从 MATLAB 中 fsolve 使用的目标函数获取额外的输出参数

计算科学 优化 matlab 非线性方程 迭代法
2021-12-26 17:44:47

我有一个 MATLAB 代码(见下文),它使用优化工具箱中的“fsolve”来解决求根问题。

瓶颈在于,在目标函数计算中,有一个计算量很大的函数(在下面的代码中表示为“expensive_function”,位于 matlabpath 中)。变量“x_sol”保存“fsolve”返回的解。

问题是,在主代码中,我需要访问由昂贵函数计算的“other_results”结构以进行进一步计算。使用解值重新计算 'other_results' 结构是很浪费的(例如在 'main' 中使用以下代码行)

other_results = expensive_function(x_sol,param);

有没有办法在不重新评估昂贵函数的情况下访问这个结构?

PS:在我的整个职业生涯中,我一直被警告不要使用全局/持久变量,到目前为止我一直远离它们。我不知道这是否是解决此问题的唯一方法,还是存在更好/更聪明的方法?

%% main code

x_sol = fsolve(@(x) compute_residual(x,param) , x0);

% code below needs to use various values from the "other_results" struct computed in the obj_fun  function

line with some computation on 'other_results' result
line with some other computation using 'other_results' struct
....
...
and so on.


________________________________________________________

function residual = compute_residual(x, param)
     other_results = expensive_function(x,param);  % other_results is a struct returned by a very computationally expensive function
     residual = abs(other_results.a * other_results.b - x)   % the abs(diff) 
end
1个回答

正如我在评论中所说,我认为您不一定可以指望 x最后一次调用函数的值是作为解决方案返回的值。

但是,话虽如此,这是一种做你想做的事的方法。我在下面显示的代码中的解决方案依赖于两个组件。首先,您定义一个派生自 的 MATLAB 类handle这使它成为所谓的句柄类,因此当它作为参数传递给函数时,它是通过引用传递的,因此它的内容可以由该函数修改。其次,匿名函数定义用于将此类的实例传递给您的fsolve函数,以便您可以将解决方案存储在那里。下面的示例代码明确显示了这一点。

类定义是

classdef SolutionSaver < handle
  properties
    x, expensiveResult;
  end
end

而使用这个类的测试用例是

function solutionSaveTest
   ss = SolutionSaver;
   func = @(x) calcF(x, ss);
   x = fsolve(func, 1);
   fprintf('x=%18.10e, ss.x=%18.10e\n', x, ss.x);
   ss.expensiveResult
end

function f=calcF(x, ss)
  e=expensive_calc(x);
  f = e - 5;
  ss.x = x;
  ss.expensiveResult = e;
end

function e=expensive_calc(x)
  e = x^2;
end

我在 Octave 中运行了这个示例,在这种情况下,保存x 值等于返回的x. 但是,一般来说,在使用保存的解决方案数据之前可能值得测试该事实。