在MatLab

时间:2016-09-04 10:11:35

标签: matlab matrix octave diagonal

我需要在矩阵中获取所有对角线的索引。矩阵可以是非正方形。

diag函数给出了值,但我需要coords。例如,[1 2 3; 4 5 6; 7 8 9],我希望[1 1; 2 2; 3;3][2 6]3,因为它们是矩阵的上对角线,下面也是[4 8] }和7。所以索引的完整列表是:[1 1; 2 2; 3 3], [1 2; 2 3], [1 3], [2 1], [3 2], [3 1]

我也需要在另一个对角线方向......

它需要适用于任何形状的矩阵,即不仅仅是方形矩阵,包括矢量(即1xn和nx1) - 但我想我可以测试最后2个案例并单独处理。

编辑: 非方矩阵的一个例子是这个3x2矩阵:

1   2
3   4
5   6

在这种情况下,我需要的索引是:

[1 1; 2 2]
[2 1; 3 2]
[1 2]
[3 1]

然后对于以对方方式运行的对角线也一样......

我知道diag函数并且可以编写一些代码来迭代矩阵,但我不能看到如何轻松地将这些值转换为索引。

至于为什么我需要这个:这是我在MatLab做的在线课程。使用MatLab介绍编程。我是一位经验丰富的程序员,但我不熟悉MatLab,我想学习更多。

这个问题要求我们找到任何方向上任何n个数字的最大乘积,即行,列和对角线(双向)。事情是我们不返回产品,我们返回构成该产品的元素的索引。

我希望这能提供更多信息。

编辑2: 很抱歉没有回复你们,我一直忙于做其他事情。当我第一次发布这里时,我认为我错过了一些东西,这将是一些需要几行的东西。但它比那更棘手,所以你们发布的代码将花费我更多的时间来了解并理解等等。但我希望今天这样做并接受一个作为答案。感谢所有的回复。

5 个答案:

答案 0 :(得分:0)

不要忘记Matlab理解线性索引到多维矩阵。对于OP的3*3(我们称之为a)矩阵的示例,表达式a(3)标识与a(3,1)相同的元素(Matlab使用列主要布局)。因此,对于k*k矩阵,表达式

[1, k+2, 2k+3, 3k+4, ...]

给出主对角线上元素的索引。有多种方法可以生成该向量。然后,ind2sub的明智应用将使2-d指数成为同一矩阵。

将这种方法概括为其他对角线和非方形矩阵应该不会太难。

答案 1 :(得分:0)

这是“西北到东南”对角线的解决方案。

A = [1,2,3,4,5;6,7,8,9,10;11,12,13,14,15];  
rows = size (A,1);   cols = size (A,2);   padding = rows - 1; 
padded = [ones(rows, padding), A, ones(rows, padding)];

% Create a Helper array containing column/row pairs and a product
Helper = zeros (cols + padding, rows * 2 + 1);
for i = 1 : cols + padding;  % i moves along columns of the padded array
  i0 = i - padding; % "actual" index w.r.t A, where leftmost index is 1-padding
  c  = 1;       % a counter used for filling current "Helper" row appropriately
  for j = 1 : rows;       % j moves along rows
    Helper(i, c)   = i0;  % store current "actual" column
    Helper(i, c+1) = j;   % store current row
    c  = c  + 2;          % move to next 2 slots in "Helper"
    i0 = i0 + 1;          % move to next "actual" column for processing
  end 

  % Process product at appropriate indices
  Helper(i, end) = prod (padded (sub2ind (       ...
                     size (padded),              ...
                     Helper(i,2:2:end-1),        ...
                     Helper(i,1:2:end-1)+padding ...
                   )));
end

% Isolate the correct indices for which the product is largest
[~, biggest] = max (Helper(:, end)); % column index of largest product in Helper
Pairs = reshape (Helper(biggest, 1:end-1), 2, []); % collect indices
Pairs = fliplr (Pairs.');                          % express as rows/cols

% Remove pairs where column occurs in the "padded" zone
for i = 1 : size (Pairs, 1)
  if Pairs(i, 1) < 1 || Pairs(i, 1) > cols; Pairs(i, :) = []; end
end

display(Pairs)

如果您了解这背后的逻辑,那么“NorthEast to SouthWest”对角线也应该是一块蛋糕。我会留下让你弄明白:)

