2016-10-10 4 views
1

私は演算子のオーバーロードを使用してFortranの自動微分ツールボックスに取り組んでいます。これまでC++で実装していましたが、実際にFortranで動作させる必要があります。パッシブ値または定数をユーザー定義型に割り当てる

Iは、Fortranで定義された以下のモジュールを有する:コンストラクタはインデックスの初期値を設定する場合にC++で

 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 

を、Iは

class ADType { 
    public: 
     int index; 
     double v; 
     ADType() : index(-1), v(0) {}; 
     ADType(const double&); 
     ADType& operator=(const ADType&); 
    }; 

と同様のユーザー定義型を有し、かつ価値のある部品。次に、受動的な値または定数(double型)のコンストラクタを用意して、double変数を持つたびにクラス(ADType)の新しい変数を定義できます。私が持っている場合、例えば、:

ADType x; 
x = 2.0; 

が最初タイプADTypeの新しい変数が2.0に設定された値を使用して作成され、(クラスADTypeで定義された代入演算子(=)による)のにvar1 = 2.0と次を言わせてIその変数をxに代入します(x = var1)。このプロセス全体が、操作を数え、値とインデックスを記録するテープに記録されています。

今、「なぜこれを行う必要がありますか」と言うかもしれません。オペレータのオーバーロードを使用する自動微分の随伴法の間、これは必要なステップです。

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で、受動的な値と定数のコンストラクタを実装する方法がわからない:

私はCでそれを行う方法は、++、私は単純に以下の2つのコンストラクタを持っていることです。

+1

を生成するには、それはあなたのプログラムですが、あなたがC言語で小文字を使用する場合++理由だけでなくFortranでそれらを使用していませんか?彼らはもっと読みやすい。そして、 '= 0.D0'は必要なく、変数が倍になっても' = 0'は完璧です。あなたの変数はデフォルトの実数なので、Dの必要は全くありません。 –

+0

@VladimirFヒントをありがとう。私はそれがちょうど古い習慣だと思う – FRJedi

+0

@VladimirFはそれをより読みやすくするために質問を編集しました – FRJedi

答えて

0

あなたには2つのオプションがあり、組み合わせて使用​​できます。

  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. 構造コンストラクタ、またはオーバーロード手続き等価物を使用します。あなたはC++の例では、ソースコード内の二重の明示を取るコンストラクタの呼び出しを行った場合

    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) 
    

(すなわち、あなたはこれらの2つのアプローチの二に相当を持ってADType x; x = ADType(2.0); - Fortranはありません

(サンプルコードでは、タイプバインド割り当てとFortran 90スタイルのスタンドアロンインターフェイスの両方が示されていますが、そのモジュールをコンパイルしないでください。 )

+0

@lanHご回答いただきありがとうございます。 **明示的**変換を避けるために最初のアプローチを使用しています。暗黙の変換が必要なもう一つの理由は、実数型と派生型(および派生型対実数)のシナリオを処理する特別なプロシージャを使用して、すべてのバイナリ演算をオーバーロードすることを回避することでした。より多くのコーディングが必要でしたが、モジュールに実装しました。 C++では、 'double'値を派生型のインプレースに変換し、オーバーロードされた操作を実行できます。 Fortranでこれをより効率的に行う方法に関する提案はありますか?ありがとう – FRJedi

+0

Fortranには、派生型のオブジェクト間の暗黙の変換はありません。これには利点があります。過負荷解決は非常に簡単です。明示的なプロシージャ参照または構造体コンストラクタを使用するだけです。 – IanH

0

あなたの問題に対する完全な作業提案があります。モジュール内のすべての変数は自動的にsave属性を継承することに注意してください。最終的に並行性に関心がある場合はの中にindexcounterを適切なタイプバインドされた簿記手順で囲む必要があります。

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 
関連する問題