未知维度矩阵的索引化

10
我是一名有用的助手,可以为您翻译文本。

我有一个非固定维度的矩阵M,我想要访问单个元素。

这个元素的索引包含在向量J中。

例如:

M = rand(6,4,8,2);
J = [5 2 7 1];

output = M(5,2,7,1)

这一次M有4个维度,但事先并不知道。这取决于我正在编写的算法设置。同样也可能是

M = rand(6,4);
J = [3 1];

output = M(3,1)

所以我不能简单地使用

output=M(J(1),J(2))

我在考虑使用sub2ind,但这也需要将其变量用逗号分隔...
@gnovice 这个方法可以实现,但我打算经常从矩阵M中提取这种元素。所以如果每次访问M都要创建一个临时变量cellJ,这会不会极大地减慢计算速度?
我也可以编写一个单独的函数。
function x= getM(M,J)
    x=M(J(1),J(2));
    % M doesn't change in this function, so no mem copy needed = passed by reference
end

请注意,这是关于算法不同配置的速度与灵活性考虑的问题。当然,这只适用于获取元素,对于设置元素来说,除了实际使用索引(最好是线性索引)之外,没有其他方法。我仍然认为sub2ind是一个选项。我最终想要的结果是这样的:
function idx = getLinearIdx(J, size_M)
    idx = ...
end

结果:

function lin_idx = Lidx_ml( J, M )%#eml
%LIDX_ML converts an array of indices J for a multidimensional array M to
%linear indices, directly useable on M
%
% INPUT
%   J       NxP matrix containing P sets of N indices
%   M       A example matrix, with same size as on which the indices in J
%           will be applicable.
%
% OUTPUT
%   lin_idx Px1 array of linear indices
%

% method 1
%lin_idx = zeros(size(J,2),1);
%for ii = 1:size(J,2)
%    cellJ = num2cell(J(:,ii)); 
%    lin_idx(ii) = sub2ind(size(M),cellJ{:}); 
%end

% method 2
sizeM = size(M);
J(2:end,:) = J(2:end,:)-1;
lin_idx = cumprod([1 sizeM(1:end-1)])*J;

end

方法2比方法1快20到80倍(对于需要转换的索引集数量较少(=P)的情况下,速度提升更为明显)。很容易做出选择。


是的,我误解了你的问题,@gnovice的答案很好地解决了这个问题。 - ely
2个回答

12

对于一般情况,其中J可以是任意长度(我假设它始终与M中的维数相匹配),您有几个选项:

  1. You can place each entry of J in a cell of a cell array using the num2cell function, then create a comma-separated list from this cell array using the colon operator:

    cellJ = num2cell(J);
    output = M(cellJ{:});
    
  2. You can sidestep the sub2ind function and compute the linear index yourself with a little bit of math:

    sizeM = size(M);
    index = cumprod([1 sizeM(1:end-1)]) * (J(:) - [0; ones(numel(J)-1, 1)]);
    output = M(index);
    

刚刚编辑完问题,谢谢! 我认为如果我在配置中将其编译为emlmex函数,计算工作量将是最小的 :) 当我有更多实现时,我会发布结果。 - Gunther Struyf
1
@GuntherStruyf:很高兴能帮忙,尽管我觉得这可能只是微小的优化。我猜你的代码性能瓶颈不会是在索引矩阵上花费的时间,所以这些解决方案都应该很好。 - gnovice
1
可能,但是每一个小的改进都是受欢迎的。 8小时的计算时间真的很长 :P - Gunther Struyf
4
你可以使用 MATLAB 分析器找出程序的瓶颈并进行优化,优化重点不在于数组索引,因为它只占用运行时间的 0.1%。即使你完全消除了这个开销,你的总运行时间减少的也只有 30 秒。相反,尽可能将所有东西向量化,在可能的情况下使用MATLAB内置的C语言函数,在循环开始前预先分配数组等操作都能够大幅提高性能。 - Li-aung Yip
我只想让我的代码“干净”,不喜欢快速而肮脏的解决方案,当更好的解决方案存在时(需要更多的努力)。在这种情况下,我认为num2cell方法是一种快速而肮脏的方式,另一种方式是索引计算。 我很高兴在这种情况下有一个如此简单和整洁的解决方案。我熟悉分析器,但还是谢谢你的建议。我正在构建一个新的解决框架来解决优化问题,因为旧框架充满了这样的快速而肮脏的修复程序,总体上很慢 :/ - Gunther Struyf

0
这是gnovices选项2)的一个版本,它允许处理一个包含多个下标的矩阵,其中每一行包含一个下标。例如,对于3个下标:
J = [5 2 7 1 
     1 5 2 7
     4 3 9 2];

sizeM = size(M);
idx = cumprod([1 sizeX(1:end-1)])*(J - [zeros(size(J,1),1) ones(size(J,1),size(J,2)-1)]).';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接