将被动值或常量分配给用户定义的类型

时间:2016-10-10 04:19:21

标签: variables types fortran assignment-operator fortran2003

所以我正在使用运算符重载在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中实现被动值和常量的构造函数。

2 个答案:

答案 0 :(得分:0)

您有两种选择,可以组合使用。

  1. 使用与右侧有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
    
  2. 使用结构构造函数或重载的过程等效项。

    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)  
    
  3. 如果你在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
相关问题