Fortran:矩阵列表作为函数参数

Fortran: list of matrices as a function argument

我需要实现一种对矩阵列表进行运算的算法。矩阵的数量和它们的大小是事先不知道的 - 用户可以自由地将算法应用于任何有限数量的任何大小的矩阵。如何在 Fortran 代码中实现此类行为?是否有合适的数据结构可以做到这一点?我正在寻找一个完善的 Fortran 编程模式。

使用 list 数据结构和 numpy 的组合,在 Python 中实现这样的算法相对容易矩阵,但它的工作方式很慢。

请注意,我假设您的所有矩阵都具有相同数据类型的元素。

这是我将要执行的操作的简化示例(并且是非常老式的)

ian@eris:~/work/stack$ cat list_of_matrices.f90 
Module numbers_module

  Implicit None

  Integer, Parameter, Public :: wp = Selected_real_kind( 12, 70 )

  Private

End Module numbers_module

Module matrix_module

  Use numbers_module, Only : wp

  Implicit None

  Type, Public :: matrix
     Real( wp ), Dimension( :, : ), Allocatable, Public :: data
  End type matrix

  Public :: matrix_allocate
  Public :: matrix_free
  Public :: matrix_set_with_random
  Public :: matrix_print

  Private

Contains

  Subroutine matrix_allocate( A, m, n )

    Type( matrix ), Intent(   Out ) :: A
    Integer       , Intent( In    ) :: m
    Integer       , Intent( In    ) :: n

    Allocate( A%data( 1:m, 1:n ) )

  End Subroutine matrix_allocate

  Subroutine matrix_free( A )

    Type( matrix ), Intent( InOut ) :: A

    Deallocate( A%data )

  End Subroutine matrix_free

  Subroutine matrix_set_with_random( A )

    Type( matrix ), Intent( InOut ) :: A

    Call Random_number( A%data )

  End Subroutine matrix_set_with_random

  Subroutine matrix_print( A, format )

    Type( matrix )      , Intent( In ) :: A
    Character( Len = * ), Intent( In ) :: format

    Integer :: i

    Write( *, * ) 'The matrix has the shape: ', Shape( A%data )
    Do i = 1, Size( A%data, Dim = 1 )
       Write( *, format ) A%data( i, : )
    End Do

  End Subroutine matrix_print

End Module matrix_module

Program test_matrix

  Use matrix_module, Only : matrix, matrix_allocate, matrix_free, &
       matrix_set_with_random, matrix_print

  Implicit None

  Type( matrix ), Dimension( : ), Allocatable :: list_of_matrices

  Integer :: n_mats
  Integer :: n, m
  Integer :: i_mat

  Write( *, * ) 'How many matrices'
  Read ( *, * ) n_mats

  Allocate( list_of_matrices( 1:n_mats ) )

  Do i_mat = 1, n_mats
     Write( *, * ) 'Dimensions for matrix ', i_mat
     Read ( *, * ) m, n
     Call matrix_allocate( list_of_matrices( i_mat ), m, n )
     Call matrix_set_with_random( list_of_matrices( i_mat ) )
  End Do

  Do i_mat = 1, n_mats
     Write( *, * ) 'Data for matrix ', i_mat
     Call matrix_print( list_of_matrices( i_mat ), '( 20( f5.2, 1x ) )' )
  End Do

  Do i_mat = n_mats, 1, -1
     Call matrix_free( list_of_matrices( i_mat ) )
  End Do
  Deallocate( list_of_matrices )

End Program test_matrix
ian@eris:~/work/stack$ gfortran -std=f2008 -Wall -Wextra -Wuse-without-only -Wsurprising -Wimplicit-interface -Werror -fcheck=all list_of_matrices.f90 -o list_of_matrices
ian@eris:~/work/stack$ ./list_of_matrices 
 How many matrices
3
 Dimensions for matrix            1
2 1
 Dimensions for matrix            2
4 3
 Dimensions for matrix            3
5 6
 Data for matrix            1
 The matrix has the shape:            2           1
 0.06
 0.31
 Data for matrix            2
 The matrix has the shape:            4           3
 0.02  0.63  0.08
 0.26  0.84  0.75
 0.85  0.67  0.34
 0.85  0.91  0.33
 Data for matrix            3
 The matrix has the shape:            5           6
 0.35  0.58  0.01  0.93  0.74  0.46
 0.43  0.38  0.89  0.83  0.51  0.26
 0.33  0.03  0.73  0.26  0.40  0.58
 0.48  0.87  0.15  0.62  0.13  0.79
 0.59  0.97  0.15  0.09  0.05  0.37
ian@eris:~/work/stack$ 

在实践中,我会将派生类型的内容保密,并且只能由模块过程访问,现在我会在矩阵类型中使用类型绑定过程,但为此我认为这会分散注意力因此走稍微老一点的路线。在生产代码中,我可能还会有一个单独的 list_of_matrices 类型来保存矩阵数组,但这取决于你在做什么。

事实上,我目前正在研究的东西本质上是一个更复杂的版本 - 在矩阵列表上执行线性代数的例程,其中这些矩阵可以是实矩阵也可以是复矩阵,以及这些矩阵中的数据可以分布在多个进程中。刚刚斥责了某人要求我们下载未知文件,我对此感到有些内疚,但如果有兴趣,你可以在 github 上找到它:

git clone https://github.com/drijbush/dmat2.git