2025年4月7日月曜日

myPlayer


-- pipe.hs
import System.Process
import System.Environment
main :: IO () 
a:_ <- getArgs
    (_, Just so, _, _)  <- createProcess (proc "runghc" ["randomList.hs",a]) { std_out = CreatePipe } 
    _ <- createProcess (proc "/home/i/myPlayer/viewer" []) { std_in = UseHandle so }
    return ()

-- randomList.hs
import System.Random
import System.Process
import System.Posix.Time (epochTime)
import System.Environment
import System.Directory
import System.FilePath.Posix
imnum = 10
lines' = return . lines
randomize :: [FilePath] -> IO [FilePath]
randomize lst = do
    let c = length lst
    r <- fromEnum <$> epochTime >>= (\x -> return (randomRs (0, (c-1)) (mkStdGen x) ))
    return [lst !! x|x <- take imnum r]
dirFilePairs :: [FilePath] -> IO [(FilePath,FilePath)]
dirFilePairs lst = return [(takeDirectory x,x) | x <- lst]
fileFilePairs :: [(FilePath,FilePath)] -> IO [(FilePath,FilePath)]
fileFilePairs = mapM (\(a,b) -> do{aa <- getAA a; return (aa,b)})
    where
        getAA p = do
            fs <- listDirectory p >>= filtFile ".jpg"
            if fs == [] then return "cd.jpg"
                        else return $ p ++ ['/'] ++ head(fs)
        filtFile ex = return . filter (\x -> takeExtension x == ex)
main = do
    fs <- getArgs >>= \(a:_) -> readFile a
    lines' fs >>= randomize >>= dirFilePairs >>= fileFilePairs >>= print
                                                                                                                      1,1          全て

-- viewer.hs
import Graphics.UI.Gtk
import System.Process
import MyButton
iSize = 100
getAps :: IO [(FilePath,FilePath)]
getAps = getContents >>= return . read
func1 f = createProcess (proc "audacious" [f]) >> return ()
main = do
    aps <- getAps
    initGUI
    w <-  windowNew
    set w [windowWindowPosition := WinPosNone,
            windowDefaultWidth := 400, windowDefaultHeight := 900]
    vb <- vBoxNew False 0
    sw <- scrolledWindowNew Nothing Nothing
    scrolledWindowAddWithViewport sw vb
    containerAdd w sw
    bs <- mapM (\(a,b) -> newImgButton iSize (a,b) func1) aps
    mapM (containerAdd vb) bs
    widgetShowAll w
    w `on` unrealize $ mainQuit
    mainGUI
