fortran66のブログ

fortran について書きます。

Post-Modern Fortran Explanted

近代の超克

Modern Fortran の次は、Post-Modern Fortran の時代が来ると考えられる。そのためには Fortran90/95 により始まった構造化プログラミングを脱構築する必要がある。



Dis-construction から dis-structured へ

COME FROM 文により。
Comefrom Statement

We don't know where to GOTO if we don't know where we've COME FROM. This linguistic innovation lives up to all expectations.
By R. Lawrence Clark*

f:id:fortran66:20170625025309j:plain

GO TO 文と COME FROM 文をセットにして双方向化することで、多くの問題を超克できる。

Bug とは白人中年男性の偏見に過ぎない

現在のコンピュータおよびコンピュータ言語は、いずれも白人中年男性*1により創作されたものであり、いわゆる『バグ』と呼ばれているものは、あくまで白人中年男性の偏見の反映に過ぎない。むしろ尊重されるべき個性である。

たとえば物理法則もニュートンをはじめとする白人中年男性の偏見の一種に過ぎない。したがって、マイノリティーはニュートン力学に従う必要はない。

一つの実例として Lesbian Physics という別の運動体系が存在する。
f:id:fortran66:20170625030652g:plain
Lesbian physics | Anime Amino


http://www.tbs.co.jp/anime/sakura/(2014)



ねむくなったので終わりwww

*1:COBOLのグレイス・ホッパーは、中年にさしかってからアメリカ軍に入隊し白人男性原理の価値観を受け入れたので、白人中年男性に入れる。

ソビエト時代のメインフレームのエミュレーター

ソビエト時代のメインフレームエミュレーター

BESM-6 と呼ばれるもののようです。色々能書きが書いてあります。

BESM-6 Nostalgia Page

昔、ソ連では ALGOL68 コンパイラが標準で使われていて、とても進んでいるという噂でしたが、全ては幻想で、ソ連崩壊後に普通に FORTRAN のコピーが使われていると分かりました。

High-speed computers of the Soviet Union - IEEE Xplore Document

www.computer-museum.ru

なお冷戦終了後、ソ連かぶれの皆さんは支那・朝鮮方面にシフトしてキチガイ度がアップしていますw

WEB版エミュレータページ

ALGOL、FORTRANアセンブラが使えるようです。
FORTRAN は 66 水準のようです。
BESM-6 emulator test


岩波新書1円の価値w

Fortran 入門 f95

ネット上のフリー入門 Fortran95

大阪大学レーザー研 高性能計算機室

公開テキスト
ページ内にLinkあり。

FORTRANのよい入門書がないと相談したところ、レーザー研の共同研究者である摂南大学の田口先生が、ご自分の研究室向けに作られていた入門書を一般的なものに加筆修正して提供してくださいました。 これは、Fortran文法とプログラムの書き方を解説した基礎編、様々な数値計算法を解説した実践編の2部構成の400ページを超す大作として進化し、2015年7月には技術評論社より「Fortranハンドブック」として出版されました。

  • 2011/10/17 第2.1版 2011/7/8(福田) パソコン&スーパーコンピュータで計算するための基礎知識

pdf 1.17MB

  • 2016/3/29 第4版 2013/5/20

摂南大学 田口俊弘先生より
ご提供いただきました) Fortranスマートプログラミング(2015年度版) pdf 930KB

※上記2つの資料の抜粋版は、東北大学の 広報誌(SENAC)に掲載されています。
      詳細はこちら(2012年4月号、7月号、10月号、2013年1月号)。

「並列Fortranの現状と展望」の講演資料公開

Fortranに関するシンポジウム(第3回)

「並列Fortranの現状と展望」
~現代化か肥大化か?~

が六月初旬に無事開催された模様です。以下のページで講演資料が見られます。

並列Fortranに関するシンポジウムのご案内(第3回) - 高性能 Fortran 推進協議会

Fortran ~ modernization or cumbersome ~
Project Editor, ISO/IEC Fortran standard / Numerical Algorithms Group Oxford/Tokyo
Malcolm Cohen

Modern Fortran Explained の著者の一人であり日本 NAG の Malcolm Cohen 氏の講演は、Fortran 規格を定めかつコンパイラを作る側からの視点で甚だ興味深いものです。