答案 2 :(得分:0)

执行此操作的简单方法是构造一个与输入形状相同的数组,其中每个元素的值都是其索引。然后你可以得到每个对角线的值(索引)。

function diag_cell = alldiags(A)    
   [m,n] = size(A);

   M = reshape(1:m*n, m, n);   % construct array of indices
   % there are (m-1) diagonals below the main (k parameter negative)
   %   and (n-1) diagonals above, plus 0 for the main diagonal
   for d = 1-m:n-1
      C1{d+m} = diag(M, d);   % store in C1{1}..C1{m+n-1}
   end

   % to get the antidiagonals, rotate the index matrix `M` and repeat
   %   (remember to swap `m` and `n`):
   M = rot90(M);
   for d = 1-n:m-1
      C2{d+n} = diag(M, d);
   end

   diag_cell = {C1{:}, C2{:}};   % concatenate the cell arrays and return
end

这是使用3x3样本矩阵的测试运行:

A =

   1   2   3
   4   5   6
   7   8   9

>> alldiags(A)
ans =
{
  [1,1] =  3
  [1,2] =

     2
     6

  [1,3] =

     1
     5
     9

  [1,4] =

     4
     8

  [1,5] =  7
  [1,6] =  1
  [1,7] =

     4
     2

  [1,8] =

     7
     5
     3

  [1,9] =

     8
     6

  [1,10] =  9
}

如果你真的需要,你可以随时将所有索引转换为下标,但是如果你正在访问原始矩阵,那么使用索引可能更容易。这是一个将主对角线转换为下标的示例:

>> C{3}
ans =

   1
   5
   9

>> [r,c] = ind2sub(size(A), C{3});
>> subs = [r c]
subs =

   1   1
   2   2
   3   3

这是一个例子来说明为什么会这样。我们采用随机的6x3矩阵A

A =

   0.634825   0.560609   0.926716
   0.049504   0.226152   0.748278
   0.746754   0.493896   0.773868
   0.993245   0.457522   0.412092
   0.430003   0.695042   0.641917
   0.935298   0.960166   0.022872

函数做的第一件事是获取输入矩阵A的大小,并创建一个相同大小的新矩阵,使每个元素的值等于其线性索引。线性索引从下标1的{​​{1}}开始,将列向下增加到[1,1]的{​​{1}},然后转到m寻找下标[m,1],在下标m+1的索引[1,2]处结束。

m*n

此矩阵的输出[m,n]如下所示(重新格式化,因此更容易一次看到所有内容):

>> [m,n] = size(A)
m =  6
n =  3
>> M = reshape(1:m*n, m, n)
M =

    1    7   13
    2    8   14
    3    9   15
    4   10   16
    5   11   17
    6   12   18

条目的前半部分是正常对角线(左上角到右下角),后半部分是反对角线(从右上角到左下角)。

举个例子,走对角线diag_cell。您可以查看矩阵diag_cell = { [1,1] = 6 [1,2] = 5 12 [1,3] = 4 11 18 [1,4] = 3 10 17 [1,5] = 2 9 16 [1,6] = 1 8 15 [1,7] = 7 14 [1,8] = 13 [1,9] = 1 [1,10] = 7 2 [1,11] = 13 8 3 [1,12] = 14 9 4 [1,13] = 15 10 5 [1,14] = 16 11 6 [1,15] = 17 12 [1,16] = 18 } 以查看这些索引引用的元素。

diag_cell{4} = [3; 10; 17]

此对角线从M开始,到A = 0.634825 0.560609 0.926716 0.049504 0.226152 0.748278 *0.746754* 0.493896 0.773868 0.993245 *0.457522* 0.412092 0.430003 0.695042 *0.641917* 0.935298 0.960166 0.022872 结束。如果我们从[3,1]恢复值,我们会得到:

