将被动值或常量分配给用户定义的类型 [英] Assigning passive values or constants to a user-defined type
问题描述
因此,我正在使用运算符重载在Fortran中使用自动区分工具箱.我以前已经在C ++中实现了此功能,但确实需要使其在Fortran中工作.
So I'm working on an automatic differentiation toolbox in Fortran using operator overloading. I have previously implemented this in C++ but really need to get it to work in Fortran.
我在Fortran中定义了以下模块:
I have the following module defined in 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 ++中,我具有与用户定义的类型相似的
In C++, I have a similar user-defined type as
class ADType {
public:
int index;
double v;
ADType() : index(-1), v(0) {};
ADType(const double&);
ADType& operator=(const ADType&);
};
其中,构造函数为索引和值部分设置初始值.接下来,我有一个用于构造被动值或常量(双精度类型)的构造函数,以便在有双精度变量时可以定义一个新的类(ADType
)变量.例如,当我有:
where the constructor sets the initial values for the index and value parts. Next, I have a constructor for passive values or constants (of type double) so that I can define a new variable of class (ADType
) whenever I have a double variable. For example, when I have:
ADType x;
x = 2.0;
最初会创建一个类型为ADType
的新变量,其值设置为2.0,假设var1 = 2.0
然后是下一个(根据类ADType
中定义的赋值运算符(=)),我将该变量分配给x,即x = var1
.整个过程都记录在磁带中,该磁带对操作进行计数并记录值和索引.
initially a new variable of type ADType
is created with value set to 2.0, let's say var1 = 2.0
and next (according to the assignment operator (=) defined in the class ADType
) I will assign that variable to x, i.e. x = var1
. This entire process is being recorded in a tape that counts operations and records the values and indices.
现在,您可以说为什么要这样做?".好吧,在使用运算符重载的自动微分的伴随方法中,这是必需的步骤.
Now, you may say "why do you have to do this?". Well, during the adjoint method of automatic differentiation using operator overloading, this is a necessary step.
在C ++中执行此操作的方式是,我仅具有以下两个构造函数:
The way I do it in C++ is that I simply have the following two constructors:
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中实现被动值和常量的构造函数.
but I don't know how to implement the constructor for passive values and constants in Fortran.
推荐答案
以下是对您的问题的完整建议.请注意,模块内的每个变量都会自动继承save
属性.如果您最终对并发感兴趣,则可能必须将indexcounter
括在ADtape
内,并使用适当的类型绑定程序进行记账.
Here's a complete working suggestion to your problem. Please note that every variable inside a module automatically inherits the save
attribute. If you're eventually interested in concurrency you may have to enclose indexcounter
inside ADtape
with an appropriate type-bound procedure for bookkeeping.
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
这篇关于将被动值或常量分配给用户定义的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!