首页 文章

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

提问于
浏览
1

Foreword

为了存储带状矩阵,其完整对应物可以从 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,除了我将对角线存储为列而不是行) .

  • 组件 ldud 应分别包含下对角线和上对角线的数量,即 -lbound(A%matrix,2)+ubound(A%matrix,2) .

  • 2元素组件 lbub 应该包含沿着两个维度的实际完整矩阵的下界和上界 . 特别是 lb(1)ub(1) 应该与 lbound(A%matrix,1)lbound(A%matrix,2) 相同 .

正如您在第2点和第3点所看到的那样,派生类型包含一些冗余信息,但我没有写过,在填充矩阵之前就知道了有关边界的信息和实际完整矩阵的带 . 所以我首先将值分配给组件 ldudlbub ,然后我将这些组件用于 ALLOCATE matrix 组件(然后我可以正确填充它) .

The problem

我必须在这些稀疏矩阵之间执行矩阵乘法,所以我写了 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

这意味着,如果我必须多次执行该产品,则在函数内多次执行分配 . 从性能的角度来看,我认为这并不好 .

我就如何完成带状稀疏矩阵时间带状稀疏矩阵的任务提出了建议 . 我想使用我定义的类型,因为我需要它作为一般的,就边界而言,就像现在一样 . 但我可以更改执行产品的过程(如果需要,从 FUNCTIONSUBROUTINE ) .

Ideas

我可以将程序重写为 SUBROUTINE ,以便声明 CDS_mat_x_CDS_matINTENT(INOUT) 进行 matrix 以外的组件分配,以及 SUBROUTINE 之外的分配 . 缺点是我无法重载 * 运算符 .

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

1 回答

  • 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
    

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

相关问题