Fortran函数用于在具有可分配组件的派生类型之间重载乘法

时间:2016-07-06 17:33:06

标签: fortran operator-overloading sparse-matrix matrix-multiplication derived-types

前言

为了存储带状矩阵,其完整对应物可以从1以外的索引索引行和列,我将派生数据类型定义为

TYPE CDS
  REAL, DIMENSION(:,:), ALLOCATABLE :: matrix
  INTEGER, DIMENSION(2) :: lb, ub
  INTEGER :: ld, ud
END TYPE CDS

其中CDS代表压缩对角线存储。 鉴于声明TYPE(CDS) :: A

  1. rank-2组件matrix应该包含实际完整矩阵的对角线(如here,作为列,除了我将对角线存储为列而不是行)。
  2. 组件ldud应分别包含下方和上方对角线的数量,即-lbound(A%matrix,2)+ubound(A%matrix,2)
  3. 2元素组件lbub应该包含沿着两个维度的实际完整矩阵的下界和上界。特别是lb(1)ub(1)应与lbound(A%matrix,1)lbound(A%matrix,2)相同。
  4. 正如您在第2点和第3点中所看到的,派生类型包含一些冗余信息,但我不在乎,因为它们只是3对整数。此外,在我正在编写的代码中,关于实际完整矩阵的边界和带的信息是之前知道矩阵可以填充。所以我首先将值分配给组件ldudlbub,然后我将这些组件用于ALLOCATE matrix } component(然后我可以正确地填充它)。

    问题

    我必须在这些稀疏矩阵之间执行矩阵乘法,所以我写了一个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,以便CDS_mat_x_CDS_mat声明INTENT(INOUT)matrix以外的组件分配,以及外部分配SUBROUTINE。缺点是我无法重载*运算符。

    我注意到内部函数MATMUL可以对任何rank-2操作数进行操作,无论两个维度的上限和下限。这意味着分配在函数内部执行。我认为它是有效的(因为它是一个内在的)。与我的函数的不同之处在于它接受任何形状的rank-2数组,我接受具有任何形状的rank-2数组组件的派生数据类型对象。

1 个答案:

答案 0 :(得分:2)

内在函数MATMUL具有相当于自动(F2008 5.2.2)的结果 - 结果的形状以这样的方式表示,即它成为函数的特征(F2008 12.3.3) - 形状函数结果在函数的规范部分中确定,并且(在实现方面)编译器因此知道如何在实际执行函数之前计算函数结果的形状。

因此,没有与等效的内在MATMUL函数结果相关联的Fortran语言ALLOCATABLE变量。这与没有内存分配"没有相同的事情。 - 编译器可能仍需要在幕后为自己的目的分配内存 - 例如表达式临时等等。

(我说"相当于"上面,因为内在程序本质上是特殊的 - 但假装MATMUL只是一个用户功能片刻。)

通过使用长度类型参数,可以实现对您的案例的那种自动结果的等效。这是Fortran 2003的特性 - 引入可分配组件的基本语言标准相同 - 但它并不是所有主动维护的编译器都实现的。

MODULE xyz
  IMPLICIT NONE

  TYPE CDS(lb1, ub1, ld, ud)
    INTEGER, LEN :: lb1, ub1, ld, ud
    REAL :: matrix(lb1:ub1, ld:ud)
    INTEGER :: lb2, ub2
  END TYPE CDS

  INTERFACE OPERATOR(*)
    MODULE PROCEDURE CDS_mat_x_CDS_mat
  END INTERFACE OPERATOR(*)
CONTAINS
  FUNCTION CDS_mat_x_CDS_mat(A, B) RESULT(C)
    TYPE(CDS(*,*,*,*)), INTENT(IN) :: A, B
    TYPE(CDS(A%lb1, A%ub1, A%ld+B%ld, A%ud+B%ud)) :: C

    C%lb2 = B%lb2
    C%ub2 = B%ub2

    ! perform the product.
    ! :

  END FUNCTION CDS_mat_x_CDS_mat
END MODULE xyz

从理论上讲,这为编译器提供了更多的优化机会,因为它在函数调用所需的存储功能之前有更多的洞察力。这实际上是否会带来更好的实际性能取决于编译器的实现和函数引用的性质。