【问题标题】:Linear indexing in symmetric matrices对称矩阵中的线性索引
【发布时间】:2013-10-02 18:02:34
【问题描述】:

我们可以使用遵循这种模式的线性索引来访问矩阵

0 1 2

3 4 5

6 7 8

在这种情况下很容易获得 i,j 坐标(n 是矩阵维度)。对于基于 0 的索引,它会是。

i = 索引/n

j = 索引 % n

现在,如果我的矩阵是对称的,我只想访问上面的部分,该怎么办

0 1 2 3

.. 4 5 6

..... 7 8

........ 9

我知道线性索引将由下式给出

索引 = j + n*i - i (i-1) / 2

但我想知道给定 idx 的 i,j。你们知道这样做的任何方法吗?我在这里查了这个,但我找不到答案。提前致谢。

【问题讨论】:

  • 至少在 Matlab 中,矩阵是行主导的,所以你的索引是关闭的。您可以不使用 Matlab 的原生 triu 函数,还是真的只需要这些索引而不是上三角矩阵?为什么同时使用 c++ 和 Matlab 标签?你到底在找什么?
  • MATLAB 中有一个函数叫做ind2sub。你可以试试看。

标签: c++ algorithm matlab matrix


【解决方案1】:

如果你想使用你使用的索引,并且你想避免循环,你可以反转索引的函数。我将使用 k 来表示线性索引,并且所有索引都是从零开始的。正如你所指出的

k = j + n*i - i*(i-1) /2.

看到我们在这里使用正整数,并且所有组合 (i,j) 映射到不同的 k 的事实意味着该函数是可逆的。我这样做的方式是首先注意这一点

j = k - n*i + i*(i-1)/2

这样,如果您可以找到您所在的行,则该列由上述等式定义。现在考虑你想要的行,它被定义为

行 = 最小{ i | k - ni + i(i-1)/2 >= 0 }.

如果你求解二次方程 k - ni + i(i-1)/2 = 0 并取 i 的底,这会给你行,即

row = floor( (2n+1 - sqrt( (2n+1)^2 - 8k ) ) / 2 )

然后

j = k - 行 * n + 行 * (row-1)/2。

在伪代码中是

//Given linear index k, and n the size of nxn matrix
i = floor( ( 2*n+1 - sqrt( (2n+1)*(2n+1) - 8*k ) ) / 2 ) ;
j = k - n*i + i*(i-1)/2 ;

这消除了循环的需要,并且对于大型矩阵来说会更快

【讨论】:

  • +1 Awww,我只是在我的循环答案中添加了这些内容。请注意,这给出了 j 相对于行。例如,使用n=4,k=8 我得到i=2,j=1。如果您希望j 相对于整个矩阵,请将i 添加到结果中。
  • 是的,问题是我的索引表达式不对,应该是:"k = j + n*i - i*(i-1) /2 - i",但是现在获取的是方程并不那么简单,因为二次方程的解是: i = floor( ( 2*n-1 - sqrt( (2n-1)*(2n-1) - 8*k ) ) / 2 ) ;它可以有虚根。
【解决方案2】:

由于还没有人发布 Matlab 解决方案,这里有一个简单的单行:

idxs = find(triu(true(size(A))))

给定矩阵A,这将返回所有索引的向量,这样idxs(k) 会将第 k 个线性索引返回到矩阵的上三角部分。

【讨论】:

    【解决方案3】:

    这是对 Keeran Brabazon 回答的评论。 k = j + ni - i(i-1) /2 - 这是你帖子中的方程,它是错误的,正确的方程是 k = j + (2*n -1 -i) *i/2。但我们不能用它来寻找 i。

    您帖子中的方程式可用于查找 i(行索引),但我们无法将 i 代入您的方程式并得到 j,因此您帖子中 j 的公式是错误的,因此最终结果将如下所示这个:

    i = floor( ( 2*n+1 - sqrt( (2n+1)*(2n+1) - 8*k ) ) / 2 ) ;(和你的一模一样)

    j = k - (2*n-1- i)*i/2; (与您的版本不同,我通过将 i 代入我的方程式来得到它)

    【讨论】:

      【解决方案4】:

      遍历你的行,跟踪每一行的偏移量和每一行的起始索引:

      offset = 0;
      startOfRow = 0;
      for(i=0;i<height;i++){
          endOfRow = startOfRow + (width - offset);
          if(idx < endOfRow){ 
              j = (idx - endOfRow) + width;
              return {i,j};
          } else {                           
              startOfRow = endOfRow;
              offset++;
          }
      }
      

      我不知道 Matlab,所以它只是伪代码,但它应该可以工作。正如 horchler 所说,确保您的索引是正确的。我在这里使用了i,j,就像您在示例中使用的那样,但我觉得它奇怪

      【讨论】:

        【解决方案5】:

        这是我能想到的最简单的方法:

        int i = 1, j, x=n;
        while (idx > x)
        {
            i++;
            idx=idx-x;
            x--;
        }
        j=idx+(i-1);
        
        return i, j;
        

        【讨论】:

          【解决方案6】:

          对于基于 0 索引:

          int j = 0;
          int x = (n-1);
          while (idx > x) {
              j++;
              idx=idx-x;
              x--;
          }
          i=idx;
          

          【讨论】:

            【解决方案7】:

            你可以用这个

            idxs = find(triu(true(size(A)))');
            

            这是对马特答案的更新。 B,因为您想要逐行表示。

            【讨论】:

              【解决方案8】:

              MATLAB 附带内置函数 ind2sub 和 sub2ind。请查看 MATLAB 的文档。

              请注意,在 MATLAB 中,线性索引沿行向下,索引从 1 开始

              示例:对于 3 x 3 矩阵

              1 4 7

              2 5 8

              3 6 9

              【讨论】:

                猜你喜欢
                • 2015-01-21
                • 2021-11-15
                • 1970-01-01
                • 1970-01-01
                • 2012-11-13
                • 1970-01-01
                • 2021-09-11
                • 2019-05-05
                • 2023-04-09
                相关资源
                最近更新 更多