所以我正在使用运算符重载在Fortran中使用自动差分工具箱。我以前用C ++实现了这个,但是真的需要让它在Fortran中运行。
我在Fortran中定义了以下模块:
module adopov
integer :: indexcount
integer, parameter :: tape_size = 1000
!
!....... ADtype
public :: ADtype
type ADtype
integer :: index = -1
real :: v = 0.0
!
contains
procedure :: oo_asg
generic, public :: assignment(=) => oo_asg
end type ADtype
!
!....... class tape
public :: ADtape
type ADtape
real :: v = 0.0
end type ADtape
!
!....... interface(s)
interface assignment(=)
module procedure oo_asg
end interface
!
type (ADtape), dimension(tape_size) :: tape
!
!....... definitions
contains
!
!....... assignment
subroutine oo_asg (x,y)
implicit none
class(ADtype), intent(out) :: x
class(ADtype), intent(in) :: y
!
tape(indexcount)%v = y%v
indexcount = indexcount + 1
x%v = y%v
x%index = indexcount
end subroutine oo_asg
!
end module adopov
在C ++中,我有一个类似于
的用户定义类型class ADType {
public:
int index;
double v;
ADType() : index(-1), v(0) {};
ADType(const double&);
ADType& operator=(const ADType&);
};
其中构造函数设置索引和值部分的初始值。接下来,我有一个被动值或常量(类型为double)的构造函数,这样每当我有一个双变量时,我就可以定义一个新的类(ADType
)变量。例如,当我有:
ADType x;
x = 2.0;
最初创建一个类型ADType
的新变量,其值设置为2.0,假设var1 = 2.0
和next(根据类ADType
中定义的赋值运算符(=))我将该变量分配给x,即x = var1
。整个过程记录在磁带中,该磁带计算操作并记录值和索引。
现在,您可能会说“为什么要这样做?”。那么,在使用运算符重载的自动微分的伴随方法中,这是必要的步骤。
我在C ++中的方式是我只需要以下两个构造函数:
ADType:: ADType(const double& x): v(x) {
tape[indexcounter].v = x;
indexcounter++;
};
ADType& ADType::operator=(const ADType& x) {
if (this==&x) return *this;
tape[indexcounter].v = v = x.v;
indexcounter++;
return *this;
}
但我不知道如何在Fortran中实现被动值和常量的构造函数。
答案 0 :(得分:0)
您有两种选择,可以组合使用。
使用与右侧有REAL对象相对应的过程重载已定义的赋值。
TYPE ADTYPE
...
CONTAINS
PROCEDURE :: OO_ASG
PROCEDURE :: ASSIGN_FROM_REAL
GENERIC, PUBLIC :: ASSIGNMENT(=) => OO_ASG, ASSIGN_FROM_REAL
END TYPE AREAL
! Users of the module shoudn't be calling this procedure
! (or the specific binding, really) directly.
PRIVATE :: ASSIGN_FROM_REAL
...
SUBROUTINE ASSIGN_FROM_REAL(x,y)
CLASS(ADTYPE), INTENT(OUT) :: x
REAL, INTENT(IN) :: y
! Do what you have to do...
...
x%V = y
END SUBROUTINE ASSIGN_FROM_REAL
! Example of use...
TYPE(ADTYPE) :: z
z = 2.0
使用结构构造函数或重载的过程等效项。
INTERFACE ADTYPE
MODULE PROCEDURE ADTYPE_construct_from_REAL
END INTERFACE ADTYPE
PRIVATE :: ADTYPE_construct_from_REAL
...
FUNCTION ADTYPE_construct_from_REAL(y) RESULT(x)
REAL, INTENT(IN) :: y
TYPE(ADTYPE) :: x
! Do what you have to do.
...
x%V = y
END FUNCTION ADTYPE_construct_from_REAL
! Example of use:
TYPE(ADTYPE) :: z
z = ADTYPE(3.0)
如果你在C ++示例中的源代码中调用了双显式的构造函数(即ADType x; x = ADType(2.0);
,那么你就等于这两种方法中的第二种 - Fortran没有隐式派生类型的对象之间的转换。
(您的示例代码显示了类型绑定赋值和Fortran 90样式的独立接口。两者都没有意义 - 该模块甚至不应该编译。)
答案 1 :(得分:0)
这是对您的问题的完整工作建议。请注意,模块内的每个变量都会自动继承save
属性。如果您最终对并发感兴趣,则可能必须将indexcounter
括在ADtape
内,并使用适当的类型绑定程序进行簿记。
module adopov
use, intrinsic :: ISO_C_binding, only: &
ip => C_INT, &
wp => C_DOUBLE
! Explicit typing only
implicit none
! Everything is private unless stated otherwise
private
public :: Adtype, wp
! Declare derived data types
type ADtape
real(wp) :: v = 0.0_wp
end type ADtape
type, public :: ADtype
integer(ip) :: index = -1
real(wp) :: v = 0.0_wp
contains
procedure, private :: asgn_from_type, asgn_from_real, asgn_from_int
generic, public :: assignment(=) => asgn_from_type, asgn_from_real, asgn_from_int
end type ADtype
! Set user-defined constructor
interface ADtype
module procedure :: ADtype_constructor
end interface ADtype
! Variables confined to the module.
! Please note that every variable
! in a module implicitly inherits the save attribute.
integer :: indexcount = 0 ! Your original code left this uninitialized
integer, parameter :: TAPE_SIZE = 1000
type (ADtape) :: tape(TAPE_SIZE)
contains
pure function ADtype_constructor(x, indx) result (return_value)
real (wp), intent(in) :: x
integer (ip), intent (in), optional :: indx
type (ADtype) :: return_value
return_value%v = x
if (present(indx)) return_value%index = indx
end function ADtype_constructor
subroutine update_tape(float)
real (wp), intent (in) :: float
tape(indexcount)%v = float
indexcount = indexcount + 1
end subroutine update_tape
subroutine asgn_from_type(this, y_type)
class(ADtype), intent(out) :: this
class(ADtype), intent(in) :: y_type
associate( &
v => this%v, &
indx => this%index &
)
call update_tape(y_type%v)
v = y_type%v
indx = indexcount
end associate
end subroutine asgn_from_type
subroutine asgn_from_real(this, y_real)
class(ADtype), intent(out) :: this
real(wp), intent(in) :: y_real
associate( &
v => this%v, &
indx => this%index &
)
call update_tape(y_real)
v = y_real
indx = indexcount
end associate
end subroutine asgn_from_real
subroutine asgn_from_int(this, y_int)
class(ADtype), intent(out) :: this
integer(ip), intent(in) :: y_int
associate( &
v => this%v, &
indx => this%index, &
float => real(y_int, kind=wp) &
)
call update_tape(float)
v = float
indx = indexcount
end associate
end subroutine asgn_from_int
end module adopov
program main
use, intrinsic :: ISO_Fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
use adopov, only: &
ADtype, wp
! Explicit typing only
implicit none
type(ADtype) :: foo, bar, woo
! Invoke the user-defined constructor
foo = ADtype(42.0_wp)
bar = ADtype(42.0_wp, -6)
woo = foo
print *, foo
print *, bar
print *, woo
write( stdout, '(/4a/)') &
' This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
这会产生
gfortran -Wall -o main.exe adopov.f90 main.f90
./main.exe
1 42.000000000000000
2 42.000000000000000
3 42.000000000000000
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -Wall