リストから要素を間引きする

真ん中優先。真ん中がないときは右側優先。

^o^ > gosh thin-out.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 3 4 6 7 8 9)
(0 1 2 3 6 7 8 9)
(0 1 2 3 7 8 9)

リストのn番目の要素を削除する

最初の要素は0番目。

^o^ > gosh delete-nth.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 4 5 6 7 8 9)
(a b c d e f g h i j)
(a b c e f g h i j)

ちゃんと 3 と d が消えている。

これを拡張して、「n番目」を複数とれるようにしてみよう。

^o^ > gosh delete-nth2.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 4 6 8 9)
(a b c d e f g h i j)
(a b c e g i j)

要素がリストに含まれているか否かを判定する述語が見当たらなかったので、include? を自作した。

整数のリストを作る(2)-あるいは省略可能な引数の扱いについて

先週のエントリを見て省略可能な引数を扱う方法を書いてくれた人がいる。

 cf. 省略可能引数 – 主題のない日記

そこでは、R6RS/R7RS で定められている case-lambda と Gauche の拡張である let-optionals* が紹介されている。どちらも省略可能な引数を簡単に扱うためのマクロのようだ。

my-iotacase-lambda を使って書くとこうなる。

ついでに step に負数を指定すると期待通りに動作しない不具合も直しておいた。
実行例:

^o^ > gosh my-iota4a.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
(2 0 -2 -4 -6 -8 -10 -12 -14 -16)

一方、let-optionals* を使って書くとこんな感じ:

^o^ > gosh my-iota4b.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
(2 0 -2 -4 -6 -8 -10 -12 -14 -16)

当然ながら実行結果はどちらも同じだけど、どちらかというと case-lambda のほうが好みだな。引数の数でパターンマッチしてる感じがいい。let-optionals* だと省略可能引数の部分だけ別に書くことになるのでコードの見通しが悪いような気がする。

Gauche のマニュアルだと、case-lambdahttp://practical-scheme.net/gauche/man/gauche-refj_24.html の一番下、let-optionals*http://practical-scheme.net/gauche/man/gauche-refj_58.html6.18.4 省略可能引数のパージング にある。

整数のリストを作る

たまには Scheme を。

Scheme で整数のリストを作るには iota 手続きが使える。

^o^ > gosh
gosh> (iota 10)
(0 1 2 3 4 5 6 7 8 9)
gosh> (iota 10 2)
(2 3 4 5 6 7 8 9 10 11)
gosh> (iota 10 2 2)
(2 4 6 8 10 12 14 16 18 20)

これを自前で実装してみよう。
最初に作ったのがこれ。可変長引数なので、引数の数に応じて対応する補助手続きを呼び出している。

実行例:

^o^ > gosh my-iota.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

上の実装では3つの補助手続きを定義しているけど、内容は同じようなものなので1つにまとめることにした。つまり、引数を3つとる補助手続き my-iota-general を定義しておいて、本体手続き my-iota のほうで場合分けをして呼び出す。

^o^ > gosh my-iota2.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

だいぶシンプルになった。もう一歩進めてみよう。上の my-iota 手続きの中では場合分けをして my-iota-general の引数 start、step を決めているので、let で局所変数にしてしまえば my-iota-general の本体部分を取り込むことができる。

^o^ > gosh my-iota3.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

めでたく1つの手続きにできた。

逆関数法で指数分布する乱数を生成する

[0,1)区間の一様乱数から、指数分布にならう乱数を生成するには、逆関数法というのが使える。
指数分布の密度関数は、パラメータをτとすると:
f(\tau)=\lambda e^{-\lambda\tau}
であり、分布関数 g(τ) は:
g(\tau)=\int^\tau_{-\infty}{\lambda e^{-\lambda\tau}}d\tau=1-e^{-\lambda\tau}
となる。g(τ)は 0~1 の値をとるので、この逆関数:
\tau=-\frac{1}{\lambda}log(1-g(\tau))
の g(τ) の代わりに一様乱数を入力してやれば、τ は指数分布する乱数になる。

じゃあ Ruby でやってみよう。

λ=0.5とし、10000個の乱数を発生させている。
これを Excel でグラフ化したのがこれ。
expon
「指数分布」の曲線は、上に書いた密度関数の曲線を、スケールを合わせるために8000倍して描いている。乱数はちゃんと指数分布になっているようだ。

参考にしたページ:
 cf. http://www.ishikawa-lab.com/montecarlo/4shou.html

Box-Muller法で正規分布する乱数を生成する

一様分布する乱数から、正規分布に従う乱数を生成する方法に、Box-Muller法というのがある。
Wikipediaによれば、(0,1) 区間の一様分布乱数2つ(X,Y)から、下の式で2つの正規分布乱数 Z_1Z_2 が得られる。

