Fortran OOP线性求解器优化:移除select type实现通用矩阵向量乘
select type实现通用矩阵求解器? 当然可以!你需要用到Fortran面向对象编程里的**抽象基类(abstract type)**来实现动态多态,这样就能让Solver模块的代码完全摆脱select type的分支判断,实现你想要的简洁写法。下面是具体的改造步骤:
第一步:定义抽象基类统一接口
首先修改你的Matrices模块,先定义一个抽象的基类matrix_like,它只声明所有矩阵类型必须实现的mxv接口,然后让原来的matrix类型扩展这个抽象基类:
module Matrices implicit none private ! 定义抽象基类,声明mxv的抽象接口(所有矩阵类型必须实现这个方法) type, public, abstract :: matrix_like contains procedure(mxv_interface), deferred, public, pass :: mxv end type matrix_like ! 定义mxv方法的接口模板 abstract interface subroutine mxv_interface(this, x, y) import :: matrix_like class(matrix_like), intent(in) :: this real*8, intent(in) :: x real*8, intent(out) :: y end subroutine mxv_interface end interface ! 让原matrix类型扩展抽象基类,实现mxv方法 type, public, extends(matrix_like) :: matrix real*8 :: coeff contains procedure, public, pass :: init procedure, public, pass :: mxv => multiplication end type matrix contains subroutine init(this,coeff) implicit none class(matrix), intent(inout) :: this real*8, intent(in ) :: coeff this%coeff=coeff end subroutine init subroutine multiplication(this,x,y) implicit none class(matrix), intent(in ) :: this real*8, intent(in ) :: x real*8, intent(out) :: y y=this%coeff*x end subroutine multiplication end module Matrices
第二步:让组合矩阵扩展抽象基类
接下来修改ComposedMatrices模块,让cmatrix同样扩展matrix_like抽象基类(注意我把原代码里multiplication子程序的this参数从intent(inout)改成了intent(in),因为矩阵-向量乘法不需要修改矩阵本身):
module ComposedMatrices use Matrices implicit none private ! 让组合矩阵类型扩展抽象基类,实现mxv方法 type, public, extends(matrix_like) :: cmatrix type(matrix) :: m1,m2 real*8 :: h contains procedure, public, pass :: init procedure, public, pass :: mxv => multiplication end type cmatrix contains subroutine init(this,m1,m2,h) implicit none class(cmatrix), intent(inout) :: this type(matrix), intent(in ) :: m1,m2 real*8, intent(in ) :: h this%m1=m1 this%m2=m2 this%h=h end subroutine init subroutine multiplication(this,x,y) implicit none class(cmatrix), intent(in) :: this ! 修正为intent(in),更符合逻辑 real*8, intent(in ) :: x real*8, intent(out ) :: y ! local real*8 :: temp call this%m1%mxv(x,y) call this%m2%mxv(x,temp) y=y+this%h*temp end subroutine multiplication end module ComposedMatrices
第三步:简化Solver模块
现在你可以完全重构Solver模块,去掉select type,直接使用抽象基类matrix_like的多态变量,Fortran会自动根据实际类型调用对应的mxv方法:
module Solver use Matrices ! 只需引入定义抽象基类的模块 implicit none contains subroutine powers(general_matrix,npower,x,y) class(matrix_like), intent(in) :: general_matrix ! 使用抽象基类类型 integer, intent(in ) :: npower real*8, intent(in ) :: x real*8, intent(out) :: y !local integer :: i real*8 :: temp temp=x do i=1,npower call general_matrix%mxv(temp,y) temp=y end do end subroutine powers end module Solver
测试程序无需修改
你原来的测试程序可以直接运行,因为matrix和cmatrix都是matrix_like的扩展类型,Fortran的多态机制会自动处理类型适配,输出结果和之前完全一致。
原理说明
抽象基类相当于一个“契约”,它规定了所有扩展它的类型必须实现的方法(这里就是mxv)。当你在Solver里使用class(matrix_like)类型的参数时,Fortran会在运行时根据实际传入的对象类型,动态调用对应的mxv实现,这就是动态多态,完美替代了select type的分支判断,让代码更简洁、更易扩展——以后如果新增其他矩阵类型,只要扩展matrix_like并实现mxv方法,Solver模块不需要做任何修改就能兼容。
内容的提问来源于stack exchange,提问作者enrico

