Page List

Search on the blog

2011年11月12日土曜日

サーバー奮闘記(16) SSHのRSA鍵設定、rm、emacsの設定など

vps初めて半年くらい経ちました。当初借りたは良いけど、何をしたらいいのか分からない状態でしたが、適当にwebサービスを作ったりしてまあまあ活用できている気がします。最近気に成っていたことがいくつかあったので、まとめて片づけました。
  1. SSHのRSA鍵設定
  2. aliasでrmをrm -i にする
  3. emacsのバックアップファイルを作成しないようにする
 まず1。プレインテキストでユーザー情報とかパスワード流すのやばいだろう。。(※訂正:teratermのオプションにプレインテキストって書いてあったので平文で流れているのかと思いましたが、mojavy先生曰くsshではすべての通信が暗号化されているため、プレインテキストでパスワードが流れるなんてことは無いそうです。)vpsで誰かがtcpdumpとかしてたら漏れ漏れじゃないですか@_@ と前々から思っていて、いつの間にか忘れていて、セキュリティの読み物見ていたら思い出して、即実行しました。

を参考にしました。

 上のサイトにあるようにローカルで鍵ペアを作成して、サーバーに公開鍵を送るようにしましょう。サーバーで作って、秘密鍵をローカルに転送とかやってたら本末転倒なので。
 あと、SSH認証を使いますっていうのをtera termの初期設定ファイルに保存しておくとログインがらくです。「設定」 -> 「SSH認証」 と進み、
  1. 「ユーザ名」にユーザ名を入力
  2. 「RSA/DSA鍵を使う」にチェック
  3. 「秘密鍵」項目で秘密鍵のファイルを選択
  4. 「OK」ボタン押下
とし、「設定」 -> 「設定の保存」を選んで、INIファイルに設定を保存します。

 2. はtypoでrm *とかやったら泣けるなーと思ってその予防策。
~/.bashrcに以下追記。

alias rm='rm -i'

 3. は、毎回チルダから始まるバックアップファイルを作っているのがemacsだと分かったので作らないように設定。
~/.emacsに以下の設定追記。

(setq make-backup-files nil)

ヨセフス数(Josephus Number)の求め方

ヨセフスの問題(Josephus problem)という有名問題があります。これの一般解を求める式があるらしいので調べてみました。

 以下では、円を組む人の数をn、スキップ数をkとします。本来は、n番目(つまり最後に)処刑される人の番号を求めればよいのですが、より汎用的にs番目に処刑される人の位置を求めることにします。

 ここのページにあるように、以下のソースコードでs番目に処刑される人の位置がわかります。


int josephus(int n, int k, int s) {
    int ret = k * s;

    while (ret > n)
        ret = ((ret - n) * k - 1) / (k - 1);

    return ret;
}

 えーーっと、よくわかりません。ということで、何故上のコードで答えがでるのか考えてみました。(結構がんばりました(汗)。)
まずは、正の整数xに対して、f_k: x -> (x * k - 1) / (k - 1)という写像が何をするのか考えます。

k = 2のとき
f_2(1) = 1
f_2(2) = 3
f_2(3) = 5
f_2(4) = 7
・・・・・

k = 3のとき
f_3(1) = 1
f_3(2) = 2
f_3(3) = 4
f_3(4) = 5
f_3(5) = 7
・・・・・

ふーむ、どうやらf_kは、自然数からなる点列(1,2,3,...)からkの倍数を取り除くような効果があるようです。本当か?ちょっと数学的に考えてみます。

f_k(x) = (k * x - 1) / (k - 1)なので、f_k(1) = (k*1 - 1) / (k - 1) = 1です。
f_k(2) = (k*2 - 1) / (k - 1) はコンピュータの整数演算では2ですが、数学上は、2余り1です。
同様に、
f_k(3) = 3余り2
f_k(4) = 4余り3
・・・・
f_k(k) = k余り(k-1)

です。f(k)は(k-1)余ってますが、(k-1)で割るのでこの余りは消えて商が1増えます。ということで、f(k) = k+1となります。これで、(1,2,3,.....k)という点列が(1,2,3,....,k-1, k+1)となりました。さらに続きを調べるために、g_k(x) = (k * x - 1) を (k-1)で割った余りが0になる場所を調べます。

g_k(1) = 0 (mod (k-1))
g_k(k) = 0 (mod (k-1))
g_k(2*k-1) = 0 (mod (k-1))
・・・・

