【发布时间】:2016-11-08 20:53:43
【问题描述】:
前言
为了存储带状矩阵,其完整对应物可以同时具有从1 以外的索引索引的行和列,我将派生数据类型定义为
TYPE CDS
REAL, DIMENSION(:,:), ALLOCATABLE :: matrix
INTEGER, DIMENSION(2) :: lb, ub
INTEGER :: ld, ud
END TYPE CDS
其中 CDS 代表压缩对角线存储。
鉴于声明TYPE(CDS) :: A,
- rank-2 组件
matrix应该包含作为列的实际完整矩阵的对角线(如 here,除了我将对角线存储为列而不是行)。 - 组件
ld和ud应该分别包含上下对角线的数量,即-lbound(A%matrix,2)和+ubound(A%matrix,2)。 - 2 元素组件
lb和ub应该包含实际完整矩阵沿两个维度的下限和上限。特别是lb(1)和ub(1)应该与lbound(A%matrix,1)和lbound(A%matrix,2)相同。
正如您在第 2 点和第 3 点中看到的,派生类型包含一些冗余信息,但我不在乎,因为它们只是 3 对整数。此外,在我正在编写的代码中,关于实际完整矩阵的边界和带的信息是知道在可以填充矩阵之前。所以我首先将值分配给组件ld、ud、lb和ub,然后我将这些组件用于ALLOCATEmatrix组件(然后我可以正确填充它)。
问题
我必须在这样的稀疏矩阵之间执行矩阵乘法,所以我写了一个FUNCTION 来执行这样的乘积,并用它来重载* 运算符。
目前功能如下,
FUNCTION CDS_mat_x_CDS_mat(A, B)
IMPLICIT NONE
TYPE(CDS), INTENT(IN) :: A, B
TYPE(CDS) :: cds_mat_x_cds_mat
! determine the lower and upper bounds and band of the result based on those of the operands
CDS_mat_x_CDS_mat%lb(1) = A%lb(1)
CDS_mat_x_CDS_mat%ub(1) = A%ub(1)
CDS_mat_x_CDS_mat%lb(2) = B%lb(2)
CDS_mat_x_CDS_mat%ub(2) = B%ub(2)
CDS_mat_x_CDS_mat%ld = A%ld + B%ld
CDS_mat_x_CDS_mat%ud = A%ud + B%ud
! allocate the matrix component
ALLOCATE(CDS_mat_x_CDS_mat%matrix(CDS_mat_x_CDS_mat%lb(1):CDS_mat_x_CDS_mat%ub(1),&
& -CDS_mat_x_CDS_mat%ld:+CDS_mat_x_CDS_mat%ud))
! perform the product
:
:
END FUNCTION
这意味着,如果我必须多次执行产品,则分配会在函数中执行多次内部。从性能的角度来看,我认为这并不好。
我请教如何完成带状稀疏矩阵乘以带状稀疏矩阵的任务。我想使用我定义的类型,因为我需要它在边界方面像现在一样通用。但我可以更改执行产品的程序(如有必要,从FUNCTION 更改为SUBROUTINE)。
想法
我可以将过程重写为SUBROUTINE,以便用INTENT(INOUT) 声明CDS_mat_x_CDS_mat,执行matrix 以外的组件的分配以及SUBROUTINE 之外的分配。缺点是我无法重载 * 运算符。
我注意到内部函数 MATMUL 可以对任何 rank-2 操作数进行操作,无论二维的上限和下限。这意味着分配是在函数内部执行的。我想它是有效的(因为它是内在的)。我的函数的不同之处在于它接受任何形状的 rank-2 数组,而我的函数接受具有任何形状的 rank-2 数组组件的派生数据类型对象。
【问题讨论】:
-
您是否进行了分析以确定该分配的(相对)成本(似乎您必须只做一次,无论是在函数中还是在进入子例程之前)?但是,也许我不明白:您建议在多次相乘时重新使用分配。但是为什么不直接缓存结果并完成呢?
标签: fortran operator-overloading sparse-matrix matrix-multiplication derived-types