[5,3]

答案 3 :(得分:0)

这个解决方案一直到你的最终任务 - 找到矩阵中任何向量的最大乘积的索引:

function out = maxVecProd(A)
% validate the input is a vector\matrix:
assert(ismatrix(A),'Input must be a vector or matrix')
[cmax,cind] = max(prod(A,1)); % find where the maximum prod in the columns
[rmax,rind] = max(prod(A,2)); % find where the maximum prod in the rows
if all(size(A))>1 % if its a matrix:
    all_d = -(size(A,1)-1):(size(A,1)-1); % get all the valid diagonals
    pd = zeros(2*numel(all_d),2); % the solution of all products
    c = 1;
    for d = all_d
        pd(c,1) = prod(diag(A,d)); % get the diagonal product
        pd(c,2) = prod(diag(fliplr(A),d)); % get the anti-diagonal product
        c = c+1;
    end
    [dmax,dind] = max(pd(:)); % find where the maximum prod in the diagonals
    % get the orientation of the maximum prod (column, row, diagonal)
    [~,dirmax] = max([rmax,cmax,dmax]);
else
    [~,dirmax] = max([rmax,cmax]);
end
switch dirmax
    case 1
        % create the indices for the maximum row:
        out = [repelem(rind,size(A,2)).' (1:size(A,2)).'];
    case 2
        % create the indices for the maximum column:
        out = [(1:size(A,1)).' repelem(cind,size(A,1)).'];
    case 3
        [r,dir] = ind2sub(size(pd),dind); % convert to [row,column]
        d_ind = all_d(r); % find which value of d gave the maximum product
        [R,C] = ndgrid(1:size(A,1),1:size(A,2)); % create a grid of all indices
        if dir==1
            % find the indices for a diagonal:
            out = [diag(R,d_ind),diag(C,d_ind)];
        else
            % find the indices for an anti-diagonal:
            out = [diag(fliplr(R),d_ind),diag(fliplr(C),d_ind)];
        end
end
end

你得到maxVecProd(A)

out =
     1     2
     2     2
     3     2

这意味着最大的产品是(1,2),(2,2)和(3,2)中的元素。

答案 4 :(得分:0)

好的,所以我昨晚自己编了代码。它很长,我相信它可以以更好的方式完成。我不太了解MatLab,所以我的解决方案很天真。但它确实有效。

function indicies = maxproduct(A, n)


function diagIndicies = getAllReverseDiagonalIndicies()
    % This function returns lists of indicies in the reverse diagonal direction (top-right to bottom-left)
    if rows == 1 
        numCells = 0;
        for j=1:length(A)
            temp = [1, j];
            numCells = numCells + 1;
            diagIndicies{numCells} = temp;
        end
        return
    end

    % This loop adds all diagonals down and to the right, to the end of the matrix.
    %fprintf('Diagonals down to main one are:\n');
    numCells = 0;
    for x=1:rows
        rowNum = x;
        colNum = 1;
        temp = [];
        while rowNum >= 1 && rowNum <= rows && colNum <= cols
            temp = [temp; [rowNum colNum]];
            rowNum = rowNum - 1;
            colNum = colNum + 1;
        end
        numCells = numCells + 1;
        temp = flipud(temp); % Need row major order for assignment
        %disp(temp);
        diagIndicies{numCells} = temp;
    end

    % Now go along bottom row
    %fprintf('Diagonals along bottom are:\n');
    for y=2:cols
        rowNum = rows;
        colNum = y;
        temp = [];
        while rowNum >= 1 && colNum <= cols
            temp = [temp; [rowNum colNum]];
            rowNum = rowNum - 1;
            colNum = colNum + 1;
        end
        numCells = numCells + 1;
        temp = flipud(temp); % Need row major order for assignment
        %disp(temp);
        diagIndicies{numCells} = temp;
    end                

end

