我正在尝试编写一个通用的子程序来实现最小化。由于我想要一个通用的子程序,目标函数可以有不同的参数,不仅在名称中,而且在尺寸上也是如此。所以我需要一种方法来传递参数结构(我使用的是单词结构,因为我的想法是在Matlab中使用类似结构类型变量的东西)。 我设法使用派生数据类型,它工作得很好,但是当我在同一个程序中有两个不同的目标函数时会出现问题。这是一个示例代码:
在主程序main.f90中:
MODULE MYPAR
IMPLICIT NONE
TYPE PARPASS1 !! Parameter passing structure 1
INTEGER :: a
REAL :: X(2,2)
END TYPE PARPASS1
TYPE PARPASS2 !! Parameter passing structure 2
REAL :: b
REAL :: Y(3)
END TYPE PARPASS2
END MODULE MYPAR
PROGRAM MAIN
USE MYPAR
USE MYLIB
IMPLICIT NONE
INTEGER :: am
REAL :: bm,Xm(2,2),Ym(3),sol1,sol2
TYPE(PARPASS1) :: PARAM1
TYPE(PARPASS2) :: PARAM2
am = 1
bm = 3.5
Xm(1,:) = [1.0, 2.0]
Xm(2,:) = [0.5, 2.5]
Ym(1:3) = [0.25,0.50,0.75]
PARAM1%a = am
PARAM1%X = Xm
PARAM2%b = bm
PARAM2%Y = Ym
CALL MYSUB(sol1,OBJ1,PARAM1)
CALL MYSUB(sol2,OBJ2,PARAM2)
PRINT *,sol1
PRINT *,sol2
CONTAINS
SUBROUTINE OBJ1(sumval,PARAM)
REAL,INTENT(OUT) :: sumval
TYPE(PARPASS1),INTENT(IN) :: PARAM
INTEGER :: a
REAL,ALLOCATABLE :: X(:,:)
a = PARAM%a
X = PARAM%X
sumval = a+X(1,1)+X(2,2)
END SUBROUTINE OBJ1
SUBROUTINE OBJ2(divval,PARAM)
REAL,INTENT(OUT) :: divval
TYPE(PARPASS2),INTENT(IN) :: PARAM
REAL :: b
REAL,ALLOCATABLE :: Y(:)
b = PARAM%b
Y = PARAM%Y
divval = b / (Y(1)+Y(2))
END SUBROUTINE OBJ2
END PROGRAM MAIN
一个名为mylib.90的模块
MODULE MYLIB
USE MYPAR
IMPLICIT NONE
CONTAINS
SUBROUTINE MYSUB(sol,FN,PARAM)
REAL,INTENT(OUT) :: sol
TYPE(PARPASS1), INTENT(IN) :: PARAM
CALL FN(sol,PARAM)
sol = 2*sol
END SUBROUTINE MYSUB
END MODULE MYLIB
显然,如果我使用CALL MYSUB(sol2,OBJ2,PARAM2)
和PRINT *,sol2
对这些行进行评论,我的代码会顺利运行。这是我之前有两个“目标函数”,但是现在当它有它们时它不起作用,因为MYSUB中的派生类型变量PARPASS1不能是任意的。
有什么想法吗?
答案 0 :(得分:2)
你可以使用一个接口并重载子程序MYSUB:
MODULE MYLIB
USE MYPAR
IMPLICIT NONE
interface MYSUB
module procedure MYSUB_PARPASS1, MYSUB_PARPASS2
end interface
CONTAINS
SUBROUTINE MYSUB_PARPASS1(sol,FN,PARAM)
REAL,INTENT(OUT) :: sol
TYPE(PARPASS1), INTENT(IN) :: PARAM
CALL FN(sol,PARAM)
sol = 2*sol
END SUBROUTINE MYSUB_PARPASS1
SUBROUTINE MYSUB_PARPASS2(sol,FN,PARAM)
REAL,INTENT(OUT) :: sol
TYPE(PARPASS2), INTENT(IN) :: PARAM
CALL FN(sol,PARAM)
sol = 2*sol
END SUBROUTINE MYSUB_PARPASS2
END MODULE MYLIB
然后你可以使用MYSUB来调用它,它会根据PARAM的类型来区分函数
编辑:好的,这个怎么样:
MODULE MYPAR
IMPLICIT NONE
type, abstract :: PARPASS
contains
procedure(func), deferred :: OBJ
end type PARPASS
TYPE, extends(PARPASS) :: PARPASS1 !! Parameter passing structure 1
INTEGER :: a
REAL :: X(2,2)
contains
procedure :: OBJ => OBJ1
END TYPE PARPASS1
TYPE, extends(PARPASS) :: PARPASS2 !! Parameter passing structure 2
REAL :: b
REAL :: Y(3)
contains
procedure :: OBJ => OBJ2
END TYPE PARPASS2
abstract interface
subroutine func(this, val) !Interface for the subroutine you want to implement
import
class(PARPASS), intent(in) :: this
real, intent(out) :: val
end subroutine func
end interface
contains
subroutine OBJ1(this, val)
class(PARPASS1),INTENT(IN) :: this
real, intent(out) :: val
INTEGER :: a
REAL,ALLOCATABLE :: X(:,:)
a = this%a
X = this%X
val = a+X(1,1)+X(2,2)
END subroutine OBJ1
subroutine OBJ2(this, val)
class(PARPASS2),INTENT(IN) :: this
real, intent(out) :: val
REAL :: b
REAL,ALLOCATABLE :: Y(:)
b = this%b
Y = this%Y
val = b / (Y(1)+Y(2))
END subroutine OBJ2
END MODULE MYPAR
MODULE MYLIB
USE MYPAR
IMPLICIT NONE
CONTAINS
SUBROUTINE MYSUB(sol, param)
REAL,INTENT(OUT) :: sol
class(PARPASS), INTENT(IN) :: PARAM
call param%obj(sol)
sol = 2*sol
END SUBROUTINE MYSUB
END MODULE MYLIB
PROGRAM MAIN
USE MYPAR
USE MYLIB
IMPLICIT NONE
INTEGER :: am
REAL :: bm,Xm(2,2),Ym(3),sol1,sol2
TYPE(PARPASS1) :: PARAM1
TYPE(PARPASS2) :: PARAM2
am = 1
bm = 3.5
Xm(1,:) = [1.0, 2.0]
Xm(2,:) = [0.5, 2.5]
Ym(1:3) = [0.25,0.50,0.75]
PARAM1%a = am
PARAM1%X = Xm
PARAM2%b = bm
PARAM2%Y = Ym
CALL MYSUB(sol1, PARAM1)
CALL MYSUB(sol2, PARAM2)
PRINT *,sol1
PRINT *,sol2
END PROGRAM MAIN
它使用包含过程OBJ
的抽象类型,然后派生类型可以扩展它并实现实际过程。然后,您可以传递任何扩展PARPASS
的类型,并将类型绑定过程OBJ
实现为'MYSUB',并从内部调用它,而无需为所有不同的可能性提供单独的接口。