Matlab函数处理工作区恶作剧

2024-02-27

In short:有没有一种优雅的方法来限制匿名函数的范围,或者Matlab在这个例子中被破坏了?

我有一个函数可以创建要在管网求解器中使用的函数句柄。它将网络状态作为输入,其中包括有关管道及其连接的信息(或者如果必须的话,还可以包括边和顶点),构造一个大字符串,该字符串在函数形式时将返回一个大矩阵,并“评估”该字符串以创建句柄。

function [Jv,...] = getPipeEquations(Network)
... %// some stuff happens here

Jv_str = ['[listConnected(~endNodes,:)',...
    ' .* areaPipes(~endNodes,:);\n',...
    anotherLongString,']'];

Jv_str = sprintf(Jv_str); %// This makes debugging the string easier

eval(['Jv = @(v,f,rho)', Jv_str, ';']);

该函数按预期工作,但是每当我需要保存包含该函数句柄的后续数据结构时,它都需要一个荒谬的内存量 (150MB) - 巧合的是,大约与创建此函数时的整个 Matlab 工作区一样多 (~150MB)。该函数句柄所需的 getPipeEquations 工作区中的变量并不是特别大,但更疯狂的是,当我检查函数句柄时:

>> f = functions(Network.jacobianFun)
f = 

     function: [1x8323 char]
         type: 'anonymous'
         file: '...\pkg\+adv\+pipe\getPipeEquations.m'
    workspace: {2x1 cell}

...工作区字段包含 getPipeEquations 拥有的所有内容(顺便说一下,not整个 Matlab 工作区)。

如果我将 eval 语句移至子函数以尝试强制作用域,则句柄将保存得更紧凑(~1MB):

function Jv = getJacobianHandle(Jv_str,listConnected,areaPipes,endNodes,D,L,g,dz)
eval(['Jv = @(v,f,rho)', Jv_str, ';']);

这是预期的行为吗?有没有更优雅的方法来限制这个匿名函数的范围?

作为附录,当我多次运行包含此函数的模拟时,清理工作区变得非常慢,这可能与 Matlab 对函数及其工作区的处理有关,也可能无关。


我可以重现:对我来说,匿名函数正在捕获以下副本all封闭工作区中的变量,而不仅仅是匿名函数表达式中引用的变量。

这是一个最小的重现。

function fcn = so_many_variables()
a = 1;
b = 2;
c = 3;
fcn = @(x) a+x;
a = 42;

事实上,它捕获了整个封闭工作空间的副本。

>> f = so_many_variables;
>> f_info = functions(f);
>> f_info.workspace{1}
ans = 
    a: 1
>> f_info.workspace{2}
ans = 
    fcn: @(x)a+x
      a: 1
      b: 2
      c: 3

起初这让我感到惊讶。但仔细想想,这是有道理的:因为存在feval and eval,Matlab 在构造时实际上无法知道匿名函数实际上最终将引用哪些变量。因此,它必须捕获范围内的所有内容,以防它们被动态引用,就像在这个人为的示例中一样。这使用了值foo但在您调用返回的函数句柄之前,Matlab 不会知道这一点。

function fcn = so_many_variables()
a = 1;
b = 2;
foo = 42;
fcn = @(x) x + eval(['f' 'oo']);

您正在执行的解决方法 - 将函数构造隔离在具有最小工作空间的单独函数中 - 听起来像是正确的修复方法。

这是获取受限工作空间来构建匿名函数的通用方法。

function eval_with_vars_out = eval_with_vars(eval_with_vars_expr, varargin)

% Assign variables to the local workspace so they can be captured
ewvo__reserved_names = {'varargin','eval_with_vars_out','eval_with_vars_expr','ewvo__reserved_names','ewvo_i'};
for ewvo_i = 2:nargin
    if ismember(inputname(ewvo_i), ewvo__reserved_names)
        error('variable name collision: %s', inputname(ewvo_i));
    end
    eval([ inputname(ewvo_i) ' = varargin{ewvo_i-1};']);
end
clear ewvo_i ewvo__reserved_names varargin;

% And eval the expression in that context
eval_with_vars_out = eval(eval_with_vars_expr);

这里的长变量名会损害可读性,但会降低与调用者变量发生冲突的可能性。

您只需调用 eval_with_vars() 而不是 eval(),并将所有输入变量作为附加参数传递。这样您就不必为每个匿名函数构建器键入静态函数定义。只要您预先知道实际要引用哪些变量,这就会起作用,这与使用方法的限制相同getJacobianHandle.

