Matlab 有没有更优雅的方法来编写这些循环?

Matlab 有没有更优雅的方法来编写这些循环?,matlab,coding-style,Matlab,Coding Style,我有一个脚本,需要几个参数才能运行。我感兴趣的是随着参数的变化探索结果,因此我在顶部定义了几个scan数组,将整个代码包装成多个for循环,并将参数值设置为当前扫描值 这很容易出错,而且不雅观。更改代码的过程是:1)重置顶部的scan变量,2)注释掉例如b=scan2(j2)和3)取消注释b=b0 有什么更好的方法允许将变量设置为数组,然后为所有这些组合运行代码?现在我的代码示例: close all clear all %scan1 = linspace(1,4,10); scan1 = 0

我有一个脚本,需要几个参数才能运行。我感兴趣的是随着参数的变化探索结果,因此我在顶部定义了几个
scan
数组,将整个代码包装成多个
for循环
,并将参数值设置为当前扫描值

这很容易出错,而且不雅观。更改代码的过程是:1)重置顶部的
scan
变量,2)注释掉例如
b=scan2(j2)
和3)取消注释
b=b0

有什么更好的方法允许将变量设置为数组,然后为所有这些组合运行代码?现在我的代码示例:

close all
clear all

%scan1 = linspace(1,4,10);
scan1 = 0;
scan2 = linspace(0,1,10);
scan3 = linspace(-1,0,10);

for j3 = 1:length(scan3)
  for j2 = 1:length(scan2)
    for j1 = 1:length(scan1)

      a = a0;
      %b = scan2(j2);
      b = b0;
      %c = c0;
      c = scan3(j3);
      d = scan2(j2);

      %(CODE BLOCK THAT DEPENDS ON variables a,b,c,d...)

    end

  end

end

一种方法是使用ndgrid生成包含所有参数组合的单个向量。对于足够大的参数扫描,这可能会成为内存问题,但在其他方面至少要干净得多,只需要一个循环,以后在代码中不需要重新分配:

a0vec = 1;
b0vec = linspace(1,4,4);
c0vec = linspace(11,15,5);
d0vec = linspace(101,104,4);
e0vec = 5;

[a0s,b0s,c0s,d0s,e0s] = ndgrid(a0vec,b0vec,c0vec,d0vec,e0vec);    
N = numel(a0s);

for j = 1:N

    a0 = a0s(j);
    b0 = b0s(j);
    c0 = c0s(j);
    d0 = d0s(j);
    e0 = e0s(j);

    %__ (CODE THAT DEPENDS ON a0 - e0 here) __

end

还是想看看你的建议

一种方法是使用ndgrid生成包含所有参数组合的单个向量。对于足够大的参数扫描,这可能会成为内存问题,但在其他方面至少要干净得多,只需要一个循环,以后在代码中不需要重新分配:

a0vec = 1;
b0vec = linspace(1,4,4);
c0vec = linspace(11,15,5);
d0vec = linspace(101,104,4);
e0vec = 5;

[a0s,b0s,c0s,d0s,e0s] = ndgrid(a0vec,b0vec,c0vec,d0vec,e0vec);    
N = numel(a0s);

for j = 1:N

    a0 = a0s(j);
    b0 = b0s(j);
    c0 = c0s(j);
    d0 = d0s(j);
    e0 = e0s(j);

    %__ (CODE THAT DEPENDS ON a0 - e0 here) __

end
还是想看看你的建议

基于使用一个for循环来模拟多个循环,我尝试使其适应您的情况。虽然实现了良好的内存效率和可用性,但此解决方案比使用单个for循环要慢