~            
-- MyButton.hs
module MyButton where
import Graphics.UI.Gtk
newImgButton size (f,f') func = do
    p <- pixbufNewFromFileAtSize f size size
    i <- imageNewFromPixbuf p
    b <- buttonNew
    set b [buttonImage := i]
    l <- labelNew $ Just $ drop 12 f'
    set l [labelWrap := True]
    hb <- hBoxNew False 0
    containerAdd hb b
    containerAdd hb l
    b `on` buttonActivated $ func f'
    return hb
      

2020年5月23日土曜日

Haskell Process

Haskellの System.Processは便利ですが、問題もあります。

単一スレッドでの逐次処理を保証していない。(想像です。)

次のようなスクリプトを書いてみた。

--a.hs
main = print [1..10]

--t.hs
import System.Process
loop x = createProcess (proc "runghc" ["a.hs"]) >> return ()
main = mapM_ loop [1..100]

実行結果。

$ runghc t.hs
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,[1,2,3,4,5,6,7,8,9,1[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
0]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,[1,2,3,4,5,6,7,8,9,10]
,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10[1,2,3,4[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4[1,2,3,4,5,6,7,8,9,10]
i@i:~/haskell$ [1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,,[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
]
[1,2,3,4,5,6,7,8,9,10]
,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3[1,2,3,4,5,6,7,8,9,10,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
,[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
]
[1,2,3,4,5,6,[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[[1,2,3,4,5,6,7,8,9,10]
1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,1[1,2,3,4,5,6,7,8,9,10]
7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
0[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
]
[1,2,3,4,5,6,7,8,9,10]
[[1,2,3,4,5,6,7,8,9,10]
1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8[1,2,3,4[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,,,5,6,[7,8,19,1,02]
,3,4,5,6,7,8,9,10]
9,10]
[1,2,3,4,5,6,7,8,9,10]
5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]

[1..10]のリストを書き終える前に次のリストを書き始めている。
100回のLoop の途中で t.hs スクリプトを終了している。

深い意味は僕には不明ですが、実用プログラムで使う場合には注意が必要なのでは・・・。

2019年2月13日水曜日

セル・オートマトン

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


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

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







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

$ 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

2018年12月3日月曜日

Github リポジトリにファイルを追加

Githubのリポジトリにファイルをグラフィカルに追加する方法。 記事が少なくなかなかわからなかった。

赤丸の位置にファイルブラウザーから追加したいファイル(複数可)をドラッグすればよい。
内容の更新も同様。

update files というボタンを押してもよい。

2018年11月2日金曜日

Module ‘System.Cmd’ is deprecated

--b.hs 
import System.Cmd 
main = rawSystem "ls" ["-lh"] 

$ runghc b.hs
b.hs:1:1: Warning:
     Module ‘System.Cmd’ is deprecated: Use "System.Process" instead


import  System.Process 
main = createProcess (proc"ls" ["-lh"])

2018年6月21日木曜日

複素数

Pythonは複素数を直接書くことができます。

Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a=0+1j
>>> a
1j

実数部が0のとき省略できます。

>>> a=1j
>>> a
1j

虚数部が0のときこれも省略できます。

>>> b=1
>>> b
1

これはただの実数ですが複素数と組み合わせるとちゃんと複素数の計算をしてくれます。

>>> a-b
(-1+1j)

複素数は距離の計算をとても楽にしてくれます。

a,b 2点間の距離は差をとって絶対値を計算すればよい。

>>> d=abs(a-b)
>>> d
1.4142135623730951

これは√2です。
これをbに代入します。

>>> b=d
>>> b
1.4142135623730951
>>> d=abs(a-b)
>>> d
1.7320508075688774

これは√3です。
このように計算結果を次々に代入していけば全ての整数の平方根がもとめられます。
(複素数の計算の内部で sqrt を使っているのでは? というツッコミはあると思いますが無視してください)

Haskellではこのような記法はできません。
Data.Complex モジュールの

(:+)

というコンストラクターで複素数のインスタンスをつくります。
Haskellではコンストラクターは関数であり、(:+)は演算子として定義されているので次のようにします。

GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> import Data.Complex
Prelude Data.Complex> let a=0:+1
Prelude Data.Complex> a
0 :+ 1
Prelude Data.Complex> let b=1:+0
Prelude Data.Complex> b
1 :+ 0

ちょっと不格好ですが・・・

Haskell は、複素数の絶対値を複素数で返します。

Prelude Data.Complex> abs(a-b)
1.4142135623730951 :+ 0.0

これは abs が
abs :: Num a => a -> a
と定義されているからです。
かわりにmagnitudeをつかいます。

Prelude Data.Complex> :t magnitude
magnitude :: RealFloat a => Complex a -> a

Prelude Data.Complex> magnitude(a-b)
1.4142135623730951

ちなみに Data.Complex では abs を
abs z               =  magnitude z :+ 0
と再定義しているようです。(^_^;)

N−1 の平方根がわかれば N の平方根が計算できることから再帰的に定義できます。

--r.hs
import Data.Complex
dist a b = magnitude (a-b)
a = 0 :+ 1
r 0 = 0
r n = dist a b
    where b = r (n-1) :+ 0


Prelude> :l r.hs
[1 of 1] Compiling Main             ( r.hs, interpreted )
Ok, modules loaded: Main.
*Main> map r [0..9]
[0.0,1.0,1.4142135623730951,1.7320508075688774,2.0,2.23606797749979,2.4494897427831783,2.6457513110645907,2.8284271247461903,3.0000000000000004]

容易に想像できると思いますがNが大きくなると時間がかかるようになります。

*Main> :set +s
*Main> r 1000000
1000.0000000000299
(7.74 secs, 1,673,363,512 bytes)

このような再帰は fold で置き換えることができます。

*Main> let r' n = foldl (\x _ -> dist a (x :+ 0)) 0 [1..n]
*Main> r' 1000000
1000.0000000000299
(5.28 secs, 1,474,441,216 bytes)

さらに Data.List モジュールの foldl'  を使うと

*Main> import Data.List
*Main Data.List> let r'' n = foldl' (\x _ -> dist a (x :+ 0)) 0 [1..n]
*Main Data.List> r'' 1000000
1000.0000000000299
(2.52 secs, 1,293,766,728 bytes)

magnitude 自体が重い処理なのでそこそこかかります。

fold を使ったコードは最初に説明した手続き的処理をそのまま置き換えている点に注目です。

手続き的なscanlの説明
参照

余談ですが (:+) の型は 

Prelude Data.Complex> :t (:+)
(:+) :: a -> a -> Complex a

です。引数の型は何でもいいようです。ですので

Prelude Data.Complex> "hello" :+ "world"
"hello" :+ "world"
Prelude Data.Complex> :t it
it :: Complex [Char]

もちろん演算とかはできません。

2017年12月9日土曜日

gist.github の罠

上のコードをコピペして実行する。

$ runghc a.hs

a.hs:3:11: error: Variable not in scope: n

たぶんこのようなエラーになるはずです。
最初はなぜエラーになるのか理解できませんでした。


Vim上ではまったく見た目は同じです。

カーソルをのせてみると違いがわかります。






show してみると

$ runghc b.hs
"n"
"\65358"

65358は、16進の"ff4e"
つまりUnicodeの小文字 n です。
対して2行目の n はアスキー。

これはコードを日本語入力がONのまま修正したことでおこりました。
見た目は同じでも異なる文字なのでエラーとなりました。

2017年11月6日月曜日

ギヤ比

ソースコード
https://github.com/index333/gear

ギヤ比は一般には単に前後の比率で表します。
例えばフロント30T x リヤ20Tの場合
30➗20で1.50

欧米では伝統的にダルマ型自転車の前輪径に換算します。
30x20の場合
27x1.5=41インチギヤ
のように表現します。
欧米式の利点は小径車にも統一的に使えることです。
上の場合
20x1.5=30インチギヤとなります。
逆にロードレーサーの41インチギヤと同じ速度を小径車で得るには
30x15あるいは39x20という前後の組み合わせが必要となります。


ケーデンスを固定した時の時速で表したほうが直感的と思います。

まずタイヤ周長を選択します。

データはキャットアイのページからコピーしました。

$ cat tires
18-622 700x18C 2070 207
19-622 700x19C 2080 208
20-622 700x20C 2086 209
23-622 700x23C 2096 210
25-622 700x25C 2105 211
28-622 700x28C 2136 214
30-622 700x30C 2146 215
32-622 700x32C 2155 216
xx-xxx  Tubular 2130 213
35-622 700x35C 2168 217
38-622 700x38C 2180 218
40-622 700x40C 2200 220
42-622 700x42C 2224 222
44-622 700x44C 2235 224
45-622 700x45C 2242 224
47-622 700x47C 2268 227

$ cat tires | runghc selectItem.hs > tmp
$ cat tmp
23-622 700x23C 2096 210


Round モジュール、MySpinBox モジュールが必要です。
$ cat tmp | runghc gear.hs

2017年11月3日金曜日

pcd,歯底距離

チェーンリングのPCD(ピッチ・サークル・ダイアメーター)を計算します。
チェーンリングのPCDとはチェーン用ギヤにチェーンを巻きつけたときチェーンピンが形作る仮想円の直径のことです。
これは1辺の長さが12.7mmの正N角形に外接する円の直径の計算に還元できます。
(
クランクのPCDと区別するため、あちらはBCD(ボルト・サークル・ダイアメーター)と表現します
)
次に歯底距離を計算します。

歯底距離を測ればチェーンリングの歯数がわかります。

$ ghci
Prelude> :l Ch.hs
[1 of 1] Compiling Ch               ( Ch.hs, interpreted )
Ok, modules loaded: Ch.
*Ch> rd0 43
(43,166)
*Ch> rd0 44
(44,170)

歯底距離が166mmであれば歯数は43T
歯底距離が170mmであれば歯数は44T

チェーリングのPCDとリヤスプロケットのPCDがわかれば、シングル・バイクのチェーン長が計算できます。

芯間距離(チェーンステイ長)405mm、前スプロケット歯数48Tそして後スプロケット歯数16Tの場合

*Ch> chlen 48 16 405
1226.491724535387
*Ch> it / p
96.57415153821945

97リンク。(半コマ使用時)
98リンク。(半コマ不使用時)

チェーン長計算は下図を参考にしてください。


SpinBoxで入力を楽に

初期データは「tmp]に

$ cat tmp
[48.0,16.0,405.0]




スプロケを交換したときに
リヤアクスルが何ミリ移動するか計算します。

2017年11月1日水曜日

ランダム法

「Haskell98標準のrandomパッケージは、1.長くない周期、2.Haskell98由来の古いAPIの制約で内部状態を毎回コピーする、3.そのため遅い、4.CPU時間と現在時間で初期化(ポケモンかな???)など、過去に標準だったため多くの環境で使用出来ると考えられる、という点以外に余りお勧めできる所が有りません。」
(Haskellの乱数事情より)
https://qiita.com/philopon/items/8f647fc8dafe66b7381b

だそうですがここでは便利さをとり
 System.Random
モジュールを使います。

 System.Randomモジュールはcabalコマンドでパッケージを導入しなければなりません。
まず

sudo apt install cabal-install

でcabalをインストール。

$ cabal update -v
$ cabal install random -v

でImportできるようになります。
結構時間がかかるので -v オプションをつけて経過を見ながら。

なお表題の「ランダム法」はランダムを使っているという意味であり「モンテカルロ法」とは関係ありません。

基本のコードは



これで、未知数が一つ、解の範囲があらかじめ推測できるという条件の方程式を解くことができます。

上のコードに

root n x = evalStateT (try (pf n x)) (1,x) >>= return
pf n x g = g^n < x
main = root 2 2 >>= print

を付け加えて実行しますと

$ runghc -XFlexibleContexts  randomMethod.hs
(1.4142135623728276,1.4142135623731693)

3角形の3辺の長さがわかっていれば、その形と大きさが決まることから面積を計算できるはずです。
ヘロンの公式です。
ちなみにヘロンの公式はHaskellでは極めて簡潔にこう書けます。
heron a b c = sqrt (s*(s-a)*(s-b)*(s-c)) where s = (a+b+c) / 2

余談ですがどんな複雑な形の土地でも3角形に分割することで巻き尺1本で面積計算ができます。
(ただし平面地)
ヘロンの公式が思い出せなくてもランダム法で直感的に解くことができます。

三角形の3辺の長さが a,b,c で

bを複素平面上の実数軸においたとき、
三角形の頂点は極座標で
(a,θ)
で表せます。
このθをランダム法で探ればよいのです。




$ runghc -XFlexibleContexts  heron.hs
6.0

円に内接する正6角形と、同じ円に外接する正4角形を考えると、
円周率は3と4の間に存在するとわかります。
3と4の間の実数のどれかはπの近似値になるはずです。
では、それをランダム法で求められるでしょうか。
残念ながらできません。円周率を求める方程式が存在しないからです。

複素数を使えば間接的にπを求めることはできます。
複素数 c=-1+0i を極座標で表しますと (1、π)
位相を未知数θとして θを 3と 4 の間で、さまざまに変化させ c と近似する値をみつければよい。

でもこれはチートなのでは?

2017年10月31日火曜日

2017年10月30日月曜日

手続き的なscanlの説明


手続き的なscanlの説明 foldの動作をxへの代入、再代入と捉えると分かりやすくなります。 直接foldの動きを見るのではなく、 まずscanlの動作を見てみます。 scanlの型は Prelude> :t scanl scanl :: (a -> b -> a) -> a -> [b] -> [a] となっています。 scanlは、2引数の関数と初期値と何らかのリストを引数にとり、リストを返す関数です。 実際に動かしてみましょう。 Prelude> scanl(\x y -> x + y) 0 [1..3] [0,1,3,6] scanlが内部で何をやっているのか想像してみます。 まずscanlが呼び出されたとき、変数xに初期値、(この場合は「0」)を代入します。 次に変数yにリストの最初の要素(この場合は「1」)を代入します。 次にx+yを計算して結果の「1」をxに再代入します。 次にyにリストの次の要素「2」を代入し、x+yを計算します。この時xは1になっていますので, 結果は「3」です。これをxに再代入します。 次にyにリストの次の要素「3」を代入し、x+yを計算します。この時xは3になっていますので,結果は「6」です。これをxに再代入します。 リストの終わりに到達したので、リスト[0,1,3,6]を出力して終了します。 scanlはxに値が代入された時はすべてその値をリストに保存するようです。 こう見ますとfoldlはscanlと動作は同じで終了時にxの値のみを出力して終了する、と捉えることができます。 Prelude> :t foldl foldl :: (a -> b -> a) -> a -> [b] -> a foldlの型です。 同様にscanrの動作もみてみます。 scanrはxとyの役割が逆転しており、リストの作り方も異なっています。 Prelude> scanr (\x y -> x / y) 2 [3..5] [1.875,1.6,2.5,2.0] pythonで動きを追ってみると >>> x=5. >>> y=x/y >>> y 2.5 >>> x=4 >>> y=x/y >>> y 1.6 >>> x=3 >>> y=x/y >>> y 1.875 代入、再代入はyに対しておこなわれます。 yに代入があった時、リストの先頭に値を保存します。 Prelude> 1.875:1.6:2.5:2.0:[] [1.875,1.6,2.5,2.0] haskellはソースコード上での、変数への値の再代入を許していません。 そのため繰り返しのための構文が用意されていません。 それが可能な言語、例えばPythonでは次のようなコードが書けます。

x=0
for y in [1,2,3]: 
 x=x+y  print x
これは上記の説明のfoldと全く同じです。 つまりfoldは一般的な言語の繰り返し処理をHaskellで書くための一つの方法になっているわけです。

(PythonのFor文は他の凡百の言語のFor文とはまったく異なります。どちらかというとMapに近い。ただ書き換えのできるグローバル変数も使えるので非常に自由度が高い。)




fold を手続き的にとらえると考えやすくなる処理があります。

Data.List モジュールには insert という関数が用意されています。

Prelude> import Data.List
Prelude Data.List> :t insert

insert :: Ord a => a -> [a] -> [a]

ソート済みのリストに一つ要素を加えてソート順を崩さずに新たなリストを返す関数です。
他の関数が一般的なリスト処理の関数なのに比べてやや特殊な感じがあります。
たぶん「挿入ソートを実装してください」というメッセージだと思います。
挿入ソートは再起でも書けるとは思うのですが、いきなり fold を使ったほうがわかりやすい。

Prelude Data.List> foldl (\x y -> insert y x) [] [2,7,4,0]
[0,2,4,7]

まず初期値は空リストです。
x に 代入されます。
y には リストの第一要素が代入されます。
x y をひっくり返して insert 関数を適用します。
結果 x に [2] が y に 7 が代入されます。
7 を [2]  に insert し [2,7]  ・・・・(略)

この操作をリストの終わりまで繰り返します。 これでソート完了。

flip を使って書き直すと

Prelude Data.List> foldl (flip insert) [] [2,7,4,0]
[0,2,4,7]

さらに

Prelude Data.List> foldr insert [] [2,7,4,0]
[0,2,4,7]

foldl と foldr では動作が異なりますが、この場合は結果は同じです。



も参照ください。

フィボナッチ数



f6 の実行例

*Main> last $ take 10 f6
[55,34,21,13,8,5,3,2,1,1,0]

これは

foldl (\x@(a:b:_) _ -> (a+b):x) [1,0] [0..8]

と同じです。

フィボナッチ数列の隣り合う 2 項の比は黄金比に収束Wします。

$ runghc fibo2.hs | runghc gr.hs

~
~
~
1.618033988749895
1.618033988749895
1.618033988749895
~
~
~
Ctrl-Cを押して終了。

2017年10月28日土曜日

シェルピンスキーのギャスケット


pbmファイルでシェルピンスキーのギャスケットを描きます。
まずパスカルの三角形をつくります。



$ runghc -XParallelListComp pascal.hs 3
[1]
[1,1]
[1,2,1]
[1,3,3,1]
[1,4,6,4,1]
[1,5,10,10,5,1]
[1,6,15,20,15,6,1]
[1,7,21,35,35,21,7,1]


奇数部を1、偶数部を0に置き換えます。

$ runghc -XParallelListComp sierpinski.hs 10 | display

描画には10数秒かかります。

コンパイルすればほぼ一瞬で描画するようになります。



http://senjounosantafe.blogspot.com/2019/02/blog-post.html

上記のページに

Python のコードを出力し
Turtle グラフィックスで
シェルピンスキーのギャスケットを再帰的に描画するHaskellのコードを置いています。


また1次元のセル・オートマトンにルール90を適用することでもシェルピンスキーのギャスケットを描画できるそうです。




実行例
$ runghc ca.hs




main を

main =  loop0 fs 31 $ reverse "11100001"

と書き換えるとルール225を描画します。



Intから2進数の文字列に変換するには
「2進、8進、10進、16進の各表現を相互に変換する」のページ

https://github.com/haskell-jp/recipe-collection/blob/master/%E6%95%B0%E5%80%A4/2%E9%80%B2%E3%80%818%E9%80%B2%E3%80%8110%E9%80%B2%E3%80%8116%E9%80%B2%E3%81%AE%E5%90%84%E8%A1%A8%E7%8F%BE%E3%82%92%E7%9B%B8%E4%BA%92%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B.md


を参考に。

具体的には

ghci> import Numeric
ghci> import Data.Char
ghci> showIntAtBase 2 intToDigit 123 "" -- 123を2進数表記
"1111011"

ただし8桁になるように先頭にゼロを埋めること。

"1111011" -> "01111011"



参考ページ
Elementary Cellular Automata

http://atlas.wolfram.com/01/01/



その他のルールも適用可能にし精細な画像を描くにはこちら。

http://hhg2the-haskell.blogspot.com/2019/02/blog-post.html

マンデルブロ集合

pbmファイルに書き出してマンデルブロ集合を描きます。(画像サイズは1000x1000に固定しています。)

コンパイルします。

$ ghc -O2 -threaded -rtsopts --make -XFlexibleContexts -eventlog mandel.hs
$ ./mande -2 2 2 3000 +RTS -N2 -l | display

displayコマンドにパイプします。
動作を確認。
$ threadscope mamdel.eventlog

殆どの時間2Coreで動いています。


Data.Array.Repa.IO.BMP

モジュールには

readImageFromBMP :: FilePath -> IO (Either Error (Array U DIM2 (Word8, Word8, Word8)))

writeImageToBMP :: FilePath -> Array U DIM2 (Word8, Word8, Word8) -> IO ()

という関数がありBMPファイルの読み書きができる。


画像サイズもコマンドラインから与えます。


$ ./mandel2 -2 2 2 1000 3000 +RTS -N2 -l


1次元の配列に対し map し、 reshape すればよいので、コード自体はわかりやすい。
index のTable (Int のタプルの配列)を作るのに時間がかかっているようなので、
配列を連結するやり方も試みた。



また  mandel2.hsにおいてIndexをIntではなくWord16に置き換えてみたが効果は微妙だった。

世の中にはGPUを使ってマンデルブロー集合を極めて高速に描画するプログラムもあるらしい。

2017年10月27日金曜日

画像ビューアー




この画像(IMGP2850.JPG)を表示します。

ただこのやり方だと元画像の大きさそのままで表示されます。
サイズを変更して表示するには一旦Pixbufのインスタンスをつくってから
Buttonに貼り付けます。



かんたんな画像のビューアーをつくります。 まずディレクトリーを選択するダイアログ。



dirというファイルにリダイレクトしておきます。

$ runghc dirchooser.hs > dir

ビューアー

ただ表示するだけではあまりにも芸がないのでちょっとした操作をしてみます。

ソースコード

まず補助的関数を集めたMyImageモジュール


一括処理を選択します。



画像の回転指定



確認



MyTable モジュール

最後にConvertコマンドを実行します。



スクリプトは

runghc dirChooser.hs > dir
runghc select.hs > tmp
cat tmp | runghc image.hs > tmp1
cat tmp1 | runghc confirm.hs > tmp2
cat tmp2 | runghc mkCom.hs

アイコンが必要です。

keep.png  left.png  right.png  updown.png




gtk2hs


gtk2hsのインストールは

sudo apt install libghc-gtk-dev

先にGHCを単独でインストールしてしまうとgtk2hsを加えるときに非常に時間がかかります。
Gtk2hsを使う予定がなくてもいきなり入れてしまったほうが良い。
もちろんこれでGHCも使えるようになります。



このコードを実行してウィンドウが表示されればインストールは成功です。

2017年10月26日木曜日

ハノイの塔



ハノイの塔の由来や、ルール、解き方のアルゴリズムは省略します。

hanoi.hs

実質3行のプログラムです。
haskellが提供する再帰とdo記法で極めて簡潔に書くことができます。

実行例

$ runghc hanoi.hs 3
A-B
A-C
B-C
A-B
C-A
C-B
A-B

最短の解き手順を表示します。
円盤3枚の場合です。
A-Bというのは塔Aの一番上の円盤を塔Bに移動するという意味です。

GUI版


$ runghc hanoi.hs 3 | runghc guihanoi.hs 3 100

labelhanoi.hsへの第2引数はタイミングです。ミリ秒で指定します。
同じ引数を渡すのは面倒なのでhanoi という名前でスクリプトを書いておきます。
runghc hanoi.hs $1 | runghc guihanoi.hs $1 $2
$ ./hanoi 9 500



コンソール版

スクリプト

runghc hanoi.hs  $1 | runghc -XFlexibleContexts doHanoi.hs $1

実行例

./dohanoi 64

こちらも参照ください。

πの計算

ライプニッツの公式




実行結果
$ runghc l.hs
3.140592653839793

マチンの公式によるπ


参考にしたページ
http://handasse.blogspot.com/2011/12/1.html

Parallel版

1万桁では差がでないので
10万桁ほど計算します。

コンパイルします。

ghc  --make -O2 pm.hs -rtsopts -threaded -eventlog

CPUはCore2Duo。デュアルコアなので -N2 オプションで実行します。
$./pm +RTS -N2 -l
threadscope で動作を確認します。
$ threadscope pm.eventlog

僅かですが速くなっています。
並列計算を効率よく利用するには最初から並列化を意識してコードを書く必要があるようです。

spigot アルゴリズムをLoopで書いたコード
kk62526 さんが10進Basicで書いたコードをそのまま移植しています。

グローバル変数 「i(注)」に現在何桁目を計算しているかが保持されてますので(ただし+2された数字)
(注: 本当は無名ですが、こう捉えたほうが分かりやすいです。)
if (i-2) `mod` 100 == 0 then ・・・・・・
のようなコードを挿めば100桁ごとに区切ったりできます。
実行結果
 $ runghc p.hs > a
$ less a
3 1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679()
100 8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196()
200 4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273()
300
~
~
~
(略)
ちなみに10000桁を計算し終えるのに2秒少々でした。
ギボンズ博士が spigot アルゴリズムに対し
"not competitive with state-of-the-art arithmetic-geometric mean algorithms"
と言うとおり決して高速とはいえませんが、いきなり1桁目から表示を始めますので、
体感的には超高速です。
(注:10000桁の計算では8万数千桁のIntegerが3つ、作られます。)

ギボンズ博士のspigot アルゴリズムは
https://www.cs.ox.ac.uk/jeremy.gibbons/publications/spigot.pdf
コードだけ紹介しますと




平方根、立方根



2の平方根

$ runghc nroot.hs 2 2 | tee a

2の立方根

$ runghc nroot.hs 2 3 | tee b

猛列な勢いで計算しますので適当なファイルに保存もしています。(Ctrl-Cで停止)

なお√2に限ればこう書けます。

One liner:
loop a b n = return (a*2+1) >>= \c -> if c<b then loop (a+1)(b-c)(n+1) else putStr (show n) >> loop (a*10)(b*100)0; main = loop 1 1 1
 
平方根は正方形の色紙を百分割して並べることで、
立方根は正四角形のサイコロを千分割して貼り付けていくことで深い桁まで計算をすすめることができます。

参照ページ
http://senjounosantafe.blogspot.com/2018/05/2.html

myPlayer

-- pipe.hs import System.Process import System.Environment main :: IO () a:_ IO [FilePath] randomize lst = do let c = length lst ...