Z_1=\sqrt{-2log{X}}\cos{2\pi{Y}}
Z_2=\sqrt{-2log{X}}\sin{2\pi{Y}}

Z_1Z_2 は標準正規分布となるので、これらに標準偏差 σ をかけて平均 μ を足してやれば、任意の正規分布に従う乱数が得られる。

Ruby で 10000個の乱数を発生させるスクリプトを書いてみた。ここでは平均 μ=1.0、標準偏差 σ=0.2 とした。

結果を Excel でグラフ化してみた。水色の点が 0.1 単位のヒストグラム。黄緑の線が Excel に用意されている MORM.DIST 関数で描いたもの(スケールを合わせるために NORM.DIST 関数の値は 1000 倍している)。

Box-Muller

こうしてみると、ほぼぴったりと正規分布になっているようだ。

ちなみに Excel で平均値と標準偏差を求めたら、それぞれ μ=0.997、σ=0.201 となった。

Windowsマシンで動かしているSinatraアプリにほかのマシンからアクセスできなくてハマった

おおよその事情はタイトルの通り。
Windows マシンで Sinatra アプリを動かす。

^o^ > rackup config.ru

ポート 9292 で待機するので、ほかのマシンからアクセスするも繋がらない。ローカルホストからだとちゃんと繋がるので、アプリのせいではない……と思ったら、これが大間違いだった。

最初、ファイアウォールのせいだと思って Norton Internet Security のポート開放方法とかをググって試してみたけど、どうやっても繋がらない。
さんざんやったあげく、ふと Sinatra で同じ目にあってる人がいるかと思って「ruby sinatra ポート」でググったら、次のページを見つけた。

 cf. Sinatraがデフォルトでは外部から繋がらなくなってたよ – Qiita

なんてこった。Sinatra 1.4.0 から development 環境ではデフォルトでローカルホストからしかアクセスを受け付けなくなったようだ。
ともあれ、原因と解決法が分かった。次のようしてどのホストからのアクセスも受け付けるようにすればいい。

^o^ > rackup -o 0.0.0.0 config.ru

これで無事OK。

新しいPCが届いたのでWindowsを消してUbuntuをインストールした

今日一日かけて作業した。Ubuntu 16.04 LTS。ホスト名は muffinman。
宅内ネットワークの Webサーバ用。apostrophe(旧nightschool)で動かしていた、Sinatra アプリ2つを移設。いくつかハマりどころがあったけど、なんとか終わった。
ホントはちゃんと作業記録を残しておくべきなんだろうけど、覚えていないので書けない。まあ、うまくいったからいいか。

Ubuntu:ホスト名を変更する

/etc/hostnameの変更

直接編集してもいいけど hostname コマンドで変更できる。

takatoh@nightschool $ hostname
nightschool
takatoh@nightschool $ sudo hostname apostrophe
[sudo] password for takatoh:

/etc/hostsの変更

127.0.0.1	localhost
127.0.0.1	apostrophe   # <- ここを変更

192.168.1.12    valarie

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

ネットワークの再起動

takatoh@nightschool $ sudo /etc/init.d/networking restart
takatoh@nightschool $ hostname
apostrophe

これで完了。
/etc/hosts を書き換えてから出ないとネットワークを再起動したときにエラーが出る。

takatoh@nightschool $ sudo /etc/init.d/networking restart
sudo: ホスト apostrophe の名前解決ができません

ちなみに、プロンプトのホスト名が変わってないけど、これは端末を起動し直すとちゃんと変更が反映される。

[追記]

上記の通りで OK かと思ったら、完全じゃなかった。OS を再起動したらホスト名が戻ってしまった。

takatoh@nightschool $ hostname
nightschool

hostnamectl コマンドで見ると:

takatoh@nightschool $ hostnamectl
   Static hostname: nightschool
         Icon name: computer-desktop
           Chassis: desktop
           Boot ID: 2026269b5ed74ccab65e1a806d7e231f
  Operating System: Ubuntu 14.04.4 LTS
            Kernel: Linux 3.13.0-85-generic
      Architecture: x86_64

hostnamectl コマンドで変更する。

takatoh@nightschool $ sudo hostnamectl set-hostname apostrophe
takatoh@nightschool $ hostnamectl
   Static hostname: apostrophe
         Icon name: computer-desktop
           Chassis: desktop
           Boot ID: 2026269b5ed74ccab65e1a806d7e231f
  Operating System: Ubuntu 14.04.4 LTS
            Kernel: Linux 3.13.0-85-generic
      Architecture: x86_64

参考ページ:

 cf. ホスト名を設定する