オブジェクト指向Fortranが拓く(はずだった)新しい世界
名古屋大学 未来材料・システム研究所
出川 智啓

先ごろ話題になった Fortran 同人の中の人の講演で、Fortran によるオブジェクト指向を解説した力作に基づく講演です。

角川のオンラインストア電子書籍が購入できます。
bookwalker.jp

twitter で正誤表が配られています。


Fortranで高性能計算 ~その仕様使いますか?~
宇宙航空研究開発機構 宇宙科学研究所
高木 亮治

Modern Fortran の仕様の利用とパフォーマンスのバランスについて、実際のプログラムでの使用例をもとに論じられています。

糞アマゾンで売られている海賊版 

Jacob Mason 名義で大量の技術書の海賊版が売られている。もしくはただの詐欺。値段が安いわけでもないので、目的が何なのかよく分からない。ISBN 番号はついているし、このからくりは何なのか?

Michael Metcalf, John Reid & Malcolm Cohen の Modern Fortran Explained が、まんまコピーで売られているw

著作権表示ページのこの手抜き感ww
f:id:fortran66:20170618210537p:plain


アマゾンは中国・韓国人による違法 windows や office 海賊版も一向に取り締まろうとせず、破廉恥極まりない。

本物

日アマゾン

米アマゾン
www.amazon.com

英アマゾン
www.amazon.co.uk

Fortran 三面記事 ウィークエンダー  

www.youtube.com

ARM が自社 CPU 用に HPC 向けの Fortran 2003 水準のコンパイラを出す

ネット新聞によりますと

www.hpcwire.com

HPC 分野の標準の C/C++/Fortran compiler および基本的ライブラリ optimized BLAS, LAPACK and FFTデバッグツールなどを揃えるとのことです。

developer.arm.com

自動ベクトル化機能をもったコンパイラだそうです。
試してみたいものですが、旧型ラズパイのラズビアン環境でゆけるのかよく分かりません。

CoArray Fortran が Jupyter 上で試せる

ネットニュースグループによりますと

「Try Coarray Fortran in the cloud」Zaak氏が Jupyter Notebook 上で CAF が試せるからくりを開発した模様です。Fortran プログラムそのものが動くもようで、F2PY のようにサブルーチンだけというわけではないようです。そのうえで CoArray も動くようです。

https://groups.google.com/forum/#!topic/comp.lang.fortran/_VFKgicY9SE

一応、リンクを踏むと用意してある環境で試せる模様です。

An Empirical Study of Fortran Programs – Don Knuth (1971) [pdf]

ハッカーニュースによりますと
An Empirical Study of Fortran Programs – Don Knuth (1971) [pdf] | Hacker News

Fortran 95/2003 for Scientists & Engineers (5th edition) 値下がり中

アマゾン乞食による貧困調査

米アマゾンで Stephen Chapman の 「Fortran 95/2003 for Scientists & Engineers (第5版)」が 中古 $60 台に値下がり中の模様です。新版が出たせいで値崩れしたものと思われます。1000頁を超える大部の書で $100~$200 していたので大幅安です。CoArray の章が加わったものと思われます。

www.amazon.com




Fortran

NHK カルチャーラジオ アメリカン・ミュージックの系譜 が面白い

第11回【ヒップポップ~知的でクリエイティブな側面】
www4.nhk.or.jp

ヒップホップって、匹夫凡夫の聞く現代のお経のような音楽だと思っていましたが、90年代ポストモダンの文脈から見ると、70年代から最先端を切っていたということで、なかなか面白い解釈でした。

ロックまでの音楽は自己の内側・内面にある衝動のようなものから引き出した何かを音楽という形式で表現していたが、ヒップホップは自己の外側にあるレコードコレクション・データベースから適当にサンプリングして音楽を構成するという点で画期的に新しかったと言われていて、なるほどと思いました。

90年代といえば、庵野エヴァンゲリオンが過去特撮の引用ばかりでもはや創作にオリジナリティは必要ないと言い、押井守攻殻機動隊の登場人物が小難しいことを言いあってるけどあれは裏で外部データベースを必死で検索しての引用合戦なんだ、と言われていたのを思い出します。

元曲のお気に入り部分以外は要らないから捨てるという発想はすがすがしい限りです。2000年代からの日常系萌四コマアニメへの進化に通ずるものがあると思います。

