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
我需要实现一种对矩阵列表进行运算的算法。矩阵的数量和它们的大小是事先不知道的 - 用户可以自由地将算法应用于任何有限数量的任何大小的矩阵。如何在 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