fortran66のブログ

fortran について書きます。

四月馬鹿 「How Thou Canst Maketh a Fine Program in Fortran」

今更ですが、四月馬鹿のジョーク記事で、18世紀風?の古雅な英語で書かれた Fortran インストールおよび、”Hello World!" ならぬ "Good morrow, and well met, O world!" 表示までの紹介記事がありました。

www.digitalocean.com


ちょっと面白かったです。作者はクラウドコンピューティングサービス会社のテクニカルライターの方のようです。

Fortran 2008 の pointer function で作った連想配列

Fortran 2008 の新機能 pointer function を用いて、簡単な連想配列 (associative array) を作ってみます。

ここでは古典的な手法で、文字列をインデックスとした整数型連想配列を作ってみます。

まず文字列を適当な整数に変換し、あらかじめ用意した配列のサイズの剰余をとって、それを実際の引数とします。このとき、単射性が無いため数値が重なることがあります(いわゆる衝突)、これが起きた場合は、適当な数を足して空いている場所が見つかるまでずらします。

文字列を数値に変換するために、まず文字列を文字配列に直し、次にそれをASCIIコードに直し、総和を取って、適当な素数で剰余を取っています。また衝突時にずらす数も素数に取れば、全ての空きを探すことになります(全射)。


ソース・プログラム

    module m_hash
      implicit none
     ! private
      integer, parameter :: nhash = 17, nd = 13
      type :: t_key
        character(len = :), allocatable :: key  
      end type t_key
      type (t_key) :: keyc(nhash)  
      integer, target :: vals(nhash) = 0  
    contains
      integer function ihash(text)
        character(len = *), intent(in) :: text
        ihash = mod(sum(iachar(transfer(text, ' ', size = len_trim(text)))), nhash) + 1
      end function ihash  
       
      function ia(text) result(ires)
        character(len = *), intent(in) :: text
        integer, pointer :: ires 
        integer :: key, loc, i
        key = ihash(text)
        do i = 1, nhash
          if (.not. allocated(keyc(key)%key)) then
            keyc(key)%key = trim(text)
            ires => vals(key)
            exit
          else if (keyc(key)%key == trim(text)) then 
            ires => vals(key)
            exit
          else ! collision
            key = mod(key + nd, nhash) + 1  
          end if
        end do  
        if (i > nhash) stop 'associative array exhausted!' 
      end function ia      
    end module m_hash
    
    program Hash
      use m_hash
      implicit none
      
      ia('a') = 41
      print *, ia('a')
      ia('a') = 100
      print *, ia('a')
      ia('b') = 200
      print *, ia('a') + ia('b')
      
      
      ia('FORTRAN77') = 1978
      ia('Fortran90') = 1991
      ia('Donald Trump') = 1
      ia('Steve Bannon') = 4
      ia('Milo Yiannopoulos') = 10
      
      block
        integer :: i
        do i = 1, nhash
          print '(i3,a,a20,a,i10)', i, ':', keyc(i)%key, '=>', ia(keyc(i)%key)
        end do    
      end block
    end program Hash

実行結果

          41
         100
         300
  1:                    =>         0
  2:           Fortran90=>      1991
  3:                    =>         0
  4:                    =>         0
  5:           FORTRAN77=>      1978
  6:                    =>         0
  7:        Donald Trump=>         1
  8:                    =>         0
  9:                    =>         0
 10:   Milo Yiannopoulos=>        10
 11:                    =>         0
 12:                    =>         0
 13:                   a=>       100
 14:                   b=>       200
 15:                    =>         0
 16:                    =>         0
 17:        Steve Bannon=>         4
続行するには何かキーを押してください . . .

変数っぽく扱える pointer function

Fortran 2008 の新機能に、pointer を返り値としてもつ関数が、あたかも変数のように扱えるというものがあります。Modern Fortran Explained の 20.5.2 pointer functions denoting variables や The new features of Fortran 2008 の 6.2 Pointer functions に記述があります。

