【问题标题】:Rotate the rows of a matrix (like GAUSS function rotater)旋转矩阵的行(如 GAUSS 函数旋转器)
【发布时间】:2015-01-16 17:32:17
【问题描述】:

我目前正在将一些 GAUSS 代码带到 Matlab 中,但我一直在尝试使用 GAUSS“旋转器”功能。

旋转器的命令参考条目说:

  • 用途旋转矩阵的行
  • 格式 y = rotater(x,r)
  • 输入 x:要旋转的 N x K 矩阵。 r:指定旋转量的 N x 1 或 1 x 1 矩阵。
  • 输出 y:N x K 旋转矩阵。
  • 备注 旋转在矩阵的每一行内水平执行。正旋转值将导致元素移动 向右。负旋转将导致元素移动到 左边。在任何一种情况下,被推离末端的元素 该行将环绕到同一行的另一端。如果旋转值大于或等于 x 中的列数,则将使用 (r % cols(x)) 计算旋转值。

示例 1 (我在这里遵循 Matlab 的符号,用直括号表示矩阵,用分号表示新的 ro)

如果 x = [1 2 3; 4 5 6], r = [1; -1],然后 y = [3 1 2; 5 6 4]

示例 1

如果 x = [1 2 3; 4 5 6; 7 8 9; 10, 11, 12] 和 r = [0; 1个; 2; 3],则 y = [1 2 3; 6 4 5; 8 9 7; 10 11 12]

也许有人在某个地方找到了类似的函数,或者可以给我建议如何编写它?

【问题讨论】:

    标签: matlab matrix rotation statistics linear-algebra


    【解决方案1】:

    这可以使用bsxfun 完成两次:

    1. 通过用bsxfun 减去r 并使用mod 计算旋转行索引。像往常一样,mod 需要从 0 开始的索引,而不是 1。旋转后的行索引保留为从 0 开始,因为这对于第 2 步更方便。
    2. 从列和旋转行中获取linear index,再次使用bsxfun。应用于x 的线性索引给出y

    代码:

    [s1 s2] = size(x);
    rows = mod(bsxfun(@plus, 1:s2, -r(:))-1, s2);  % // step 1
    y = x(bsxfun(@plus, rows*s1, (1:s1).'));       %'// step 2
    

    【讨论】:

    • 我知道有一个bsxfun 解决方案潜伏在... ;)
    【解决方案2】:

    circshift 非常接近您正在寻找的内容,除了 1) 它适用于列而不是行,以及 2) 它将整个矩阵移动相同的偏移量。

    第一个很容易修复,我们只是转置。对于第二个,我找不到矢量化方法,但与此同时,这里有一个带有 for 循环的版本:

    x = [1 2 3; 4 5 6; 7 8 9; 10 11 12]
    r = [0 1 2 3]
    
    B = x'
    
    C = zeros(size(B));
    for ii = 1:size(B,2)
      C(:,ii) = circshift(B(:,ii),r(ii));
    end
    
    y = C'
    

    输出是:

    x =
    
        1    2    3
        4    5    6
        7    8    9
       10   11   12
    
    r =
    
       0   1   2   3
    
    B =
    
        1    4    7   10
        2    5    8   11
        3    6    9   12
    
    y =
    
        1    2    3
        6    4    5
        8    9    7
       10   11   12
    

    【讨论】:

      【解决方案3】:

      这可以使用一个简单的 for 循环来遍历每一行,并使用 matlab 中名为“circshift”的函数来完成。

      我创建了一个函数,它遍历每一行并对其应用适当的转变。可能有更有效的方法来实现这一点,但这种方式适用于您的示例。我创建了一个函数

      function rotated_arr = GaussRotate(input_array, rotation_vector)
          [N,K] = size(input_array)
      
          %creates array for return values
          rotated_arr = zeros(N,K);
      
          %if the rotation vector is a scalar
          if (length(rotation_vector) == 1)
              %replicate the value once for each row
              rotation_vector = repmat(rotation_vector, [1,N]);
          end
      
          %if the rotation vector doesn't have as many entries as there are rows
          %in the input array
          if (length(rotation_vector) ~= N)
              disp('ERROR GaussRotate: rotation_vector is the wrong size')
              disp('if input_Array is NxK, rotation_vector must be Nx1 or 1x1')
              return
          end
      
          %for each row
          for idx=1:size(input_array,1)
              %shift the row by the appropriate number of columns
              %we use [0,shift] because we want to shift the columns, the row
              %stays where it is (even though this is a 1xN at this point we
              %still specify rows vs columns)
              rotated_arr(idx,:) = circshift(input_array(idx,:),[0,rotation_vector(idx)]);
          end
      
      end
      

      然后用你的例子简单地调用它

       x = [1 2 3; 4 5 6];
       r = [1; -1];
       y =  GaussRotate(x,r)
       %produces [3 1 2; 5 6 4]
      
       %I also made it support the 1x1 case
       r = [-1] 
       %this will shift all elements one column to the left
       y = GaussRotate(x,r)
       %produces [2 3 1; 5 6 4]
      
       x = [1 2 3; 4 5 6; 7 8 9; 10, 11, 12]
       r = [0; 1; 2; 3]
       y = GaussRotate(x,r)
       %produces  [1 2 3; 6 4 5; 8 9 7; 10 11 12]
      

      【讨论】:

      • 我的答案与@beaker 匹配,除了我只是简单地传入了用于 circshift 的数组而不是转置(这样你就可以让它在行而不是列上工作)我还通过更多的错误检查改进了他的答案,但是两者都可以正常工作。 (我会在你的代码烧杯中添加 cmets,但我还没有足够的积分)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多