fortran66のブログ

fortran について書きます。

【乞食晩報】PGI の CUDA Fortran 無料

PGI Community Edition という名で、昨年末あたりから PGIのコンパイラが無料で使えるようになっていたようです。サポート無しということ以外では、特に制限もないようです。Linux/Windows/macOSとなんでもござれのご様子。

www.pgroup.com


Ian D. Chivers 氏による対応表を見る限り、Fortran2003 はほぼ全部の機能を網羅しているようです。F2008の方はどのくらい進んだのでしょうか?興味がある所です。


Fortran 2003 status in Fortran Wiki

Fortran 2008 status in Fortran Wiki

EU の Fortran2003/08 入門講座資料

EU 圏のスパコン連合のようなところの Fortran 上級コースが、Fortran2003/08 に絞った入門講座資料を公開しています。中々よさげな感じです。

[http://www.training.prace-ri.eu/training_material/?tx_pracetmo_pi1[uid]=474&no_cache=1:title]

内容

  1. F03/08 概略
  2. C 言語との連携
  3. CAF (coarray fortran)
  4. OO (Object Oriented features)

PDF 直リン
http://www.training.prace-ri.eu/uploads/tx_pracetmo/AdvancedFortranProgHandoutAFPC116.pdf

ACM SIGPLAN Fortran Forum 最新号出る!

ACM SIGPLAN Fortran Forum 8月号

年三回出版の Fortran 専門誌 ACM SIGPLAN Fortran Forum 最新号が出ました。

悲しいかな、今号の記事は1本のみ。しかも、よそにもう出ているものとほぼ同じ。

ACM SIGPLAN Fortran Forum

The new features of Fortran 2015
John Reid
Pages: 3-28
doi>10.1145/3131212.3131213

これとほぼ同じ内容だと思います。
fortran66.hatenablog.com

John Reid 氏引退!?

Dr. Fortran こと Steve Lionel 氏の最新ブログ記事によると、長年 Fortran コミュニティーを引っ張て来た John Reid 氏が Fortran ワーキンググループの議長(Convenor of WG5)から降りることを表明し、Steve Lionel 氏に地位を禅譲することにしたそうです。

software.intel.com

And on a related note, John Reid, who has been the Convenor of WG5 since 1999, has decided to step down from that role and he asked me if I'd be interested in filling that position. It was an honor to be asked and I agreed to be nominated for the role.

John Reid 氏の "The new features of Fortran XX" シリーズは、手っ取り早く勉強するのにとても良い文書です。Michael Metcalf 氏との共著の(最新作では Malcolm Cohen 氏も参加) "Fortran xx Explained" も、とても要領のよい良書です。John Reid 氏に万歳三唱!

なお、Chairman of the ANSI Fortran Standards Committee として尽力した Jeanne Clare Adams 女史の死亡後、共著の "Fortran xx Handbook" シリーズの刊行が止まってしまったことが、なんとなく思い起こされます。

Jupyter 上の IJulia 経由の Fortran 呼び出しで図を描く

能書き

IPython がいつのころか Jupyter に名前を変えて、Python に限定されないプラットフォームに進化しております。

図表と記号処理と数値計算が混じり合った処理は、旧来 Maple/Mathematica/Matlab 等で行なわれてきましたが、年々上がる年貢の賦課に耐えかねて、これらに変わって Jupyter 上の寄せ集めでやろうという動きもあるようです。

一方モダン Fortran を使うには、IPython は微妙に Python 経由での Fortran 呼び出しが面倒でしたが、Jupyter 上の IJulia 経由だと、Fortran 呼び出しが楽だという噂を小耳にはさんだので、挑戦してみます。


以下のサイトを参考にしました。
divrot.hatenablog.com

Calling C and Fortran Code — Julia Language 0.4.8-pre documentation


下準備

上記の参考サイトを見ればわかるように、根本的なからくりはダイナミック・ライブラリを作ってそれを呼び出す形になるため、Fortran コンパイラの吐き出すライブラリがちゃんと呼び出せる必要があります。

Windows上では、DLL の形式が MSC のリンカ―のバージョンなどに依存して、いらぬ気苦労をしそうなので、敬して遠ざけることとします。そこで ubuntu on bash on windows 上で Jupyter/IPython/IJulia 環境を作って、bash on windows 側の gfortran を使うことにしました。

ネット情報を頼りにやりましたが、何ヶ所か躓きました。ひどく時間はかかりましたが、エラーメッセージを我慢して読むことで、なんとか解決できました。

重症例

  • ZMQ ライブラリ構築失敗 ⇒ g++ がなかったため。
  • PyPlot が IPython では作画可能ながら IJulia で失敗 ⇒ OpenGL がらみのライブラリが足りなかった。エラーで無いとい言われたものを検索、Ubuntu apt-get でパッケージをインストール。

[追記:sudo apt install libzmq5
pip uninstall matplotlib
pip install matplotlib
matplotlib のバージョン違いで問題になったりする。
しかし環境依存。
]

Fortran

とりあえず、エラトステネスのふるいで素数を求めて個数をプロットしてみることにします。Fortran 側の関数で個数を求めて、IJulia 側では、関数呼び出しと作図のみを行うことにします。

Fortran 側でも、デバッグの為メインプログラムで個数を求めてみます。

F2003 以降の C言語互換用の BIND を使うことで名前問題は解決するので、関数は Module 内においても大丈夫。またダイナミック・ライブラリにするので、メイン・プログラム付きのままコンパイルしても大丈夫(のはず)です。関数の引数は値呼び出しにしました。

    module m_prime
      implicit none
    contains
      integer function nprim(n) bind(c, name = 'nprim')
        integer, value :: n
        logical(1), allocatable :: tab(:) ! Sieve of Eratosthenes
        integer :: i
        allocate(tab(n))
        tab = .true.
        tab(1) = .false.
        do i = 1, int(sqrt(real(n)))
          if (tab(i)) tab(i**2::i) = .false.
        end do     
        nprim = count(tab)
      end function nprim
    end module m_prime
    
    program eratos3
      use m_prime
      implicit none
      integer :: i
      do i = 1, 8
        print *, nprim(10**i)  
      end do    
    end program eratos3

これは windows 側の visual studio で作りました。


これを、bash on windows 側に送って、gfortran でコンパイルします。

gfortran prime.f90 -o prime.so -shared -fPIC

これで、ダイナミック・リンク用のライブラリが出来ました。


IJulia 側での処理

とりえあえず、関数を呼び出してみます。Fortran の引数は基本的に参照呼び出しなのですが、ここでは値呼び出しにすることで厄介をさけています。

よく分からないでの、ライブラリは絶対 path を与えておきました。

呼び出し時の fortran 関数の引数リストはタプルなので、変数1個の時にはコンマで終わる「( Int32, )」ということにしばらく気づきませんでした。

n = 100
t = ccall( (:nprim, "/mnt/d/home/prime.so"), Int32, ( Int32, ), n )

これで百までの素数の個数である 25 が返されます。

次にこれをもとに Fortran の関数を呼び出す Julia の関数を定義します。

function np(i)
    n = Int32(10^i)
    return ccall( (:nprim, "/mnt/d/home/prime.so"), Int32, ( Int32, ), n )
end

10 から 10^9 までの 10のべき乗個以下の素数の個数を求め配列に入れます。

x = 1:9
y = np.(x)
print(y)

出てきた結果は以下のようになります。

Int32[4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534]

出た結果を対数グラフに出力します。

using PyPlot
grid("on")
xlabel("x")
ylabel("Number of Primes pi(10^x)")
ax = gca()
ax[:set_yscale]("log")
grid("on")
plot(x, y)

以上の結果のハードコピーです。
https://cdn-ak2.f.st-hatena.com/images/fotolife/f/fortran66/20170806/20170806030224_original.png


今回は引数の受け渡しなどが素朴だったので、比較的簡単に実行できました。



付録

Julia言語に否定的な方々の意見 1年以上前のものですが
Giving up on Julia

その中での引用先
http://www.davideaversa.it/2015/12/the-most-promising-languages-of-2016/
A review of the Julia programming language

遅く、バグが多くかつ放置気味で、言語仕様が MATLAB 的でダサいようです。
MATLAB 代替のニッチ向きとのこと。

私は配列1始まりで、ブロックを end で閉じる方が落ち着くんですけど。

ARM の Fortran

Advancing scientific codes with ARM Fortran Compiler

かつて intel cpu の輸出規制を食らったロシアのプーチン首相(当時)が、ARMでスパコン作れと号令しましたが、日本の次期スパコンも ARMと決まり、ヨーロッパも ARM でスパコン作ると言い出しています。

Fortran コンパイラは、利幅の大きいハイエンドHPCサーバー向けのキラーソフトウェアであるため(入札条件などに Fortran 必須だし)、サーバー市場を狙う ARM もいよいよ Fortran2003 コンパイラのβ版を出してきました。電力消費がネックとなっている今、ARM にチャンスが来ています。

昔から、安くてショボイものが、高くてしっかりしたものを侵食してきたコンピュータ業界故、ARM も馬鹿に出来ません。

www.electronicsmedia.info

developer.arm.com

developer.arm.com

Intel が商売つぶしのために、Fortran compiler を値下げすることを期待しますw

そういえばプーチン氏は、ロシア人の VISA/Master カードの使用禁止制裁を食らったときに、日本には JCB という独自ネットワークの国際クレジットカードがある、ロシアにも同様のがあると良いと言っておりました。

最近の話題から

Road to Fortran Programming: Learn Fortran (90/95/2003) from the ground up with examples

アマゾンを見ていると Fortran の同人的新刊が。NASAの公募に挑戦するため勉強してますとのことで、百円なので買ってみましたが・・・あぁ百円返せ。Googleストアは返金してくれたりするが。

Fortranでオセロゲーム

gamewoshiyou.blog.fc2.com

メインルーチンのところで、コピペ失敗でコードが崩れています。

if(n1>n2) then
write(*,*)'winner :: ○'
else if(n1 write(*,*)'winner :: ●'
else
write(*,*)'draw'
endif
end program m
if(n1 > n2) then
  write(*,*)'winner :: ○'
else if(n1 < n2) 
  write(*,*)'winner :: ●'
else
  write(*,*)'draw'
endif
end program m

これで動くようになりました。

C++ を C 経由で Fortran から呼ぶ

屏風からトラを出すように、まず C の人が C++ 呼び出しインターフェースを作ってくれねばメンドイですね。
modelingguru.nasa.gov

C 用のインターフェース作成のような機械的作業こそ、奴隷人たるコンピュータがやるべき仕事だと思うのですが。

まんが 即席 FORTRAN 1969

CDC 6000 series

archive.org

分割をフロベニウス記法へ

分割のヤング図をフロベニウス記法へ

分割 [4,3,3,3,1,1] rank=3
フロベニウス記法 a=(3,1,0)、 b=(5,2,1)

■□□□
□■□
□□■
□□□

その逆も作りましたが、まだ詰め足りないです。途中ということでw(追記:少し直しました)

関数の総称名の作り方もよく分かりません。

実行結果

([3,1,0],[5,2,1])

ソースプログラム

main = print (frobenius [4,3,3,3,1,1]) 
--print (ftop ([3,1,0], [5,2,1]) ) 

type Partition = [Int]
type Frobenius = ([Int], [Int])

frobenius :: Partition -> Frobenius
frobenius xs = (a xs, b xs)
  where
    a :: Partition -> [Int]
    a = a' 1 
    
    a' :: Int -> Partition -> [Int]
    a' _ [] = [] 
    a' k (x:xs) = if (x-k) < 0 then [] 
                               else (x-k): a' (k+1) xs
                        
    b :: Partition -> [Int]                   
    b = a . conjugate 
    
conjugate :: Partition -> Partition
conjugate [] = []
conjugate xs = (length xs): conjugate (filter (>0) (map (\x -> x-1) xs))

conjugate'  :: Frobenius -> Frobenius
conjugate' (x,y) = (y,x) 


--Frobenius to Partition 
ftop :: Frobenius -> Partition
ftop xs = (atop 1 xs) ++ (btop xs)

atop :: Int -> Frobenius -> Partition
atop _ ([],[]) = []
atop i (a:as,b:bs) = (a+i): (atop (i+1) (as,bs) )   

btop :: Frobenius -> Partition
btop = conjugate . btop' 
  where
    btop' :: Frobenius -> Partition
    btop' ([],[]) = []
    btop' (a:as, b:bs) = if (b-length as) <= 0 then []
                       else (b-length as):(btop' (as, bs))  

Fortran 分割からフロベニウス記法 (逆は無し)

Fortran で考えた方が、考えをそのまま書けるので便利です。

実行結果

 3 1 0 : 5 2 1
続行するには何かキーを押してください . . .

ソースプログラム

    module m_young
      implicit none
    contains
      integer function irank(list)
        integer, intent(in) :: list(:)
        do irank = 1, size(list)
          if (list(irank) < irank) exit  
        end do    
        irank = irank -1
      end function irank
      
      function a(list) result(ires)
        integer, intent(in)  :: list(:)
        integer, allocatable :: ires(:)
        integer :: i, n
        n = irank(list)
        allocate(ires(n))
        do i = 1, n
          ires(i) = list(i) - i  
        end do 
      end function a
      
      function b(list) result(ires)
        integer, intent(in) :: list(:)
        integer, allocatable :: ires(:)
        ires = a( conj(list) )
      end function b
    
      function conj(list) result(ires)
        integer, value  :: list(:)
        integer, allocatable :: ires(:), l(:)
        integer :: i
        l = list
        allocate(ires(list(1)))
        do i = 1, list(1)
          ires(i) = size(l)
          l = pack(l - 1, l > 1) 
        end do
      end function conj  
    end module m_young
    
    program Console10
      use m_young
      implicit none
      integer :: i, j, n, nrank
      integer, allocatable :: ll(:)
      ll = [4,3,3,3,1,1]
      print *, a(ll), ':', b(ll)
    end program Console10