配列シフト関数

Fortran90 で導入された配列シフト関数を用いてプログラムを書いて見ます。元々は、二次元トーラス型のメッシュをしたアレイプロセッサ型の並列コンピュータ用の命令だと思います。つまり、二次元配列の各要素がメッシュ状のプロセッサに割り当てられて計算され、隣接のプロセッサと通信が可能になっているハードウェア用の命令だと思います。現今のハードウェアに対しては全く適切ではないと思います。

この命令のいいところは境界の扱いを自動で処理してくれるところにあります。eoshift は境界値固定、cshift はトーラス状の周期境界値となります。

#eoshift を用いたラプラス方程式
ラプラス方程式を反復法で解きます。中央部に電位 5eV の矩形電極があり、境界がアースされて 0eV になっている矩形の電位分布を求めます。

配列シフト関数で上下左右の４座標の電位の平均値を求めています。普通は境界での例外処理に手間取るのですが、eoshift を用いればその必要がありません。ここでは境界を全て 0.0 としましたが、配列により任意の境界値を与えることができます。

##プログラム
```fortran
    program Laplace
      implicit none
      integer, parameter :: n = 20
      real :: y(-n:n, -n:n) = 0.0
      logical :: mask(-n:n, -n:n) = .false.
      integer :: iter
      mask(-5:5, -5:5) = .true.
      where (mask) y = 5.0
      do iter = 1, 500
        where (mask)
        elsewhere   
          y =  ( eoshift(y, 1, dim = 1) + eoshift(y, -1, dim = 1) &
               + eoshift(y, 1, dim = 2) + eoshift(y, -1, dim = 2) ) / 4.0
        end where  
        call execute_command_line('cls')
        print '(41i1)', int(y) 
      end do  
    end program Laplace
```

##実行結果　収束値
電位を切り捨てで１桁だけプロットしています。

```
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
00000000000000111111111111100000000000000
00000000000111111111111111111100000000000
00000000011111111111111111111111000000000
00000000111111111111111111111111100000000
00000001111111122222222222111111110000000
00000011111112222222222222221111111000000
00000011111122222222222222222111111000000
00000111111222223333333332222211111100000
00000111112222333333333333322221111100000
00000111122223333444444433332222111100000
00001111122233344444444444333222111110000
00001111222233455555555555433222211110000
00001111222333455555555555433322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222334455555555555443322211110000
00001111222333455555555555433322211110000
00001111222233455555555555433222211110000
00001111122233344444444444333222111110000
00000111122223333444444433332222111100000
00000111112222333333333333322221111100000
00000111111222223333333332222211111100000
00000011111122222222222222222111111000000
00000011111112222222222222221111111000000
00000001111111122222222222111111110000000
00000000111111111111111111111111100000000
00000000011111111111111111111111000000000
00000000000111111111111111111100000000000
00000000000000111111111111100000000000000
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
00000000000000000000000000000000000000000
続行するには何かキーを押してください . . .
```
#cshift を用いたライフゲーム
ライフゲームはセルオートマトンの一種で、コンピュータ界では昔からよく扱われています。座標ごとに生死の二値をとるとして、ある座標の周囲８マスの生者の総和により、その座標での生死が定まります。

周囲８マスの生者の相和を求めるのに cshift 関数を用いました。斜めの値を直接得られないので、少し冗漫になっています。しかし、境界での例外処理の必要がないので便利です。

##プログラム
windows の dos 窓で見易く実行するため非標準の sleepqq 命令を用いましたが、適当に時間稼ぎをする処理で代替できます。

```fortran
    program Life
      implicit none
      integer, parameter :: nx = 40, ny = 20
      character (len = 80) :: fmt
      integer :: itab(nx, ny) = 0, itmp(nx, ny) = 0
      real :: tmp(nx, ny)
      integer :: iter
      write(fmt, '(a, i5, a)') '(', nx, 'i1)'
      call random_seed()
      call random_number(tmp)
      where (tmp > 0.8) itab = 1
      do iter = 1, 1000
        call execute_command_line('cls')
        print fmt, itab
        itmp =  cshift(itab, 1, dim = 1) + cshift(itab, -1,  dim = 1) &
              + cshift(itab, 1, dim = 2) + cshift(itab, -1,  dim = 2) &
              + cshift(cshift(itab,  1, dim = 1),  1, dim = 2) &
              + cshift(cshift(itab,  1, dim = 1), -1, dim = 2) &
              + cshift(cshift(itab, -1, dim = 1),  1, dim = 2) &
              + cshift(cshift(itab, -1, dim = 1), -1, dim = 2) 
        where (itmp >= 4 .or. itmp <= 1)
          itab = 0
        elsewhere (itmp == 3)
          itab = 1
        end where
        call sleepqq(300) ! non-standard MS-Windows
      end do  
    end program Life
```

##実行結果
定常状態に入って終わりました。

```
0000001000000000000000000000000000000000
0000000000000000000000000000000000000000
0011100011100000000000000000000000000000
0000000000000000000000000000000000000000
0000001000000000000000000000000000000000
0000001000000000000000000000000000000000
0000001000000000000000000000000000000000
0000000000000000000000000100000000000000
0100000000000000000000001010000000000000
1010000000000000000000001010000000000000
1010000000000000000000000100000000000000
0100000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000001110000000000
0000000000000000000000000000000000000000
0000000000000000000110000100000100000000
0000000000000000000110000100000100000000
0000000000000000000000000100000100000000
0000001000000000000000000000000000000000
0000001000000000000000000001110000000000
```