連想配列のようなものに適しているのではないかと思います。

実例1

    module m_sub
      implicit none
    contains
      function storage(key) result(loc)
        integer, intent(in) :: key
        integer, pointer :: loc
        integer, target :: m(100) = 0
        loc => m(key)
      end function storage
    end module m_sub

    program Console2
      use m_sub
      implicit none
      integer :: i
      do i = 1, 10
        storage(i) = i**2
      end do
      do i = 1, 10
        print *, storage(i)
      end do        
    end program Console2

実行例1

           1
           4
           9
          16
          25
          36
          49
          64
          81
         100
続行するには何かキーを押してください . . .

実例2

フィボナッチ数列再帰で求めますが、一度求めた値はテーブルに記録して再利用します。フィボナッチ数の計算では意味がないのですが、テーブルのインデックスはとびとびの値でよくなっています。

二重再帰を使っています。

    module m_fib
      implicit none
      integer, private, parameter :: nmax = 1000
      integer, private :: nx = 0
      integer, private :: keys(nmax) = -huge(0)  
      integer, private, target :: vals(nmax) = 0  
    contains
      recursive function fib(n) result(ires)
        integer, intent(in) :: n
        integer :: ires
        select case(n)
          case (1:2)
            ires = 1
          case (3:)
            ires = fib_table(n)
          case default
            ires = 0
        end select     
      end function fib
    
      recursive function fib_table(key) result(ires)
        integer, intent(in) :: key
        integer, pointer :: ires 
        integer :: loc
        loc = findloc(keys(:nx), key, dim = 1) 
        if (loc <= 0) then 
          nx = nx + 1  
          keys (nx) = key
          vals(nx) = fib(key - 1) + fib(key - 2)
          loc = nx
        end if
        ires => vals(loc)
      end function fib_table
    end module m_fib
    
    program fibonacci
      use m_fib
      implicit none
      integer :: i
      do i = 1, 40
        print *, i, fib(i)
      end do   
    end program fibonacci

実行結果

           1           1
           2           1
           3           2
           4           3
           5           5
           6           8
           7          13
           8          21
           9          34
          10          55
          11          89
          12         144
          13         233
          14         377
          15         610
          16         987
          17        1597
          18        2584
          19        4181
          20        6765
          21       10946
          22       17711
          23       28657
          24       46368
          25       75025
          26      121393
          27      196418
          28      317811
          29      514229
          30      832040
          31     1346269
          32     2178309
          33     3524578
          34     5702887
          35     9227465
          36    14930352
          37    24157817
          38    39088169
続行するには何かキーを押してください . . .

参考 配列を利用したフィボナッチ計算結果再利用型

    module m_fib2
      implicit none
    contains
      recursive function fib(n) result(ires)
        integer, intent(in) :: n
        integer :: ires  
        select case(n)
        case (1:2)
          ires = 1
        case (3:)  
          ires = fib(n - 1) + fib(n - 2)
        case default
          ires = 0
        end select  
      end function fib

      recursive function fib4(n) result(ires)
        integer, intent(in) :: n
        integer :: ires
        integer, save :: stor(100) = 0
        select case(n)
          case(1:2)  
            ires = 1
          case(3:)  
            if (stor(n) == 0) stor(n) = fib4(n - 1) + fib4(n - 2)
            ires = stor(n)
          case default
            ires = 0
        end select    
      end function fib4
    end module m_fib2
    
    program fibonacci
      use m_fib2
      implicit none
      integer :: i
      do i = 1, 38
        print *, i, fib(i)
      end do  
      pause
      do i = 1, 38
        print *, i, fib4(i)
      end do   
    end program fibonacci

派生型の再帰的割り付け成分

Fortran 2008 では、派生型の成分に自分自身を allocatable 属性で持てます。つまり再帰的に派生型を定義できます。再帰的定義は古典的なリスト構造によく使われます。

