【问题标题】:How to create a tri diagonal matrix as 1D如何将三对角矩阵创建为一维
【发布时间】:2019-07-16 03:09:51
【问题描述】:

所以对于我的应用程序,我需要创建一个三对角矩阵。这对任何语言都很容易做到,循环遍历所有行和列,然后设置主对角线值、子对角线值和超对角线值。通常,这是在二维数组上执行的。

对于我的应用程序,我需要创建一个“三对角线”的一维数组。换句话说,就是:取 2d 三对角矩阵,然后把它变成 1d。我可以从 2d 开始,然后编写一些将 2d 数组转换为 1d 数组的函数。这个,我可以。我想知道我们是否可以直接进入一维“三对角线”?例如,假设 2D 数组是 10*10,那么我的 1D 数组将是 100 个元素长,那么我需要找出哪个索引是主对角线、超对角线和子对角线。

可以这样做吗?请告诉我,谢谢

【问题讨论】:

  • 您要存储所有元素(包括所有零)还是只存储三对角元素(在 10x10 示例中为 28)。
  • 我想存储所有元素
  • 那么,只是一个简单的序列化?喜欢idx1d = col + row * columnCount
  • 差不多。我首先将一维数组清零,然后循环遍历它并选择哪个索引具有主对角线、超对角线和子对角线值。问题是我不知道如何获取这些索引。
  • 这就是我在上一条评论中所写的。主对角线有col = row,所以idx1d = i * (1 + columnCount),其中i 是行/列。下对角线在前,上对角线在后。

标签: c++ algorithm matrix fortran


【解决方案1】:

也请考虑:

  • @YvesDaoust 的回答,因为提出了更好的存储策略:不是存储三对角矩阵的所有元素,而是仅存储非零元素。如果值得的话,您可以编写派生类型来封装行为。

  • @VladmirF 的回答,因为指针关联可能是比通过reshape 复制所有数组更好的方法(取决于您的用例),如果您只想在工作时为了方便而临时更改索引在数据上。

说了这么多,来看看我的回答吧。

  • 填充三对角矩阵与构造任何矩阵没有什么不同。我认为这并不重要。请记住,Fortran 以 Column Major 顺序存储数组,基于 1 的索引。

  • 如果存储是连续的,那么更改数据的形状很容易且显而易见。您可以建立pointer 关联或将其转移到具有reshape 的新变量。

  • 提取主对角线、超对角线和子对角线也是一个小问题,只需对数组索引三元组进行简单操作即可完成。看:

    program tridiagonal
      implicit none
      integer, parameter :: n = 4
      integer :: A(n, n), B(n**2), main(n), sub(n-1), sup(n-1)
    
      A(1,:) = [1, 4, 0, 0]
      A(2,:) = [3, 4, 1, 0]
      A(3,:) = [0, 2, 3, 4]
      A(4,:) = [0, 0, 1, 3]
                                ! Remember, colum major
      B = reshape(A, shape(B))  ! 1, 3, 0, 0, 4, 4, 2, 0, 0, 1, 3, 1, 0, 0, 4, 3
    
      main = B(  1:n**2:n+1)    ! 1, 4, 3, 3
      sub  = B(  2:n**2:n+1)    ! 3, 2, 1
      sup  = B(n+1:n**2:n+1)    ! 4, 1, 4
    end
    

【讨论】:

    【解决方案2】:

    主对角线上的元素在索引 (i, i) 处,共有 n 个; (i, i-1) 和 (i, i+1) 处的上对角线和下对角线,共有 n-1 个(i 分别从 2 开始和 n-1 结束)。

    一种选择是使用三个向量并将元素存储在这三个向量中相应索引 i 处。

    您还可以将所有值打包到一个长度为 3n 的向量中(如果您想腾出空间,则为 3n-2)。将 n 或 2n 添加到索引中,具体取决于您要处理的对角线。对于元素 (i, j),对角线的索引由 j-i+2 给出。

    【讨论】:

    • 我不明白为什么会否决...但是如果您提供一些代码,您的答案会更有用。老实说,对于这类数据来说,这是一个很好的存储策略。
    • @RodrigoRodrigues:这是处理带状矩阵的一种非常标准的方法。
    【解决方案3】:

    您可以使用二维数组指针查看一维数组。 Fortran:

      integer, target :: A(100)
    
      integer, pointer :: B(:,:)
    
      B(1:10,1:10) => A
    
      B = 0
      do i = 1, 10
        B(i,i) = 1
      end do
    
      print '(*(1x,g0))', A
    end
    
    
    > gfortran diag1d.f90 
    > ./a.out 
     1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1
    

    在 C++ 中,强制转换也很简单。

    【讨论】:

    • 这是显而易见的(也是可取的)方法,可以说比reshape 更好,因为没有进行复制。尽管如此,这个答案并没有解决问题的某些部分(如果我做对了):我需要弄清楚哪个索引是主对角线、超级对角线和子对角线。
    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 2022-10-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    相关资源
    最近更新 更多