なので、y = 1 + i * (k-1), i = 0,1,2,3,...なる正の整数yに対してg_k(y) = 0 (mod (k-1))となります。先の例で正の整数の点列からkが除去されることを確認しました。2*k-1という場所は本来2*kがある場所です。(kが無くなってるから1引かれる)。ここで同様に商の繰り上がりがおこることから、2*kは点列から除去されます。同様に3*k-2に対応する3*kも除去されます。以降同様にして、kの倍数がすべて除去されるというわけです。

 ここまでで、写像f_kがkの倍数だけを除いた整数点列を生成できることが分かりました。ソースコードを見ると、まず
ret = k * s;
としているので、retは、(1,2,3...n)の点列を拡張して、(1,2,3,....,n,n+1,n+2,....... k*s)にしたものを考えていることが分かります。ここから逆算して、k*sが区間[1,n]の整数のどれに対応しているかをみていこうというわけです。(ret - n)でnからはみ出ている分が分かります。このはみ出ている部分に対して、写像f_kを適用することで、retは消えたものを除いて数えた場合にそれがあるべき場所へとマッピングされます。これをret <= nになるまで繰り返しているというわけです。ちょっと説明足らずな感じなので、表で示します。n = 5, k = 3, s = 5とした場合、

k*s123456789101112131415
k*s - n -----12345678910
f_k(k*s - n)-----12457810111314

となります。例えば、処刑される順番は、k*s = 3, 6, 9, 12, 15の順です。それぞれ見て行きます。
1番目に処刑される人は、3番目の人です。
2番目に処刑されるのは、6ですが、これはnより大きいので、もともといる位置に変換します。表のf_k(k*s - n)を見ると1なので、1番目の人です。
3番目に処刑されるのは、9ですが、これも同様に対応位置に変換して5になります。
4番目に処刑されるのは、12 -> 10 -> 7 -> 2と変換されるので、2番目の人です。
同様に、最後に処刑されるのは、15 -> 14 -> 13 -> 11 -> 8 -> 4で4番目の人です。

ということで、(3, 1, 5, 2, 4)の順で処刑されるということです。4の位置に居れば助かりますね!

2011年11月10日木曜日

アセンブラを出力して遊ぶ

簡単なプログラムをアセンブラで出力して、スタックの動きを追ってみます。簡単なプログラムですが、結構面白いです。環境は、Ubuntu、gcc 4.4.3です。

 まず、Cのソースコード(test.c)。

#include <stdio.h>

main()
{
int i, j, k;

i = 1;
j = 2;
k = i + j;
printf("%d %d %d\n", i, j, k);
}


 そして、アセンブラ(test.s)。
$ gcc -S test.c
でアセンブラのコードを出力できます。

    .file    "test.c"
    .section    .rodata
.LC0:
    .string    "%d %d %d\n"
    .text
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $32, %esp
    movl    $1, 28(%esp)
    movl    $2, 24(%esp)
    movl    24(%esp), %eax
    movl    28(%esp), %edx
    leal    (%edx,%eax), %eax
    movl    %eax, 20(%esp)
    movl    $.LC0, %eax
    movl    20(%esp), %edx
    movl    %edx, 12(%esp)
    movl    24(%esp), %edx
    movl    %edx, 8(%esp)
    movl    28(%esp), %edx
    movl    %edx, 4(%esp)
    movl    %eax, (%esp)
    call    printf
    leave
    ret
    .size    main, .-main
    .ident    "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

 いろいろ分かることがあります。
 まず、スタックのアドレスが番地の大きい方から小さいほうへと広がっているところです。これはx86マシンでは共通だと昔聞いたことがあります。
 それから、andl $-16, %esp があるので、16byteのaddress alignmentを使っているようです。FFFFFFF0でマスキングして16の倍数になる次の数をスタックポインタに代入しています。これだとベースポインタとスタックポインタの整合性があわないようにみえるんですけど、結局ベースポインタ使ってないし、リターンする時ベースポインタをスタックポインタに戻す処理も省略されてるので別にいいような気もします。
 意外だったのは、スタック内の変数にスタックポインタからの差分でアクセスしているところです。スタックポインタは実行時に移動するから、ベースポインタからの差分で変数にアクセスするのが普通かと思いましたが、そうでもないみたいです。
 あと、最後にprintfの可変長引数のところの仕組みがおもしろいです。第一引数の%dが3つあるんで、第一引数をpopしたあと、3回popすればいいんですねー。当然といえば当然ですが、実際コード上でみるとちょっとした感動がありました。printfがcallされるときのstackの状態は下のようになっています。



2011年11月6日日曜日

素数とは宇宙の創造主が人間に与えた暗号である