アマゾンがホール・フーズ・マーケット買収

新聞によりますと
www.nikkei.com

最近ホールフーズの売り上げが落ち目になってきて、店舗改革がプレミアム感を落としてうまくいっていないというニュースが出ていましたが、赤字になる前にアマゾンに見切り売りのようです。ショッピングモール形式が時代遅れになりつつあるようでアマゾン独り勝ちです。アマゾンはマーケットプレイス業者向けの金貸し事業も始めたようで、ゆりかごから墓場までアマゾンに支配されそうです。

そのうちアマゾンが CPU メーカーを買収して amazon Fortran が出る日も近い。数値は三割引きで表示とか。

むかしホールフーズマーケットで、伊藤園のペットボトルのお茶が健康食品として $2 で売られていて愛飲していましたが、米国向けはミニマルアート風のこじゃれた外装で、おーい!お茶などのダジャレた外装と対極をなしていました。

ホールフーズは、金持白人がプリウスBMW で乗り付ける意識高い系と馬鹿にされる店なので、アマゾンの19世紀的強盗資本主義のノリと合わないと思うのですが・・・

CAF と MPI 例題比較  その2

W. Gropp 等の Using MPI の例題を CAF で書き直してみるつもりが、二個目の例題で早くも大苦戦で苦笑。


CAF の sync によるバリアでは、任意の imeage を1個を待つことができないようで、manager-worker 型の処理に困りました。集団通信のように任意の順で来る全員を待つことはできるが、任意の一名が出頭すればよろしいとい形にはできないようです。(それとも何か理解を間違えているのか?w)

配列 A を coarray にして、worker 側から get 出来るようにすれば色々すっきりするので、元々こういう manager-worker 型の構造は取る必要はないのかもしれません。 

とりあえず仕方がないので、manager-worker 間の制御には atomic 変数による spin-wait loop を例題から借りてきて、worker 間の排他処理には lock を用いました。citical だと内部で sync が使えないようなので、lock を用いる必要がありました。

参考:J. Reid (2009), "Coarrays in Fortran 2008"
ftp://cuter.rl.ac.uk/pub/talks/jkr.pgas.7X09.pdf

CAF

例題では c = Axb を計算しています。manager に当たる image 1 がデータの配布と結果の回収をおこない、image 2 以降が積を計算します。データの回収と配布に2回の sync が必要になります。

ソースプログラム

まだごちゃごちゃしています。intelコンパイラのバグで debug モードでうまくいかないところがあるので回避しています。手抜きの為、MPI 版にあるプロセッサ数が行列次元より大きい場合の処理を省略しました。

    program CAF3_5
      use, intrinsic :: iso_fortran_env
      implicit none
      integer, parameter :: kd = kind(1.0d0)
      integer, parameter :: MAX_ROWS = 1000, MAX_COLS = 1000
      real(kd) :: a(MAX_ROWS, MAX_COLS), b(MAX_COLS)[*]
      real(kd) :: c(MAX_ROWS), buffer(MAX_COLS)[*], ans[*]
      integer :: rows, cols
      integer :: myid, numprocs
      integer :: i, j, numsent, cnt = 0
      integer :: row[*], no[*]

      logical(atomic_logical_kind) :: locked[*] = .true.
      logical :: val
      
      type(lock_type) :: list_lock[*]  

      myid     = this_image()
      numprocs = num_images()
      
!      manager = 1
      rows = 100
      cols = 100
      !
      ! Initialize A, b ; Broadcast b
      !
      if (myid == 1) then
        do j = 1, cols
          b(j) = 1
          do i = 1, rows
            a(i, j) = i 
          end do
        end do
        sync images(*) ! Broadcast b
        numsent = 0
      else
        sync images(1)  
        b(:) = b(:)[1]  
      end if
      !
      ! send initial data
      !
      if (myid == 1) then
        do i = 2, numprocs
          numsent = numsent + 1
          row[i] = numsent