Fortran 2003 までは、派生型の再帰的な成分は pointer 型に限られていました。pointer 型の成分に記憶領域の割り付けをする場合、解放時の処理を利用者側が自分でやらなければなりませんでした。記憶領域の解放漏れが起きないよう慎重に解放処理を用意する必要がありました。

ところが allocatable 属性の場合は、記憶領域解放時の処理を、処理系側が引き受けてくれるので、利用者側の負担が大幅に減ります。

根元を解放すれば、そこから連なる子・孫・末代まで皆、処理系側が解放してくれます。根元を解放するとそこから連なる記憶領域がアクセス不能の死に領域になってしまう pointer 型との大きな違いです。

ソースプログラム

古典的な一次元単方向リストを定義して、整数値を入れてゆきます。つぎに根元からリストをたぐって代入した整数値を出力します。最後に、リストの根元を解放します。この時、ファイナライザ(いわゆるデストラクタ)を用意して、いまわの際に成分を出力させています。

    module m_final
      type :: t_list
        integer :: ival
        type (t_list), allocatable :: next
      contains
        final :: destruct
      end type t_list  
    contains
      subroutine destruct(this)
        type (t_list), intent(in) :: this
        print *, this%ival
      end subroutine destruct
    end module m_final
    
    program final
      use m_final
      implicit none
      type (t_list), allocatable, target :: root
      type (t_list), pointer :: last
      integer :: i
      allocate(root, source = t_list(0))
      last => root
      do i = 1, 10
        allocate(last%next, source = t_list(i))
        last => last%next
      end do    
      last => root
      
      print *, 'print list'
      do 
        if (.not. associated(last)) exit
        print *, last%ival
        last => last%next
      end do  
      
      print *, 'finalizer'
      deallocate(root)
    end program final

実行結果

ファイナライズする順番は枝葉の末端から根元に向かってではなく、根元から枝葉の末端に向かって解放されてゆくようです。

 print list
           0
           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
 finalizer
           0
           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
続行するには何かキーを押してください . . .

参考
・M.Metcalf, J.Reid and M.Cohen: Modern Fortran Explained 20.3.1
・J.Reid: The new features of Fortran 2008

web clip メモ帳 

直リンが多くて申し訳ないが検索で飛んだ場所なので・・・

・Modern Fortran
www.admin-magazine.com
www.admin-magazine.com
www.admin-magazine.com


フィンランド Fortran 講義 CAFあり
Modern Fortran Programming for Chemists and Physicists

・CAF スライド NEC
2012 F2008の並列処理関連機能
http://www.hpfpc.org/documents/soukai_120419/F2008Para.pdf

2013 Fortran 2008 のcoarray機能
http://www.pccluster.org/ja/event/xmpws1st/hayashi.pdf

2016 Fortran規格のcoarray機能 - Fortran 2008 と Fortran 2015
http://site.hpfpc.org/home/events/parallel_fortran_sympo2/documents_16060/hayashi_160601v2.pdf?attredirects=0&d=1
並列Fortranに関するシンポジウムのご案内(第2回) - 高性能Fortran 推進協議会

fujitu
2016 富士通Fortranへの取り組み ~Coarrayの実装と性能~
http://site.hpfpc.org/home/events/parallel_fortran_sympo2/documents_16060/haraguchi_160601.pdf?attredirects=0&d=1

・Xcalable + CAF 
XcalableMP WebSite

2014
https://www.aics.riken.jp/aicssite/wp-content/uploads/2014/12/2014sympo_0307_1010.pdf
https://www.gfd-dennou.org/arch/davis/workshop/2014-03-10/murai.pdf

2016
http://www.xcalablemp.org/download/workshop/4th/iwashita.pdf


・CAF2.0 
Coarray Fortran 2.0 at Rice University

スライド
2009
http://open-supercomputer.org/wp-content/uploads/2012/03/WPSE2009-06-Scherer.pdf

2012
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.648.5708&rep=rep1&type=pdf

2013
https://crd.lbl.gov/assets/Uploads/FTG/Projects/DEGAS/RetreatSummer13/CAF2.0.pdf