"On the trail" by Mr eNil

最近、素数に関するNHKのドキュメンタリーを見た。それそれは、もう、感動でした。宇宙の神秘、数学の美に魅せられました。元ネタは、『魔性の難問 ~リーマン予想・天才たちの闘い~』です。要約を書きます。

 まず、素数とは何か?それ自身と1以外に約数を持たない正の整数のことです。2,3,5,7,11,13....と無限に続きます。この素数列の並びはランダムに見えます。しかし、2人の有名な数学者が素数と自然界においてとても重要な数を結びつけました。レオンハルト・オイラーは、素数と円周率πの間に以下の関係を見出しました。


まったくランダムに見える素数に関する式を無限個掛けあわせると、なんと世界で最も美しい数πがでてくるのです。これによって、オイラーは素数と円や球体が何らかの関係を持っていることを発見しました。

 それから、カール・フリードリヒ・ガウスは、ある正数xまでに現れる素数の数は以下の式で近似できることを発見しました。いわゆる素数定理ってやつですね。


ln()は自然対数で、その底はeです。eは、カタツムリの渦巻き、台風、銀河なのどの自然界で多くみられる螺旋形状と関連のある数字です。

 オイラーとガウスの手によって、ランダムな素数が数のキングおよびクイーンと関連付けられました。そして、素数と自然界には何らかの関係があるのではと考えられるようになったのです。その考えはベルンハント・リーマンによって『何らかの関係がある』から以下のような数学的な問題へと変換されました。

ゼータ関数

の非自明な零点は一直線上に並ぶ。

ゼータ関数が零になるようなx(複素数)を複素平面上にプロットすると、なんとそれが一直線上に並ぶというのです。衝撃的ですね!

 上記のリーマン予想は、現在証明されておらず、N ≓ NP予想などと同様にミレニアム懸賞問題の一つです。今まで、ジョン・ナッシュやアラン・チューリングといった偉大な数学者、暗号科学者たちがその証明を試みましたが、失敗に終わっています。

 時は流れて、違ったアプローチでリーマン予想にチャレンジする数学者が現れました。ヒュー・モンゴメリーは、直線状にならぶ零点の間隔に興味をもちました。そして、たまたま出会った物理学者フリーマン・ダイソンに零点の間隔の式を見せた時に、ダイソンは言いました。「それはすごい!その式はウランなどの原子核のエネルギーレベルの間隔を表す式と同じような形をしている!」
素数と量子力学の世界、まったく異なる分野が一つになった瞬間でした。

 この発見を機に、多くの物理学者がゼータ関数の零点と同じ間隔をもった原子を探すようになりました。すると今度は、非可換幾何学というまったく異なる学問を研究しているアラン・コンヌが閃いたのです。「モンゴメリーの発見を発端として、物理学者たちは素数と関連をもつ空間をさがしている。そして、その空間とは非可換幾何学と完璧に一致する空間である。」当時、非可換幾何学は、量子力学を書き変え森羅万象の原理を説明する究極の法則『万物の理論』の基礎になると期待されていた学問でした。宇宙の創生と素数が繋がっていることを示す非常に興味深い話です!

 ある数学者はいいます。
「非可換幾何学を使って素数の謎がとかれるとき、森羅万象を説明する万物の理論--いわば創造主による宇宙の設計図--も明らかになるだろう。」と。

2011年11月4日金曜日

Google Developer Day Japan 2011


 『Webの世界はすさまじい速度で進化してきた。次世代のWebがどのようなものになるのか私は分からない。しかし確かなことがある。次世代の新しいWebはこの部屋にいる技術者たちによって作られだろう。そして未来のビジネスはあなた方がつくった新しい仕組みのうえで展開される。』

 ―先日、Google Developer Day 2011が横浜で開催されました。Googleの製品へ高い貢献をしているDeveloper、およびDevQuizで高得点を取り招待状をゲットしたエンジニア、約2000人が一同に会しました。

 Google Developer Dayは午前の部と午後の部に大きく分かれていて、午前はKeynote Speech、午後は複数のSessionが同時進行するという形で構成されていました。主に、
  • Android
  • Chrome
  • App Engine
  • HTML5
  • Google+