%define your parameters
p.a = 1;
p.b = linspace(1,4,4);
p.c = linspace(11,15,5);
p.d = linspace(101,104,4);
p.e = 5;
iterations=structfun(@numel,p);
iterator=cell(1,numel(iterations));
for jx = 1:prod(iterations)
    [iterator{:}]=ind2sub(iterations(:).',jx);%.'
    %This line uses itertor to extract the corresponding elemets of p and creates a struct which only contains scalars.
    q=cell2struct(cellfun(@(a,b)(a(b)),struct2cell(p),iterator(:),'uniform',false),fieldnames(p));
    %__ (CODE THAT DEPENDS ON q.a to q.e here) __

end
对于我测试的场景,它在每次迭代中增加的计算开销低于
0.0002
s,总计
0.0002.*prod(iterations)
s。

基于使用一个For循环来模拟多个循环,我尝试将其适应您的情况。虽然实现了良好的内存效率和可用性,但此解决方案比使用单个for循环要慢

%define your parameters
p.a = 1;
p.b = linspace(1,4,4);
p.c = linspace(11,15,5);
p.d = linspace(101,104,4);
p.e = 5;
iterations=structfun(@numel,p);
iterator=cell(1,numel(iterations));
for jx = 1:prod(iterations)
    [iterator{:}]=ind2sub(iterations(:).',jx);%.'
    %This line uses itertor to extract the corresponding elemets of p and creates a struct which only contains scalars.
    q=cell2struct(cellfun(@(a,b)(a(b)),struct2cell(p),iterator(:),'uniform',false),fieldnames(p));
    %__ (CODE THAT DEPENDS ON q.a to q.e here) __

end


对于我测试的场景,每次迭代增加的计算开销低于
0.0002
s,总计
0.0002.*prod(迭代)
s。

在这一点上没有一般规则。代码的矢量化在很大程度上取决于循环中到底发生了什么,例如矩阵乘法、求和或其他。我不是真的想把它矢量化,我只是想要更好的组织。例如,我可以为顶部的每个参数制作一个1xN数组,避免注释,但我有点担心内存使用。。。当我经常只在一次扫描中循环时,似乎没有必要使用三重for循环。我试图理解您的代码,是否有特定的原因来枚举与您的参数不同的
scan
变量?你不能将它们重命名为
scana
scanbetc,将迭代器重命名为
ja
jb
etc吗?@Daniel这是一种可能性,但是我需要n个嵌套循环,每个a、b、c对应一个循环。目前没有通用规则。代码的矢量化在很大程度上取决于循环中到底发生了什么,例如矩阵乘法、求和或其他。我不是真的想把它矢量化,我只是想要更好的组织。例如,我可以为顶部的每个参数制作一个1xN数组,避免注释,但我有点担心内存使用。。。当我经常只在一次扫描中循环时,似乎没有必要使用三重for循环。我试图理解您的代码,是否有特定的原因来枚举与您的参数不同的
scan
变量?你不能将它们重命名为
scana
scanb等,将迭代器重命名为
ja
jb
等吗?@Daniel这是一种可能性,但是我需要n个嵌套循环,每个a、b、c对应一个循环……因为你的档案上写着
python
:使用那种语言和生成器怎么样,为了避免将所有这些值都存储在内存中?:)请注意:循环中发生了什么?“有什么复杂的,或者可以矢量化的吗?”安德拉斯达克:好建议!快速浏览一下,就会发现matlab没有类似生成器的语法。至于内存,我只运行了这些数字,100x100x100网格x20倍占用的内存不到.2 gig,所以在我的情况下可以使用。代码是~1000行,这确实是一个好的编码实践问题!事实上,我确信MATLAB不能支持类似于生成器的任何东西。如果您的参数空间总是那么小,那么您的答案似乎很合理。因为您的配置文件中说的是
python
:使用该语言和生成器如何,以避免将所有这些值存储在内存中?:)相关注释:循环中发生了什么?“有什么复杂的,或者可以矢量化的吗?”安德拉斯达克:好建议!快速浏览一下,就会发现matlab没有类似生成器的语法。至于内存,我只运行了这些数字,100x100x100网格x20倍占用的内存不到.2 gig,所以在我的情况下可以使用。代码是~1000行,这确实是一个好的编码实践问题!事实上,我确信MATLAB不能支持类似于生成器的任何东西。如果你的参数空间总是那么小,你的答案似乎很合理。很酷!我认为这是因为
结构
?在我的例子中,速度不是包装器循环的问题:我的内部代码占用的时间要多几个数量级,所以这是一个选项。单元格数组、结构、调用ind2sub,与每次迭代大约0.002s的纯for循环相比,所有这三件事都增加了开销。你的意思是
ind2sub(迭代(:)。,j)
而不是
ind2sub(迭代次数(:).”,3)
在循环的第一行?非常酷!我认为这是因为
结构
?在我的例子中,速度不是包装器循环的问题:我的内部代码占用的时间要多几个数量级,所以这将是一个选项