!          buffer(:)[i] = a(numsent, :)  ! intel fortran v.18 bug in debug mode
          do j  = 1, rows
            buffer(j)[i] = a(numsent, j)  
          end do
          sync images (i)
        end do    
      else
        sync images (1)
      end if
      !
      ! main loop
      !
      do 
        if (myid == 1) then
          val = .true.   ! Spin-wait loop
          do while (val)
            call atomic_ref(val, locked)  
          end do    
          sync memory
          call atomic_define(locked, .true.)   
          ! receive data
          sync images(no)
          c(row) = ans  
          ! send new data
          numsent = numsent + 1
          row[no] = numsent
          if (numsent > rows) then 
            row[no] = 0
            cnt = cnt + 1
            if (cnt >= numprocs - 1) then 
                sync images (no)
                exit
            end if    
          end if  
!          buffer(:)[no] = a(numsent, :)  ! intel fortran v.18 bug in debug mode
          do j  = 1, rows
            buffer(j)[no] = a(numsent, j)  
          end do
          sync images(no)
        else
          if (row == 0) exit
          ans = dot_product(buffer, b)
          lock(list_lock[1])  
            ! send result
            no[1] = myid
            sync memory
            call atomic_define(locked[1], .false.) ! release image 1 from spin loop
            row[1] = row
            ans[1] = ans
            sync images (1) ! send result
            sync images (1) ! recv new data
          unlock(list_lock[1])  
        end if    
      end do    
      if (myid == 1) print *, c(:rows) 
      sync all
    end program CAF3_5
実行結果
   100.000000000000        200.000000000000        300.000000000000
   400.000000000000        500.000000000000        600.000000000000
   700.000000000000        800.000000000000        900.000000000000
   1000.00000000000        1100.00000000000        1200.00000000000
   1300.00000000000        1400.00000000000        1500.00000000000
   1600.00000000000        1700.00000000000        1800.00000000000
   1900.00000000000        2000.00000000000        2100.00000000000
   2200.00000000000        2300.00000000000        2400.00000000000
   2500.00000000000        2600.00000000000        2700.00000000000
   2800.00000000000        2900.00000000000        3000.00000000000
   3100.00000000000        3200.00000000000        3300.00000000000
   3400.00000000000        3500.00000000000        3600.00000000000
   3700.00000000000        3800.00000000000        3900.00000000000
   4000.00000000000        4100.00000000000        4200.00000000000
   4300.00000000000        4400.00000000000        4500.00000000000
   4600.00000000000        4700.00000000000        4800.00000000000
   4900.00000000000        5000.00000000000        5100.00000000000
   5200.00000000000        5300.00000000000        5400.00000000000
   5500.00000000000        5600.00000000000        5700.00000000000
   5800.00000000000        5900.00000000000        6000.00000000000
   6100.00000000000        6200.00000000000        6300.00000000000
   6400.00000000000        6500.00000000000        6600.00000000000
   6700.00000000000        6800.00000000000        6900.00000000000
   7000.00000000000        7100.00000000000        7200.00000000000
   7300.00000000000        7400.00000000000        7500.00000000000
   7600.00000000000        7700.00000000000        7800.00000000000
   7900.00000000000        8000.00000000000        8100.00000000000
   8200.00000000000        8300.00000000000        8400.00000000000
   8500.00000000000        8600.00000000000        8700.00000000000
   8800.00000000000        8900.00000000000        9000.00000000000
   9100.00000000000        9200.00000000000        9300.00000000000
   9400.00000000000        9500.00000000000        9600.00000000000
   9700.00000000000        9800.00000000000        9900.00000000000
   10000.0000000000
続行するには何かキーを押してください . . .

MPI Figs. 3-5, 3-6, 3-7 from W.Gropp et. al.

