2019年2月13日水曜日

セル・オートマトン

ソースコードは下記アドレス


1次元のセル・オートマトンにルール30を適用して得た画像。

一部Repaを使ってみました。



import Rule
import Prelude as P
import System.Environment
import Data.Array.Repa.IO.BMP
import Data.Array.Repa as R
import Control.Parallel.Strategies
getN :: IO Int
getN = do
a:_ <- getArgs
return $ read a
cells = 1001
fs :: [Bool]
fs = cs P.++ [b] P.++ cs
where cs = replicate n w
n = cells `div` 2
is = P.map (\x -> (x, x+1, x+2)) [0..(cells - 1)]
nextC :: Int -> (Bool,Bool,Bool) -> Bool
nextC rl (a,b,c) = rule rl i
where i = bToI [a,b,c]
loop t a n = do
rl <- getN
if n == 0
then return a
else do
let tt = (last t:t) P.++ [head t] --セル列の両端はリング状につながっている。
let ta = R.fromListUnboxed (Z :. cells+2) tt:: R.Array R.U R.DIM1 Bool
let toA = P.map (\x -> nextCell rl x ta) is
`using` parListChunk 100 rdeepseq
loop toA (toA P.++ a ) (n-1)
where nextCell rl (a,b,c) tt = nextC rl (tt ! (Z :. a), tt ! (Z :. b), tt ! (Z :. c))
main = do
bs <- loop fs fs (cells `div` 2)
let bbs = R.fromListUnboxed (Z :. (cells*(cells `div` 2 + 1))) bs :: R.Array R.U R.DIM1 Bool
let a = R.map (\x -> if x then bk else wt) bbs
computeP ( reshape (Z :. (cells `div` 2 + 1) :. cells) a) >>= (writeImageToBMP "a.bmp")
view raw cellA.hs hosted with ❤ by GitHub


module Rule where
import Data.Bits
import GHC.Word
rule :: Int -> Int -> Bool
rule = testBit
bk,wt :: (GHC.Word.Word8, GHC.Word.Word8, GHC.Word.Word8)
bk = (0,0,0)
wt = (255,255,255)
b,w :: Bool
b = True
w = False
bToI :: [Bool] -> Int
bToI bs = foldl (\x (y,z) -> if z then setBit x y else clearBit x y) (0::Int)
$ zipWith (\a b -> (a,b)) [0 ..] $ reverse bs
~
view raw Rule.hs hosted with ❤ by GitHub


以下のインストール が必要。

$ cabal update -v
$ cabal install repa -v
$ cabal -v install repa-io
$ cabal install parallel -v

コンパイルは

$ ghc -O2 -threaded -rtsopts --make -XFlexibleContexts -eventlog cellA.hs

作成された実行ファイルを実行します。

$ ./cellA 110 +RTS -N2 -l

ルールはコマンドライン引数で与えます。

eventlog が作成されます。

$ threadscope cellA.eventlog

 一応2コアで動いています。



ルール110の実行例。

$ display a.bmp

ルール45
ルール225

0 件のコメント:

コメントを投稿

Haskell Process

Haskellの System.Processは便利ですが、問題もあります。 単一スレッドでの逐次処理を保証していない。(想像です。) 次のようなスクリプトを書いてみた。 --a.hs main = print [1..10] --t.hs import Sy...