Jv = eval_with_vars_out(['@(v,f,rho) ' Jv_str],listConnected,areaPipes,endNodes,D,L,g,dz);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Matlab函数处理工作区恶作剧 的相关文章

  • 傅里叶变换定理 matlab

    我目前正在尝试理解二维傅里叶位移定理 根据我到目前为止所了解到的情况 图像空间中的平移会导致相位差异 但不会导致频率空间中的幅度差异 我试图用一个小例子来演示这一点 但它只适用于行的移位 而不适用于列的移位 这是一个小演示 我只在这里显示幅
  • 通过傅里叶空间填充进行插值

    我最近尝试在 matlab 上实现一个在傅立叶域中使用零填充的插值方法的简单示例 但我无法正常工作 我总是有一个小的频移 在傅里叶空间中几乎不可见 但它在时空上产生了巨大的误差 由于傅里叶空间中的零填充似乎是一种常见 且快速 的插值方法 因
  • 同时重新排序和旋转图像的高效方法

    为了快速加载 jpeg 我为turbojpeg 实现了一个 mex wrapper 以有效地将 大 jpeg 读入 MATLAB 对于 4000x3000px 的图像 实际解码只需要大约 120 毫秒 而不是 5 毫秒 然而 像素顺序是 R
  • 在 Matlab 中显示有理数

    我有两个整数 m n 它们一起形成 m n 形式的有理数 现在我只想以这种理性的形式在 Matlab 中显示它们 我可以通过这样做来做到这一点 char sym m n 所以 如果 例如m 1 n 2 Matlab将显示1 2 然而 如果m
  • 如何获取调用函数的“this”值?

    如果我有一个这样的函数 function foo this console log this function bar bar prototype func function foo this var test new bar test f
  • Matlab Solve():未给出所有解决方案

    我试图找到两条曲线的交点 syms x y g x 20 exp x 30 3 5 1 sol x sol y solve x 22 3097 2 y 16 2497 2 25 y g x x y Real true 它只提供一种解决方案
  • 如何在Matlab中将世界坐标转换为像素索引

    我有 512x512x313 体积的 dicom 图像 并且我有一个以世界坐标表示的点 57 7475 63 4184 83 1515 我如何在 Matlab 中获得该世界坐标的相应像素坐标 我不想戳破你的幻想 但你所要求的是不可能的 我能
  • Javascript 闭包与 PHP 闭包,有什么区别?

    JS 中的闭包和 PHP 中的闭包有什么区别 它们的工作方式几乎相同吗 在 PHP 中编写闭包时有什么需要注意的注意事项吗 一个区别是两者如何处理存储执行匿名函数的上下文 JavaScript var a 1 var f function
  • 定义自定义 Mupad 程序的一般相对搜索路径

    假设我有一个 mupad 笔记本myMupadNotebook mn在路径上 C projectFolder ABC abc 它调用程序MyMupadProcedure mu它位于 C DEF GHI 现在我有一个 Matlab 脚本mai
  • 垂直子图的单一颜色条

    我想让下面的 MATLAB 图有一个沿着两个子图延伸的颜色条 像这样的事情 使用图形编辑器手动完成 Note 这与提出的问题不同here https stackoverflow com questions 39950229 matlab t
  • Clojure:让作用域和函数返回值

    我在弄清楚如何使用 let 形式时遇到了一些麻烦 在下面的示例中 我想在本地绑定值 cols 以便稍后在函数中处理它 然而 我注意到 如果我使用 let 函数 sel opt tmp 将返回 nil 值而不是列表 defn sel opt
  • 如何为已编译的 MATLAB 创建安装程序并要求用户接受我们的许可条款?

    我正在 MATLAB 中编写程序分发给 Windows 用户 我使用 MATLAB 编译器和 MATLAB r2014a 版本来创建程序 我可以使用 MATLAB 应用程序编译器创建 Windows 安装程序 并且它的工作效果可以接受 但是
  • 在 Matlab 的命令窗口中获取旧式帮助

    问题的简短版本 在最新版本的 Matlab 中 我在 Windows 上的 R2014b 和 R2015a 中看到过 当您键入help foo你得到一个简要描述 简介函数及其签名 例如 输入help bsxfun产生类似这样的东西 只有更好
  • 在Matlab中对字符进行分组并形成矩阵

    我有 26 个字符 A 到 Z 我将 4 个字符组合在一起 并用空格分隔以下 4 个字符 如下所示 abcd efgh ijkl mnop qrst uvwx yz 我的Matlab编码如下 str abcdefghijklmnopqrst
  • 带有闭包的 JavaScript 性能

    var name function n var digits one two three four return digits n var namenew function digits one two three four return
  • 如何在向量中的所有点之间绘制线?

    我有一个包含二维空间中一些点的向量 我希望 MATLAB 用从每个点到每个其他点绘制的线来绘制这些点 基本上 我想要一个所有顶点都连接的图 你能用情节来做到这一点吗 如果可以 怎么做 一种解决方案是使用该函数为每个点组合创建一组索引MESH
  • 如何在 CF10 中确定闭包变量的范围?

    引自Adobe ColdFusion 10 使用闭包文档 http help adobe com en US ColdFusion 10 0 Developing WSe61e35da8d31851842acbba1353e848b35 8
  • 命令 A(~A) 在 matlab 中的真正作用是什么

    我一直在寻找找到矩阵非零最小值的最有效方法 并在论坛上找到了这个 设数据为矩阵A A A nan minNonZero min A 这是非常短且高效的 至少在代码行数方面 但我不明白当我们这样做时会发生什么 我找不到任何关于此的文档 因为它
  • for 循环中的绘图没有可见点

    我正在努力解决我想使用 for 循环制作的情节 我知道当我在循环之后添加它时它会起作用 只是一个简单的图 但我想用另一种方式尝试一下 fib ones 1 10 for k 3 10 hold on fib k fib k 1 fib k
  • 如何为 jQuery 插件设置私有变量?

    我想创建一个简单的插件 它使用元素的文本作为默认值 或者您可以在调用插件时设置此值 但是 如果我不设置该值 并为多个元素调用插件 则默认值会成倍增加 function fn reText function options var setti

随机推荐