ソースプログラム
    program MPI3_5
      use mpi
      implicit none
      integer, parameter :: kd = kind(1.0d0)
      integer, parameter :: MAX_ROWS = 1000, MAX_COLS = 1000
      integer :: rows, cols
      real(kd) :: a(MAX_ROWS, MAX_COLS), b(MAX_COLS)
      real(kd) :: c(MAX_ROWS), buffer(MAX_COLS), ans
      
      integer :: myid, manager, numprocs, ierr, status(MPI_STATUS_SIZE)
      integer :: i, j, numsent, sender
      integer :: anstype, row
      
      call MPI_INIT(ierr)
      call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
      call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
      manager = 0
      rows = 100
      cols = 100
      
      if (myid == manager) then
        do j = 1, cols
          b(j) = 1
          do i = 1, rows
            a(i, j) = i
          end do
        end do
        numsent = 0
        !
        call MPI_BCAST(b, cols, MPI_DOUBLE_PRECISION, manager, MPI_COMM_WORLD, ierr)
        !
        do i = 1, min(numprocs - 1, rows)
          do j = 1, cols
            buffer(j) = a(i, j)
          end do
          call MPI_SEND(buffer, cols, MPI_DOUBLE_PRECISION, i, i, MPI_COMM_WORLD, ierr)
          numsent = numsent + 1
        end do
        do i = 1, rows
          call MPI_RECV(ans, 1, MPI_DOUBLE_PRECISION, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, status, ierr)
          sender  = status(MPI_SOURCE)
          anstype = status(MPI_TAG)
          c(anstype) = ans
          if (numsent < rows) then
            do j = 1, cols
              buffer(j) = a(numsent + 1, j)
            end do    
            call MPI_SEND(buffer, cols, MPI_DOUBLE_PRECISION, sender, numsent + 1, MPI_COMM_WORLD, ierr)
            numsent = numsent + 1
          else
            call MPI_SEND(MPI_BOTTOM, 0, MPI_DOUBLE_PRECISION, sender, 0, MPI_COMM_WORLD, ierr)  
          end if    
        end do  
      else
        call MPI_BCAST(b, cols, MPI_DOUBLE_PRECISION, manager, MPI_COMM_WORLD, ierr)
        if (myid <= rows) then
          do 
            call MPI_RECV(buffer, cols, MPI_DOUBLE_PRECISION, manager, MPI_ANY_TAG, MPI_COMM_WORLD, status, ierr)
            if (status(MPI_TAG) == 0) exit
            row = status(MPI_TAG)
            ans = 0.0_kd
            do i = 1, cols
              ans = ans + buffer(i) * b(i)
            end do  
            call MPI_SEND(ans, 1, MPI_DOUBLE_PRECISION, manager, row, MPI_COMM_WORLD, ierr)
          end do  
        end if  
      end if
      call MPI_FINALIZE(ierr)
      if (myid == 0) print *, c(:cols) 
    end program MPI3_5
実行結果
C:\Program Files (x86)\IntelSWTools>mpiexec -n 4 "C:\Users\O\Documents\Visual Studio 2015\Projects\MPI\Console2\x64\Debug\Console2.exe"
   100.000000000000        200.000000000000        300.000000000000
   400.000000000000        500.000000000000        600.000000000000
   700.000000000000        800.000000000000        900.000000000000
   1000.00000000000        1100.00000000000        1200.00000000000
   1300.00000000000        1400.00000000000        1500.00000000000
   1600.00000000000        1700.00000000000        1800.00000000000
   1900.00000000000        2000.00000000000        2100.00000000000
   2200.00000000000        2300.00000000000        2400.00000000000
   2500.00000000000        2600.00000000000        2700.00000000000
   2800.00000000000        2900.00000000000        3000.00000000000
   3100.00000000000        3200.00000000000        3300.00000000000
   3400.00000000000        3500.00000000000        3600.00000000000
   3700.00000000000        3800.00000000000        3900.00000000000
   4000.00000000000        4100.00000000000        4200.00000000000
   4300.00000000000        4400.00000000000        4500.00000000000
   4600.00000000000        4700.00000000000        4800.00000000000
   4900.00000000000        5000.00000000000        5100.00000000000
   5200.00000000000        5300.00000000000        5400.00000000000
   5500.00000000000        5600.00000000000        5700.00000000000
   5800.00000000000        5900.00000000000        6000.00000000000
   6100.00000000000        6200.00000000000        6300.00000000000
   6400.00000000000        6500.00000000000        6600.00000000000
   6700.00000000000        6800.00000000000        6900.00000000000
   7000.00000000000        7100.00000000000        7200.00000000000
   7300.00000000000        7400.00000000000        7500.00000000000
   7600.00000000000        7700.00000000000        7800.00000000000
   7900.00000000000        8000.00000000000        8100.00000000000
   8200.00000000000        8300.00000000000        8400.00000000000
   8500.00000000000        8600.00000000000        8700.00000000000
   8800.00000000000        8900.00000000000        9000.00000000000
   9100.00000000000        9200.00000000000        9300.00000000000
   9400.00000000000        9500.00000000000        9600.00000000000
   9700.00000000000        9800.00000000000        9900.00000000000
   10000.0000000000