将被动值或常量分配给用户定义的类型 [英] Assigning passive values or constants to a user-defined type

查看:92
本文介绍了将被动值或常量分配给用户定义的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在使用运算符重载在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