function diagIndicies = getAllDiagonalIndicies()
    % This function returns lists of indicies in the main diagonal direction (top-left to bottom-right)
    if rows == 1 
        numCells = 0;
        for j=1:length(A)
            temp = [1, j];
            numCells = numCells + 1;
            diagIndicies{numCells} = temp;
        end
        return
    end

     % This loop adds all diagonals down and to the left, to the lhs of the matrix.
    %fprintf('Diagonals down to main one are:\n');
    numCells = 0;
    for x=1:rows
        rowNum = x;
        colNum = cols;
        temp = [];
        while rowNum >= 1 && rowNum <= rows && colNum >= 1
            temp = [temp; [rowNum colNum]];
            rowNum = rowNum - 1;
            colNum = colNum - 1;
        end
        numCells = numCells + 1;
        temp = flipud(temp); % Need row major order for assignment
        %disp(temp);
        diagIndicies{numCells} = temp;
    end

    % Now go along bottom row...
    %fprintf('Diagonals along bottom are:\n');
    for y=cols-1:-1:1
        rowNum = rows;
        colNum = y;
        temp = [];
        while rowNum >= 1 && colNum >= 1
            temp = [temp; [rowNum colNum]];
            rowNum = rowNum - 1;
            colNum = colNum - 1;
        end
        numCells = numCells + 1;
        temp = flipud(temp); % Need row major order for assignment
        %disp(temp);
        diagIndicies{numCells} = temp;
    end

 end


 % Main function starts here.

[rows, cols] = size(A);

theMaxProduct = -10000000;
indicies = [];

if isscalar(A)
    if A == 1 && n == 1
        indicies = [1,1];
        return;
    else
        return;
    end
end



% Find max product in each row of A
for i=1:rows
    for j=1:cols-n+1
        theProduct = 1;
        for k=j:j+n-1
            theProduct = theProduct * A(i, k);
        end
        if theProduct > theMaxProduct
            theMaxProduct = theProduct;
            indicies = [];
            for k=j:j+n-1
                indicies = [indicies; [i, k]];
            end

        end
    end
end
fprintf('theMaxProduct after examining rows = %15.15f\n', theMaxProduct);

% Find max product in each column of A
for i=1:cols
    for j=1:rows-n+1
        theProduct = 1;
        for k=j:j+n-1
            theProduct = theProduct * A(k, i);
        end
        if theProduct > theMaxProduct
            theMaxProduct = theProduct;
            indicies = [];
            for k=j:j+n-1
                indicies = [indicies; [k, i]];
            end

        end
    end
end
fprintf('theMaxProduct after examining cols = %15.15f\n', theMaxProduct);



% Find max product along reverse diagonals of A
diagIndicies = getAllReverseDiagonalIndicies();
%disp(diagIndicies);
for i=1: length(diagIndicies)
    [numIndicies, ~] = size(diagIndicies{i});
    for j=1:numIndicies-n+1
        theProduct = 1;
        for k=j:j+n-1
            theProduct = theProduct * A(diagIndicies{i}(k, 1), diagIndicies{i}(k, 2));
        end
        if theProduct > theMaxProduct
            theMaxProduct = theProduct;
            indicies = [];
            for k=j:j+n-1
                indicies = [indicies; [diagIndicies{i}(k, 1), diagIndicies{i}(k, 2)]];
            end

        end
    end
end
fprintf('theMaxProduct after examining reverse diag = %15.15f\n', theMaxProduct);


% Find max product along diagonals of A
diagIndicies = getAllDiagonalIndicies();
%disp(diagIndicies);
for i=1: length(diagIndicies)
    [numIndicies, ~] = size(diagIndicies{i});
    for j=1:numIndicies-n+1
        theProduct = 1;
        for k=j:j+n-1
            theProduct = theProduct * A(diagIndicies{i}(k, 1), diagIndicies{i}(k, 2));
        end
        if theProduct > theMaxProduct
            theMaxProduct = theProduct;
            indicies = [];
            for k=j:j+n-1
                indicies = [indicies; [diagIndicies{i}(k, 1), diagIndicies{i}(k, 2)]];
            end

        end
    end
end
fprintf('theMaxProduct after examining main diag = %15.15f\n', theMaxProduct);