などの技術の最新動向が発表されました。また、技術者同士が会話をしたり、Googleのエンジニアとコミュニケーションを取ったりできるような工夫が施されており、とても楽しいイベントでした。私自身も、缶バッジ交換のおかげでゲーム業界のエンジニアの人とお話することができ非常にいい経験となりました。

 特に私の印象に残ったのは以下の3点です。
  1. ScalabilityとAgility
  2. Googleマインド
  3. エンジニアとしての社会貢献
 1. 『これからのWebのサービスにおいて重要なものは、どうスケールするか、そして如何に柔軟な開発スタイルを取り入れていくかだ。』特に、アジャイル開発の重要性に関しては、Googleの東日本大震災に対する取り組みの中でも語られました。
 アジャイル開発を行うためには、プロトタイピング力を持ったエンジニアの存在が絶対条件だと思います。しかし、浮かんだアイディアをすぐに実装できるエンジニアは日本には決定的に少ないように感じます。これはそもそも、日本のシステム業界(とりわけSIer業界?)が要件定義/設計/開発/テスト/保守のように縦割りになっていることが原因じゃないかと。。要件定義はできるけど、fizzbuzzも書けないエンジニア。開発はできるけど要件がまったく分からないエンジニア。アジャイル開発を取り入れるためには、まずこのあたりの体質を変えていく必要があるのかなと思いました。

 2. これは、単純にいいな~と(羨ましいなと)。。会社のスローガンって見栄えだけ綺麗で中身が伴っていないことがしばしばありますが、Googleが大切にしているという以下の三箇条は本物だなと感じました。
  • なにごともエンジニアありき
  • 百聞は一デモに如かず
  • 日本で「イケる!」と思ったら、世界のみんなも同感するかも
 3. 「Googleのクライシスレスポンス」というSessionで、東日本大震災に対するGoogleの取り組みが語られました。『すべてが自動化された完璧なシステムを届ける必要はない。途中に人の手が入っていてもかまわない。』『当初、被災地の人達が欲していたのは、スマートフォン上で起動するアプリでもクラウド上で動作するアプリでもなかった。エクセルやアクセスといったごく単純な技術だった。』
 技術者として最新技術を追うことや完璧を求めることも大事だけど、今自分が持っている技術がどう世の中に役に立つのかと考えて実践するというのは本質的により重要なことだなと改めて考えさせられました。自分の技術なんて大したことないやと卑屈にならずに、少しでも世の中が変わる、少しでも世の中に役に立つはずと信じてサービスを提供していきたいなと思いました。

2011年10月29日土曜日

Haskell模写修行(2)

問題: Codeforces Beta Round #84 (Div. 2 Only) B. Lucky String

自分が書いたコード:

import Control.Monad

main = do n <- liftM read getLine
putStrLn . take n . cycle $ "abcd"


お手本コード(bjin氏参考):

main = interact$(`take`cycle"abcd").read

interact使って書くとごちゃごちゃしそうだったので、doブロックで書いた。Control.MonadのliftMは便利。適用する関数の引数の数に応じて、liftM2, liftM3, liftM4, liftM5 などもある。
bjinさんはゴルフ好きな感じである。takeをinfix operationにしてセクション(二項演算子の部分適用をするための手法)を実現してるのは面白いテクニックだなーと。

Haskell模写修行(1)

"New Zealand Autumn" by Abaconda
 
 モナドを実装したり、メモ化したり、コンビネータを書いたりとかしたけど、Haskellらしいコードが全然書けない。一応は動くものは書けるけど、どうも命令型で関数型っぽくない。ということで、Haskellらしいコードが書けるように修行する。

 "らしい"コードを書けるようになるためには、素晴らしいプログラマが書いた"らしい"コードをたくさん読んで吸収していくのが一番じゃないかなと思う。ということで、しばらく以下をやっていこうと思います。
  1. codeforceの問題をHaskellで解く
  2. ratingの高いHaskellerが書いたコードと自分のコードを比べる
  3. いいところを吸収する

自分が書いたコード:


import Char

isVowel 'a' = True
isVowel 'i' = True
isVowel 'u' = True
isVowel 'e' = True
isVowel 'o' = True
isVowel 'y' = True
isVowel 'A' = True
isVowel 'I' = True
isVowel 'U' = True
isVowel 'E' = True
isVowel 'O' = True
isVowel 'Y' = True
isVowel x = False

addDot [] = []
addDot (x:xs) = '.' : x : addDot xs

main = do
input <- getLine
putStrLn . map toLower . addDot . filter (not . isVowel ) $ input


お手本コード(bjin氏参考):

import Char
g x | x < '0' || elem x "aoyeui" = ""
| 1 > 0 = '.':[x]
main = interact $ concatMap (g.toLower)

ポイント:
  1. elem
  2. concatMap
  3. interact
 ”Haskellらしい”うんぬんより、まず便利な関数を覚えていくところからかな。