・MPI: William Gropp の講義 
Designing and Building Applications for Extreme Scale Systems

Intel Parallel Studio 2018 ベータ始まる!

Intel® Parallel Studio XE 2018 の Beta が開始になりました。

software.intel.com


Fortran v.18 は、パッと見たところ Fortan2008 規格の主な機能にほぼ完全に対応した感じです。長らく待たれていた、リスト構造を扱い易くする type 中での再帰型 allocatable や、再帰関数での無駄な計算を減らすための変数の蓄積を容易にする ポインタ関数への代入や、テーブルルックアップを容易にする finloc 関数などが一気に実装されました。

Ian Chivers による実装状況一覧

以下の記事でコンパイラごとの実装状況の比較ができます。残念ながら NECFujitsuコンパイラは入っていません。メーカが情報を送れば載せるみたいです?

Compiler support for Fortran 2003, 2008 & TS 29113 Standard - rev 20 (December 2016)
www.fortranplus.co.uk

なお最新版の rev.21 は
Ian Chivers, Jane Sleightholme:
Compiler Support for the Fortran 2003 and 2008 Standards Revision 21
ACM SIGPLAN Fortran Forum
(有料)


webinar

来週、2018 beta の内容紹介 webinar があります。

Get Onboard with the Intel® Parallel Studio XE 2018 Beta (Online)
High Performance Computing (HPC) Webinars | Intel® Software

バノン氏失脚の噂と米白人の寿命低下からの随想

トランプ米大統領の躍進の陰には、米白人弱者の困難な社会的状況があると言われていました。その証拠として、米白人庶民層の寿命低下がよく取り上げられています。背後には、生きる意味の喪失とそれに伴う酒・薬物依存すなわち自暴自棄(今風にいえばセルフネグレクトw)があるとされています。

これはソ連崩壊後のロシア人や、アメリカ人宣教師到来後の南洋土人エスキモーに見られた現象と同質のものだと思われます。すなわち、民話や土着宗教的な神話を破壊されたときに起きる、人生の意味の喪失による内側からの崩壊だと思います。

ロシアではソ連崩壊により、マルクス・レーニン主義という、過去に原始共産主義の楽園があったとする素朴な民間宗教が崩壊した後、ウォッカや薬物への依存が蔓延しました。南洋土人エスキモーも、善意のキリスト教宣教師が、いわゆる野蛮な土着信仰や民話・民謡・祭りの類を根絶したあと、アル中や薬中が蔓延しました。

このような普段見過ごされて、無駄だと見なされがちな素朴な習俗が、生きる意味などを与えていることは、決して軽視してはならないものだと思います。

近年のアメリカでは、クリスマスのような民衆レベルの素朴な風習への攻撃が行われていることがよくニュースになっています。これは上述の素朴な土着民話や宗教への攻撃と同類のものだと思われます。

かつてのティー・パーティーの諸子やスティーブ・バノン氏の登場は、このことに直観的に気付いて、それに対抗しようとした無意識の動きなのだと思います。それがいずれも、振り出し方を間違えて力を失うのは、まこと哀れな感じがします。「鳥の将に死なんとする其の鳴くや哀し」といった趣きです。


しかしながら逆に、我が国はこれを応用して敵国を内部から崩壊させることを是非とも研究しておくべきだと思います。そのためには諸外国の宗教・習俗・民話などを軽視せず、よく研究しておいて、いざという時に自己矛盾に追い込んで、根本から社会を崩壊させる手段を整えておくべきだと思います。

ここで思い起こすのは、江戸時代の日本の宋学批判から始まった儒学テキスト校訂作業が清朝支那に伝わって考証学を引き起こし、それが国家宗教の朱子学儒教への懐疑を産み、支那の精神的支柱を破壊したことです。純粋な学問研究が、うまい具合に一国家の衰運・滅亡を引き起こせたことは、学問の力の特筆すべき偉業と言えると思います。