2014年11月28日金曜日

プログラミング初心者が中級者になるために学ぶべき4つの開発ツール


プログラミングの生産性はプログラマによって大きく異なります。
生産性の差というのはアルゴリズムや言語の知識、才能など様々ありますが、その中で最も効率よく、素早く改善出来るのは開発ツールの習得でしょう

開発ツールは世の中に五万とあり、様々な用途に合わせて作られています。

それらのツールを習得しているということはプログラマとしての能力そのものと言えるでしょう。

そして、天才的なプログラマでも意外とツールを良く理解していないことがあります。彼らに対してアドバンテージを取れるという意味でも開発ツールを学ぶ価値は非常に大きいです。


ここでは個別のツールに限定するのではなく、広くどのようなツールを、どのように学ぶべきなのかを議論したいと思います。




1. IDE (統合開発環境)



ex. Eclipse, Visual Studio

多くのプロジェクトにおいて、IDEはプログラミングの殆どの時間、開いているものです。
これを良く理解しているということがプログラマにとって重要であることは間違いありません。

しかし、「IDEを習得する」とはどういうことでしょうか。
IDEの利便性を最大限に引き出すためには以下の2点を習得する必要があるでしょう。

1. ショートカットキーを覚える

IDEは思った以上に沢山のショートカットキーが存在します。
いちいちGUI上でクリックするのではなくショートカットを利用するだけで作業効率は一段と上がります。

ビルドやデバッグなどの非常に頻繁に使うショートカットはすぐに覚えますが、それほど頻繁ではないショートカットの場合、自分で意識して使うようにしないと覚えられないものです


2. ビルドプロセスを理解する

IDEを自在に操れる人というのはIDEがその内部で何をやっているのかを理解しているプログラマです。

多くのIDEはMakefileに相当するものを自動生成することでプロジェクトのビルドを自動化しています。

この自動生成されるMakefileに凡そどのような内容が書かれているのかを理解すると様々な自動化が可能になります

例えばIDEが行っているビルドをそのままスクリプトにまとめることでテストビルドを自動化することが出来ます。

 

2. テキストエディタ



ex. Vi, Vim, Emacs

テキストエディタはあらゆる場面で使う、プログラマ・エンジニアの根幹となる武器です。
プログラマにとって優良なテキストエディタを習得するということは、日本人にとって日本語を習得するということと同義です

テキストエディタの習得において最も大切なことはショートカットを覚えることです。そもそもテキストエディタを開く目的自体、あるコマンドを実行することである場合もあるでしょう。

ちなみにテキストエディタとしてはViかEmacsをおすすめします。
これらはコマンドライン上で使え、ショートカットが豊富であり、またシェアが大きいからです。

十中八九、一生使えるツールになるでしょう。



 

3. Git (バージョン管理ツール)



ex. Git, Subversion (ここではバージョン管理ツールとして)

時々Gitは不必要に複雑だ、という方がいます。

複雑かもしれませんが、不必要なものではありません。


そもそも、バージョン管理はいかなる種類のソフトウェアにおいても重要なものです。
個人で開発する場合でも、過去のコードというのは常に取っておくべきものであり、また開発の途中で「やっぱりPlan AじゃなくてPlan Bにしよう」という時にPlan Aに取りかかる前の状態にコードを戻すことが出来ます。

これを手動でやろうとして失敗した方は多いと思います。

バージョン管理を丁寧に行うだけで作業の効率は格段に上がります

Gitとは全てのプログラマが習得すべきツールです。


また、Gitは絶対にコマンドライン上で扱うべきです
確かにGUIも有用ですが、GUIはそのままでは自動化出来ないという致命的な欠点を持っています。

Gitのcommitやpushというのはめんどうな作業であるので、だからこそそれらを自動化することでそれらの作業を単純化することが出来るのです。



 

4. スクリプト言語



ex. Perl, Ruby, Python

これまでのツール紹介でも繰り返し自動化と言ってきました。

自動化というのは開発ツールの本質の一つでしょう。

そして、どれだけ自動化出来るかというのは、プログラマの能力のかなり精確なベンチマークであるでしょう

それらの自動化を担当するのがスクリプト言語です。

スクリプト言語の代表はPerl, Ruby, Pythonでしょう。

スクリプト言語は本質的に「上から順に実行する」というものなので、自動化というものととても相性がいいのです。また、そもそもスクリプト言語は書くのが簡単であるということもあります。






これらの開発ツールを習得し、高い生産性と知識を得ればいち早く初級者から中級者になれるでしょう。


そもそもプログラミングとは効率向上・自動化の為のものです。

それを、プログラミングという活動自体に適用するということが中級者以上に求められる技能とも言えましょう。

2014年11月25日火曜日

Cスタンダードライブラリにおけるsin関数の実装

Cスタンダードライブラリにおける関数は様々な驚くべき実装が存在します。
rand()関数はどのようにして乱数を作っているのでしょうか。sin()関数はどのようにしてサインを計算しているのでしょうか。

ここではsin()の実装について考えてみましょう。



・sin関数の計算方法


そもそもsinを求める方法とは何があるでしょうか。


まず思いつくのはテイラー展開でしょうか。

テイラー展開をすることでsinは以下の式で表せます。

http://upload.wikimedia.org/math/6/c/d/6cd3737be7a2653367595e4365ba58f9.png

無限級数なのでどこかで丸めなければなりません。double型の桁数に合うように次数を決められれば良いのですが、その場合次数はxの値に依存することになります。
つまりxが大きいほど収束が遅くなるため、展開次数を大きくとる必要があります



もう一つ、sinを求める方法は三角比表でしょう。
例えば以上の三角比表が与えられた場合、
sin2°はsin0°とsin5°の線形補間で計算できます

しかし、上の表を見れば分かるように、5°刻みだと非常に粗い補間になってしまいます。
double型に使うにはもっと大きな表が必要になるでしょう。ただしそうすると、より多くのメモリを要求することになります。

また、線形補間ではなく二次補間をすることでより精度をあげることが出来るでしょう。しかしこの場合は計算時間が大きくなります。



さて、いずれの方法にしても精度と計算資源(メモリ・時間)のトレードオフの関係があると言えます。



sinの実装


では、実際の実装はどのようにしてsinを計算しているのでしょうか。

ここではIBM Libraryの実装を見てみましょう。
この実装はsinの真の値に最も近いdoubleの値を返します。



/*
 * IBM Accurate Mathematical Library
 * written by International Business Machines Corp.
 * Copyright (C) 2001-2014 Free Software Foundation, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU  Lesser General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

//..中略..//

double
SECTION
__sin (double x)
{
  double xx, res, t, cor, y, s, c, sn, ssn, cs, ccs, xn, a, da, db, eps, xn1,
    xn2;
  mynumber u, v;
  int4 k, m, n;
  double retval = 0;
  SET_RESTORE_ROUND_53BIT (FE_TONEAREST);
  u.x = x;
  m = u.i[HIGH_HALF];
  k = 0x7fffffff & m;           /* no sign           */
  if (k < 0x3e500000)           /* if x->0 =>sin(x)=x */
    retval = x;
 /*---------------------------- 2^-26 < |x|< 0.25 ----------------------*/
  else if (k < 0x3fd00000)
    {
      xx = x * x;
      /* Taylor series.  */
      t = POLYNOMIAL (xx) * (xx * x);
      res = x + t;
      cor = (x - res) + t;
      retval = (res == res + 1.07 * cor) ? res : slow (x);
    }                           /*  else  if (k < 0x3fd00000)    */
/*---------------------------- 0.25<|x|< 0.855469---------------------- */
  else if (k < 0x3feb6000)
    {
      u.x = (m > 0) ? big + x : big - x;
      y = (m > 0) ? x - (u.x - big) : x + (u.x - big);
      xx = y * y;
      s = y + y * xx * (sn3 + xx * sn5);
      c = xx * (cs2 + xx * (cs4 + xx * cs6));
      SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs);
      if (m <= 0)
        {
          sn = -sn;
          ssn = -ssn;
        }
      cor = (ssn + s * ccs - sn * c) + cs * s;
      res = sn + cor;
      cor = (sn - res) + cor;
      retval = (res == res + 1.096 * cor) ? res : slow1 (x);
    }                           /*   else  if (k < 0x3feb6000)    */
/*----------------------- 0.855469  <|x|<2.426265  ----------------------*/
  else if (k < 0x400368fd)
    {

 //..後略..//


sourceware.orgで全コードを見ることが出来ます

まず面白い最適化として、xの大きさに応じて場合分けをしていることがあげられます。

xが小さい場合はテイラー展開を、45°程度の場合は三角比表を、などなどそれぞれの場合に異なる処理をしていることが分かります。

xが小さい場合はテイラー展開が非常に早く収束するのでテイラー展開を採用するなど、非常に高い水準でのトレードオフが見られます。


Cという言語はこのような極限の最適化を重ねて書かれた言語です。
坐臥して最速という訳ではないということでしょう。




2014年11月17日月曜日

Unixテキスト処理コマンド集【cat, head, tail, grep, sort, join, awk】

テキスト形式のデータ処理に便利なUnixコマンドを紹介します。
Unixコマンドは無数にあるのですべてをカバーすることは出来ません。

ここではお手軽に一行で書けるコマンドを中心に扱います。多くの「ちょっとした処理」はこれらの組み合わせで行うことが出来ます。


cat

cat <オプション> <ファイル>

全文を出力する。いわずもがななコマンド。
元々ファイルをつなげる(concatenate)為に実装されたコマンドですが、主に小さいファイルのダンプの為に使われています。
有用なオプションとしては-n: 行番号を出力するというものがあります。これを使うとコンパイルエラーの出た箇所の確認などに便利です。

cat run.sh -n
     1    #!/bin/sh
     2   
     3   
     4    # arg1 = time
     5    #
     6    #
     7   
     8    cd $PBS_O_WORKDIR
     9    ./tiles$time $algname $PBS_ARRAYID $thread_number $param1 $param2 $param3 < $problem_type
    10   
ちなみにcatの語源はconcatenate(つなげる)の略形です。


head

head <オプション> <ファイル>

ファイルの先頭の10行を出力する。大きなデータファイルを確認する場合や、ファイルヘッダーのみ確認する場合に便利です。

オプション-nで任意の行数を出力することが出来ます。
例えば
head  -n 20 astar.dat
ならば先頭20行が出力されます。
head -n -20 astar.dat
とすると最後の20行以外のすべての行を出力します。
ただしheadと続くtailはUnixのディストリビューションによって若干異なるインターフェイスを持っています。中身は同じなので大きな違いはありませんが、manページを見ておく必要はあると思います。

ちなみにheadとtailで行番号を出力したい場合は
cat astar.dat -n | head -n -20
のようにすれば出来ます。この場合の行番号は元のファイルにおける行番号になります。


tail

tail <オプション> <ファイル>
ファイルの末尾の10行を出力する。headと相似形であるので説明はheadを見てください。


grep

grep [オプション] パターン [ファイル...]
grep [オプション] [-e パターン | -f ファイル] [ファイル...]
パーサとして優秀なコマンド。特にログから必要なデータをマイニングする場合によく使われます。
例えば、
grep cron /var/log/syslog
とおくとファイル/var/log/syslogの中で文字列"cron"を含む行を出力します。cronジョブのデバッグをする場合はこれを読むと原因がすぐに分かります。
このコマンドを熟知していれば「ログが多すぎて必要なデータが分からなくなってしまった」ということはありません。

オプションやトリックは様々あるのですべてを網羅することは出来ませんがいくつか基本のものを紹介します。


-c, --count
通常出力の代わりにパターンに一致した行が何行あったかを出力する。
-l, --files-with-matches
通常出力の代わりにパターンに一致した行のあるファイルの名前を出力する。

大規模なデータを扱う場合はgrepの通常出力が大きくなりすぎて扱いにくくなってしまうことがありあます。大きな詳細を扱うのではなく、より大きな傾向を見る場合に使いやすいオプションです。木ではなく森を見るためのコマンドといえるでしょう。

語源はテキストエディタedのGlobal Regular Expression Printから。


sort

sort [OPTION]... [FILE]...
ファイルの行をソートする。デフォルトだと先頭のフィールドに基づいてソートされる。
データは順番が重要になることがあります。例えばgnupotは一行ずつ読み込んで処理するシステムの一つです。plot with linesとするとデータ入力順に線を引いていきます。

デフォルトだと入力文字列を文字列としてみなしてソートする。どういうことかというと、以下のtest.txtをソートすると10が2よりも前にくるということです。
$ cat test.txt
0 zero
1 one
2 two
10 ten
 これをsortすると、
$ sort test.txt
0 zero
10 ten
1 one
2 two
2どころか1よりも手前にきてしまいます。フィールドを数字としてみなしてソートする為には-nオプションをつける必要があります。
$ sort sort.txt -n
0 zero
1 one
2 two
10 ten

join

join [OPTION]... FILE1 FILE2
二つのファイルの内部結合(inner join)を出力する。
比較データなどを1ファイルにまとめる場合などに便利です。
-aコマンドでouter joinにすることが出来る。

結合フィールドはソートされている必要があるので、前述のsortを使うことになります。sortされていない形を保つ必要がある場合はcat -nで行番号を加えることで便宜的なイテレーション番号をつけ、それに基づいてソートをするということが出来ます。


awk

awkは一行でテキスト処理を行う軽快なコマンドであると同時に表現力豊かなプログラミング言語でもあります。awkのスクリプトを書けばこれまで述べてきたコマンドをawkで実装することも出来ます。しかしながらここでは一行でかける簡単な処理に絞って説明をします。詳しい言語実装を知りたい方は下記リンクをご参照下さい。

awkの基本骨子は

1. データファイルを一行読み込む
2. パターンマッチングを行う
3. パターンにマッチした場合に処理を行う

です。例えば
awk '/error/{print $1, $2}'
とすれば"error"の文字列を含む行の1番目、2番目の語を出力するという処理になります。

パターンマッチングの部分はgrepに似ていますが、awkの方がより深入りをして細かい場合分けや出力の指定をすることが出来ます。

データのフォーマットを変えたり、複数データから平均を計算したり、gnuplotに渡すデータを作成したり、shell scriptの中で活躍できるコマンドです。 結構しっかりとした言語なので詳解な説明は下記リンクに譲ります。

*awk参考リンク

The GNU Awk User's Guide
フルドキュメント。非常に詳解なので困ったらこれを見ればいいでしょう。

AWK入門(ドットインストール)
awkの入門の為ならこちらをお勧めします。awkのしっかりとした言語であるという側面と、簡単に記述できるという側面の両方を見ることが出来ます。


2014年11月4日火曜日

Torqueサーバーを1から立ち上げる為の7ステップ

Torqueサーバーを立ち上げるステップをまとめました。

一つ一つの要素技術の説明は良くまとまっている記事がたくさんあるのでそちらに譲り、この記事では全体の流れを説明することを目的とします

Steps

1. 計算機にUbuntuをインストールする
2. ノード間のネットワークを構築する
3. 必要なパッケージをインストールする
4. OpenSSHサーバーを立ち上げる
5. torqueの設定をする
6. NFSの設定をする
7. メールの設定をする

適宜済んでいる設定をスキップして読んでください。



1. 計算機にUbuntuをインストールする


まず、全ての計算機に同じバージョンのUbuntuを入れる。
特に問題が起こったということは聞かないが、OSレベルの実装を多く含むことを行うことになるので念のため同じバージョンを使うべきだろう。またジョブを実行する環境が均一である方が望ましいだろう。
また、ここではUbuntuを例に説明しているが他のDebian系のOSでも同様に設定できるはず。


2. ノード間のネットワークを構築する


ヘッドノードとスレイブノードで必要なものが異なる
ヘッドノードとは、Torqueのジョブスケジュリングや、他のノードの状態を管理するユニークなノードである。スレイブノードは実際にジョブを実行するノードである。
ヘッドノードはハブとなる計算機だが、実験自体はスレイブノードで行われる為ヘッドにはそこまでのスペックは要求されない。ただしヘッドが落ちるとシステム全体が止まってしまうので頑強なものが良い。あるいは、ヘッドノードでコンパイルなどのメモリを食う作業を禁止にするべきだろう。

2-1. 物理層のネットワークを構築する

OpenMPIなどでノード間の通信が重要である場合を除いて、特に工夫をする必要はないだろう。
スイッチングハブを購入し、LANケーブルでヘッドとノードをつなげる。2014年現在大方のLANケーブルは1Gbpsである。ので、1Gbpsよりも遅いハブを使うと重大なボトルネックになってしまう。今は1Gbpsに対応したスイッチングハブも安く購入できる。何かと通信は行うので1Gbpsのものを買った方が良いだろう。

2-2. Ubuntu上でネットワークを設定する

Ubuntuでのネットワーク設定はGUIからもCLIからも可能であるが、クラスタの設定をいちいちGUIからやるのは面倒である。CLIで同時に設定できた方がバグも少ないのでCLIをおすすめする。
こちらのUbuntu PCをルータ代わりにして、新しくLANを構築してみるという記事が非常に丁寧にかかれているのでHow Toはこちらに任せたい。ただし、ここではDHCPではなく固定IPアドレスを使う。
Torqueの場合のIPアドレスのコツは0, 1, 2と始めるのではなく、100, 101, 102と始めるということで、この方がのちのち拡張しやすい。


3. 必要なパッケージをインストールする

3-1. Torqueの為のパッケージをインストールする

ヘッドとスレイブで必要とするパッケージが異なる。

ヘッドノード
sudo apt-get install openssh-server
sudo apt-get install torque-server
sudo apt-get install torque-scheduler
sudo apt-get install wakeonlan
sudo apt-get install nfs-kernel-serversudo apt-get install mail-utils
sudo apt-get install postfix

スレイブノード
sudo apt-get install openssh-server
sudo apt-get install torque-mom
sudo apt-get install torque-client
sudo apt-get install nfs-common
さて、パッケージの説明をしたい。

openssh-server
sshサーバー。sshで入れなければ何も出来ない。セキュリティに関しては最低限パスワード認証を禁止してポート番号を変えておくと良い。
 
torque-server
torqueのサーバー。qsubやqdelなどのインターフェイスはここで定義されている模様。

torque-scheduler
ジョブスケジュラー。どのジョブをどのノードで実行するかなどの意思決定を行う。いろんな研究成果を生かした、とても賢い人工知能だと言える。

wakeonlan
コマンドラインからLANにあるコンピュータを起動することが出来る。
サーバーの稼働率や設置場所にも依るが、いちいち電源ボタンを押すのは非効率である。ヘッドからコマンドラインでスレイブノードを起動できるようすると環境構築に便利である。使い方はこちらに

nfs-kernel-server
NFS(Network File System)の為のサーバー。NFSとは簡単に言うとネットワーク上でファイルシステムを共有するというものである。Torqueでは各ノードにあるファイルを統一するのに使われる。ユーザーはヘッドにファイルを置くことで実際の実行環境にも同様にファイルを置くことが出来るということだ。NFSとは何かについてはこちらの記事がわかりやすい
 
mail-utils
postfix
メールサーバー。Torqueには実行終了をメールで知らせる機能があるが、その送信の為に必要になる。また、サーバーは特に夏にはCPU温度をモニタリングする必要がある。CPU温度が閾値を超えたらメールを送るなどの処理をする為にもメールサーバーは有用である。

torque-mom
torque-client
ジョブを受け取って実行する為のパッケージ。


3-2. 環境の移植をする


上で説明したパッケージは汎用的なものだが、環境に応じて必要なパッケージを設定する必要がある。
もし既にあるUbuntuのパッケージを移植する必要があるなら、以下の手順で移植することが出来る。

1. 移植元のコンピュータのパッケージリストを得る
sudo dpkg --get-selections | awk '{print $1}'  > pkglist

2. 移植先のコンピュータにpkglistを送る(USBなどで)

3. 移植先のコンピュータでパッケージをインストールする
cat pkglist | xargs sudo aptitude install -y

これで移植元のパッケージが揃うことになります。ただしバージョンなど、すべて同じ設定になる訳ではありませんし、パッケージではないものはなくなります。



4. OpenSSHサーバー・クライアントの設定をする


4-1. 鍵の生成と交換

openssh-serverをインストールした時点でサーバーは立ち上がっている。ただしお互いにログインする為には公開鍵を共有する必要がある。

ssh-keygen

で固有の秘密鍵・公開鍵のペアを生成することが出来る。

sshサーバーは自身の~/.ssh/authorized_keysに書かれた公開鍵を持つクライアントのみとセッションを開く。ので、すべてのノードで鍵を生成し、すべてのノードのauthorized_keysにコピーする必要がある。あるいは、すべて共通の鍵を利用するということも出来なくはないが、セキュリティ上別の鍵にした方が良いだろう。

4-2. ホストの設定


/etc/hostsと/etc/hosts.allowに通信先のホスト名を記入する必要がある。

/etc/hostsはUbuntuインストール時は自分のPC名とローカルホストとipv6関連のみがかかれているはずである。ここに自分と他のノードのIPアドレスを列記する。ここでの設定はTorqueにも使われる。
 
/etc/hosts
127.0.0.1    localhost
127.0.1.1    yuu

10.44.0.100    head
10.44.0.101    node001
10.44.0.102    node002
# 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
/etc/hosts.allowはTCP接続を許可する相手を指定できる。ここでまとめてローカルネットワーク内のホストを許可することが出来る。

/etc/hosts.allow
portmap: 10.44.0. ALLOW
lockd: 10.44.0. ALLOW
rquotad: 10.44.0. ALLOW
statd: 10.44.0. ALLOW

5. torqueの設定をする


ここの設定はTORQUEの導入・設定に譲る。よくあるエラーに対する対処法もかかれている。
ひとつ追加したいのは、サービスをリスタートすると問題が解決することが多いということである。
torque-serverなどはserviceとして常にバックで走るソフトなので、実行中に設定変更されてもすぐには反映されない。その為環境構築中はこまめに

sudo service torque-server stop
sudo service torque-scheduler stop
sudo service torque-scheduler start
sudo service torque-server start

とすると良い。これでエラーが解決することは多い。スレイブノード側の場合はtorque-momとtorque-clientでこれを行う。


この時点ジョブを実行することが出来るようになっているはずである。ヘッドノードで

pbsnodes

と打って

node001
     state = down
     np = 8
     ntype = cluster 
node002
     state = down
     np = 8
     ntype = cluster
のように出力されたらノードが認識されているということである。
スレイブノードで

pbsnodes -a

と打つとstate = freeとなるはずである。
そうでない場合はここまでの設定を見直す必要がある。

6. NFSの設定をする

ヘッドノードをそのままNFSサーバーとして使うことが出来るが、ノードの数が多いクラスタの場合はヘッドとは別にNFSサーバーを置くべきだろう。その場合も設定方法に違いはない。
How To Set Up an NFS Mount on Ubuntu 14.04が良くまとまっている。
日本語だとUbuntuでNFSサーバの設定をするがわかりやすい。


7. メールの設定をする


postfixをインストールしただけだと多くのメールに送信出来ない。
それは今のメールサーバはPort 25を禁止にしているからである。Port 25はメールの為の標準のポート番号とされている。しかしそのため、多くのスパムメールはPort 25によって送られていた。それを受けてどのメールサーバもPort 25からはメールを受信しない設定をしている。

GmailのアカウントがあればGoogleのメールサーバを使うのがわかりやすい。
サーバでメールを送るまでに設定方法が書かれているのでこちらを参照されたい。





以上の7ステップでTorqueのサーバーを立ち上げることが出来る。試しに以下のコマンドを
複雑に思えるが各要素技術は概念としてはシンプルなものであり、また非常に汎用的に使われているものが多い。Torqueサーバーの有用性はさながら、これを立ち上げることは良い勉強にもなるだろう。






2014年10月17日金曜日

Twitter APIとjNLPによる評判分析




Twitter APIとjNLPで日本語からの評判分析を実装してみました。

システムの構成としては

1. Twitter APIでキーワードを含む直近100ツイートを取得
2. cabochaでツイートの本文を語句解析
3. 得られた語句をjNLPで評判分析
4. 統計値を取り出してプロット
5. 重要なツイートは全文出力

という感じです。
これを毎週cronで行うことでキーワードに対する評判を時系列データとしてプロットが出来るようにしました。

pythonでやればせいぜい100行程度で実装することが出来ます。




1. Twitter APIによるQuery

Pythonだととても簡単に実装出来ます。
Consumer Keyなどは自分のを入れてください。


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This script is to retrive search result from twitter. 
# Basic usage is for sentiment analysis.
# This will most likely to be called from analyze.sh.
#
# Usage:
#    ./twitter.py <QUERY WORD>
#
# Return:
#    List of tweets in structure below.
#    <User Name> <User ID> <Text>

from requests_oauthlib import OAuth1Session
import json
import datetime
import sys

# Twitter Authentication

CK = ''                             # Consumer Key
CS = ''         # Consumer Secret
AT = '' # Access Token
AS = ''         # Accesss Token Secert
url = "https://api.twitter.com/1.1/search/tweets.json" # タイムライン取得用のURL

# Print Date for later use

#d = datetime.datetime.today()
#date = '%s-%s-%d' % (d.year, d.month, d.day)

word = sys.argv[1]
since = sys.argv[2]
params = {"q":word, "count": 100, "since_id": since}

twitter = OAuth1Session(CK, CS, AT, AS)
req = twitter.get(url, params = params)

tweets = []

if req.status_code == 200:
    utftext = req.text.encode('utf-8')
    timeline = json.loads(utftext)
    statuses = timeline["statuses"]
    for tweet in statuses:
        tweetid = tweet["id"]
        username = tweet["user"]["name"].replace(' ', '')
        userid = tweet["user"]["id_str"]
        text = tweet["text"].replace('\n', ' ')
        tweet = {"tweetid": tweetid, "username": username, "userid": userid, "text": text}
        tweets.append(tweet)
    for tweet in tweets:
        print tweet["tweetid"], tweet["username"].encode('utf-8'), tweet["userid"].encode('utf-8'), tweet["text"].encode('utf-8')


else:
    # エラーの場合
    print ("Error: %d" % req.status_code)

2. Cabocha

Pythonで書くことも出来ましたが、簡単にbash one-linerでかけました。

cat texts$date | cabocha -f1 | awk '/名詞/{printf("%s ", $1)} /EOS/{printf("\n")}' > words$date
awkは本当にこういうとき便利ですね。


3. jNLPによる評判分析

現状、ここはかなり適当にやっています。
というかjNLPのサンプルをそのまま使っています。
cabochaによって得た名詞をそのまますべて単語単位でsentiに投げ、その総和をツイートの評判値としています。おそらくこれは良い方法ではありません。


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import codecs
from jNlp.jSentiments import *
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
txt = sys.stdin.readlines()
#print txt

jp_wn = 'wnjpn-all.tab' #path to Japanese Word Net
en_swn = 'senti.txt' #Path to SentiWordNet
classifier = Sentiment()
sentiwordnet, jpwordnet  = classifier.train(en_swn, jp_wn)


# Print pos & neg point for each line
for line in txt:
    positive_sum = 0.0
    negative_sum = 0.0
    nouns = line.split()
    for noun in nouns:
#        print noun
        try:
            positive_score = sentiwordnet[jpwordnet[noun]][0]
            negative_score = sentiwordnet[jpwordnet[noun]][1]
            positive_sum += positive_score
            negative_sum += negative_score
        except KeyError, e:
            pass
#            print 'Not found in Dictionary.'
    print positive_sum, negative_sum


4. Gnuplotでプロット

ここではpos値とneg値を分けてプロットしました。
書いてて思ったのはscatter plotの方が思いました。あとで実装してみます。
ただしpos値, neg値=0.0のツイートが多いのでそれは消した方がいいかもしれません。


gnuplot<<EOF
   set terminal postscript enhanced color
   set title "Sentimental Analysis Report of $dateform: Raw Data"
   set xrange [0:3]
   set yrange [0:1]
   set xtics 1
   set nokey
   set xtics ('Positive' 1, 'Negative' 2)
   plot '${df}pos' using (1):1 w point notitle
   set output "${df}$date.png"
   replot '${df}neg' using (1):1 w point notitle
EOF


まぁこんな感じで100行未満で実装出来ます。
色々なライブラリに依存するので、以上のコードをコピペしても動かないとは思いますが、参考になるかと。


まだ有意義なデータを取り出すに至っていませんがこれから色々動かしてみようと思います。

2014年10月4日土曜日

Cocos2d-js×Webアプリ×Google App Engine

とにかくゲームを公開したい!

個人でソフトウェアプロジェクトを作る場合は様々な制約が存在します。

お金、時間、計算資源...

なるべくお金や時間をかけずに、まずはゲーム開発を練習したい。


そういう方にはCocos2d-js×Web×Google App Engineでの開発をお勧めします。
これらのプラットフォームのメリットを紹介します。


・全て無料で出来る

Cocos2d-jsはオープンソース、GAEも基本無料ですので全て無料でスタートアップが出来ます。



・公開するまでの手順が非常にお手軽

Cocos2d-jsもGAEもデプロイが非常に簡単です。
Cocos2d-jsはコマンドラインで一行、

cocos compile -p web -m release

とだけやれば、リリースビルドが出力されます。
そしてGAEからは基本的に、

config.py update ./

とだけ打てば良い訳です。
面倒な認証などはありません。


・高いクオリティのものが簡単に作れる

Cocos2d-jsはWebアプリケーションを作るに当たってのde factoのゲームエンジンです。
非常に多機能で、煩雑なコーディングをする必要がなく、コアのデザインに集中出来ます。
また、Tiledなどのマップエディタなどがあるのでゲームを広げるのも簡単に出来ます。



要するに安い・早い・簡単ということです。
試しに動かしてみたいゲームのプロトタイプを作る時などに活用してみてはいかがでしょうか。




ついでに、Cocos2d-jsの開発環境を整える所から、Google App Engineでデプロイするまででいくつかつまずいた点があったので並べます。

Points


・setup.pyを実行後はシステムを再起動する

setup.py後に再起動しなくても、cocos newで新しいプロジェクトが作れてしまう。サンプルアプリも動いてしまう。しかし、自作のプロジェクトをコンパイルしようとすると、何故か一部失敗する。どうしてかと思っていたら、システムの再起動を忘れていました。



・相対パス

Web開発の基本ですが、改めて。Cocos2d-jsの出力するhtmlは相対パスで他のファイルを指定しています。その為、ローカルではそのまま実行することが出来ません。ChromeやFire Foxなどの開発環境を使いましょう。Web開発のIDEはブラウザと連携を取るものが多いです。例えばCocos2d-jsの推すWebStormはChrome Integrationがあり、Cocos2d-jsを使うならば最も効率の良いIDEでしょう。



・app.yamlのパス

またもパスの問題です。こちらは、Google App Engineに由来する複雑さです。
GAEにデプロイするにはapp.yamlで開発環境のパスから、Web上でのパスに対応付けをしなければなりません。これがCocos2d-jsにはなかなかに厄介。出力されるフォルダはhtml5となっているでしょうから、これをまるまる指定してWeb上でのルートディレクトリとしてしまいましょう。
GAEのローカルデバッグ環境の問題点として、app.yamlの構成上ではパスは通っていないのにローカルでパスが通っている為に異なる挙動を示してしまうことがあることです。ローカルだとうまく言っていたのに、デプロイするとfile not foundとなる場合は、app.yamlのパスを確認する必要があります。




2014年9月22日月曜日

gnuplotの出力データが大きすぎる時の対処法




非常に大きなデータを扱う場合、postscriptはファイルサイズが大きくなりすぎて開くことが出来なくなってしまうことがあります。大きくなりすぎたpostscriptはデスクトップで開くことも、プリンタに出力することも、どうすることも出来なくなってしまいます。

 非常にデータ数の多いプロットは開くのにも一苦労。

こういうことがないように、gnuplotの出力はpostscriptだけでなくpng形式でも出すことをお勧めします

postscriptのデータサイズが大きくなってしまうのは、postscriptが情報をベクターデータとして保存するからです。もしgnuplotに入力したデータが1000000点あれば、1000000点とそれを構成する情報を保存しなければならない訳です。この形式の良い所は、後からこのpostscriptを解析して元データを復元しやすいところです。しかしながら、データサイズが入力データの大きさに従って大きくなっていってしまうことが問題点としてあります。

それに対してpng形式はデータを単なる画像として保存します。 ただ600*600の点に色を塗っていくだけです。この形式の利点は、元のデータがどんな大きさだろうともpngファイルの大きさは殆ど変わらないことにあります。ただし、タダの画像になるので、情報は不可逆変換されます。即ちpngファイルから元のデータを取り出すことは非常に難しいです


ので、可能な限りpostscriptで出力をして、もしデータサイズが大きくなってしまったらpngファイルに切り替えるという方法が有用でしょう。pngの復元は出来ないといっても、要は元のデータファイルを残しておけばいいのですから、それほど困ることではないです。


2014年9月21日日曜日

テキスト処理の為に学ぶべき4つの技術

テキスト処理を学ぶべき理由 

コードに限らず、テキストは常に扱う対象になります。
コードを書くことには熱心でもテキスト処理を学ぶことに熱心ではない方は結構います。
しかし、テキストはコードと同様に学ぶべき対象なのです。その理由を2点説明します。

 1. ルーチンワークからプログラミングへ

ログやデータの解析はルーチンワークではありません。

テキストとしてのデータは人間が読める対象である場合が殆どでしょう。
人間が読めるデータですから、一行ずつ直接データを読み、必要な作業を手で行うことはできます。
しかしこれはひどく退屈なルーチンワークにしかなりません。
テキストをプログラミングの対象として扱う方法や技術を学ぶことでルーチンワークを排して楽しいプログラミングをすることが出来ます

2. プログラマの生産性を向上させる

テキスト処理は手作業でやろうとすると思う以上に時間がかかるものです。
プロジェクト全体のコメントのフォーマットを変更する、などは手作業でやることも出来ますが、手作業だと変更し忘れるファイルがあったりすることは良くあります
チェックの時間も含めると手作業による効率はあまりよくないことが分かると思います。




以下で紹介する技術は全て一朝一夕で出来るものではありません。むしろ一生かけて学ぶものの一つを紹介することを目的に記事を書きました。
しかし前述のようにこれらの技術は一生使うに能う理由があります。
是非触って見てください。



1. テキストエディタ



当然ですがテキストエディタを扱うということは最も重要なことになるでしょう。

しかし、テキストエディタは熟練度による生産性の差が明瞭に表れるものの一つでしょう。
ViやEmacsなどのエディタは単純に文字を一つずつ打つという機能だけではありません。
文字列置換や様々なユーティリティがあり、また様々なショートカットキーがあります。
これらの機能は直感的ではない所が結構あったりします。それはこれらのキーが熟練者に最適であるようにデザインされているからであり、入門しやすいようになっている訳ではないからです。
この点が多くのIDEや商業ソフトウェアのUIとの違いでしょう。

入門が簡単なエディタと、熟練者にとって最適なエディタ。
一生プログラミングを続けるなら、どちらを選ぶべきかは自明でしょう。


2. awk

テキスト処理と言えばawkです。
awkはテキスト処理だけの為に開発されたという男らしいプログラミング言語です。manページも3ページしかありません。しかしテキスト処理という点に関しては不足のない言語です。

awkの基本的なアルゴリズムはパターンマッチングです。
入力テキストを行毎に読み込み、その行がパターンに合致していたら処理を行う。
これを最終行に行くまで繰り返す。

非常に簡潔で明解な言語です。文法も簡潔なので殆どの処理は一行(one liner)で済ませることが出来ます。

awk '/error/{print $1, $2}'

とすればerrorの文字列を含む行の1番目、2番目の語を出力するという処理になります。

awkは特にデータの解析に有用です。
gnuplotなどにデータを流し込む前の前処理を行ったり、統計値を取ったり、 データからデータを取り出すような処理に対して威力を発揮します。


参照リンク

The GNU Awk User's Guide
フルドキュメント。非常に詳解なので困ったらこれを見ればいいでしょう。

AWK入門(ドットインストール)
awkの入門の為ならこちらをお勧めします。awkのしっかりとした言語であるという側面と、簡単に記述できるという側面の両方を見ることが出来ます。



3. grep

grepは文字列検索の為のコマンドです。
作業のチェックやログの解析などに用いられます。

例えばプログラム中に埋め込んだTODO:をすべて読み込むには

grep -n TODO: main.cpp

とすれば

118:        // TODO: Array of dynamic sized objects.
124:        // TODO: temporal buffer to store nodes from income buffer.
147:            // TODO: Get nodes from income buffer and put it into open list.
170:            // TODO: minf(int f):
221:            // TODO: incumbent solution.
223:                // TODO: For some reason, sometimes pops broken node.
245:                //                TODO: need it to be atomic.
277:                // TODO: Push items to thread safe income buffer.
289:                // TODO: trylock
372:        // TODO: Time to printing these texts are included in the walltime.
377:        // TODO: pack to a method

のように出力され、進捗状況が概観するのに使えます。
awkと比較すると、grepは出力を編集するためのものではなく、インタラクティブに、テキストがどうなっているのかを把握するために使いやすいように思います。

grepによるパターンの検索(Oracle)


4. Ruby or Python

やや大規模なテキスト処理を行う場合、シェルスクリプトやawkでは表現力が足りなかったり、あるいは読みやすいコードにならない場合があります。しかしテキストデータに対してC++やJavaで書くのはオーバーキルな場合が多いです。

RubyやPythonのような言語を理解しているとこういうちょっとしたプログラムを実装するのにも役に立ちます。





先に述べましたように、これらの技術は小手先技ではなく、一朝一夕に得られるものではありません。しかしスケールアップしていくものです。
一生使える技術を学びましょう。




2014年9月12日金曜日

参加出来るオープンソースプロジェクトを探す3つの方法

オープンソースプロジェクトに参加することはプログラマの楽しみであり、社会貢献であり、確かな実績にもなります。

メジャーなオープンソースプロジェクト・団体の名前を上げるならば、GNU, Linux, Mozilla, Ruby, Python, Boost....毎日使っているオープンソースだけでもいくらでもあるでしょう。ただし、概してこれらのプロジェクトに貢献することは非常に大きな傾注を要します。例えばEmacsやLinuxカーネルへの参加は最も優れたプログラマしか許されず、怪しいコードを書くと袋叩きにあうなどという話があります。袋叩きは冗談としても、そのようなインパクトの非常に大きいコードを書くということは簡単に出来ることではありません。

オープンソースへの貢献が非常にハードルの高いものだと思っている方は先のLinuxカーネルの例を良く出します。しかしオープンソースというのは五万とあり、貢献の機会や方法はいくらでもあります。

しかし、五万とあるプロジェクトからどれにコミットすべきなのか、どのようなプロジェクトがあるのか分からないというのが本音でしょう。以下、そんな行き場のない熱意を持ったプログラマの為の指針を紹介します。



1. 既に使っているオープンソースに貢献する

これが出来れば万々歳ですね。使っているうちに、不便な所や、バグを発見したり、あるいは日本語のドキュメントが不足しているなぁと感じることがあると思います。

機能を足して行くタイプのプロジェクトならどんどんパッチを書いていけるし、バグの発見はそれだけで評価されることでしょう。issueに症状を書いて、こういう原因じゃないかと推測し、あわよくばパッチ案を出せれば完璧でしょう。そこまでじゃなくても、バグについて説明があるだけでプロジェクトとしては大きな前進です。

日本語化というのは重要な貢献だと思います。ローカライズというのはどのプロジェクトでも困るものです。概してローカライズの効果は非常に大きいです。英語は共通言語ですが、母国語が英語である人が殆どという訳では全くありません。プロジェクトに依りますが、ローカライズするしないで製作物の影響する範囲は全く異なります。しかし、ローカライズはその言語を母語などにしている人が必要であり、そしてそのクオリティはプロジェクトの運営者には(その人の母語でない限り)分かりません。そうするとローカライズは限られた人しか出来ず、かつ泥臭い作業だけでなく運営部分まで関わることが出来ます。そういう意味でローカライズは価値が大きいです。


2. 日本発のプロジェクトに貢献する

日本発のプロジェクトはドキュメントが英語化されていなかったりするので人の出入りが少ないことがあります。人手が少ないプロジェクトへの参加は当然ありがたがられるし、パッチを当てる機会も多いでしょう。オープンソースというと国籍は関係ない、という話はありますが、実際日本人にとっては日本のプロジェクトの方がやりやすいことは多いと思いますし、ローカライズの重要性は誰もが知っていることでしょう。
やや古いですが、日本のオープンソースという記事があります。ここから探すのも手でしょう。あと有名なのはenchant.jsでしょうか。

3. スタートアッププロジェクトに貢献する

まだ1.0に到達していないプロジェクトもあります。未完成なのでやるべきことは沢山あります。かつ、歴史が短いので参加者も少ないです。ではスタートアッププロジェクトはどうやって見つければいいのでしょうか。プロジェクトのメンバーは様々な所で宣伝して、人を集めているはずです。アンテナを高く張っていればそれを見つけることもできるでしょう。或いはGitHubで検索してみるのも手です

  star:"100..500"

のように検索すれば中規模のプロジェクトが沢山見つかります。また、GitHubは最近のコミットの頻度が表示されます。これを見れば、今まさに伸びてきているプロジェクトなのか、既に沈静化したプロジェクトなのかも判断することが出来ます。



改めて。オープンソースへの貢献=パッチのコミットと狭義に捉えるべきではないと思います。オープンソースにおける成功とは参加することである、と言います。

パッチが最も直截的な貢献のように思えますが、ドキュメントを書いたり、テストを書いたり、宣伝したり、プロジェクトを成立させる為の要素はいくらでもあります。特に職人気質なエンジニアはこういう努力をしたがらない傾向にあります。

恐らく、こういう良く見せる為の工夫というのに拘るというのはあまりアジアにある文化ではないのでしょう。そもそもオープンソースというのがアジアの文化にそぐわないものかもしれません。

泥臭い作業も重要な貢献です。それを無碍にされることはないでしょう。また、ドキュメントやテストを書くことは必ず次につながります。 パッチを書くための下準備であったり、コミュニティの雰囲気を知ったり。



とにかく何でもいいから参加する。コミュニケーションを取る。それがオープンソースにおける成功といいます。

2014年9月7日日曜日

Torqueでジョブの終了をプッシュ通知する

Torqueに大量にジョブを投げる場合、ジョブの終了を通知する仕組みがあると便利です。
しかしドキュメントが意外と少なく苦労したのでここにまとめます。

・Array Job

まず、大量にジョブを投げる場合はloopではなくarray jobを使いましょう。

#PBS -t 1-100

で100個のジョブを投げることが出来ます。

あるいは他のパラメータ同様qsubで

qsub -t 1-100 ./myJob.sh

として指定することも出来ます。

この時、myJob.shでは100個のジョブを識別するのに$PBS_ARRAYIDというパラメータが渡されます。これを用いてジョブ毎の固有の実装をすることが出来ます。


そして全てのジョブが終わった時の通知はこのArray Jobを用いて行います。


・Job Dependencies

Torqueのジョブは依存関係を指定することが出来ます。例えば、このジョブが終了してから、など。

 JOB1=`qsub ./myJob1.sh`
qsub -W depend=after:$JOB1 ./myJob2.sh

このように、qsubの返し値としてジョブIDが出るので、それを用いて依存先を指定できます。

ただし100個の仕事に依存する場合これで書くのは面倒です。そこでArray Jobを使います。

ARRAYJOB = 'qsub -t 1-100 myJobs.sh'
qsub -W depend=afterokarray:$ARRAYJOB[] ./mail.sh

・Array jobの場合はジョブの名前の後に配列を表す括弧を加える必要がありますのでご注意。

これによって、全ジョブ終了後に実行されるジョブを定義することが出来ます。
そして、その仕事としてmailを指定することでプッシュ通知が可能になります。

メールだけではなく、その場で結果の統計を取ったりしてからメールを送ることもできます。
Torqueのメール機能を使ってもいいと思いますが、自由な形式でメールを送るにはスクリプトにした方がわかりやすいと思いますので。

2014年9月6日土曜日

AI-RTS 人工知能によるリアルタイムストラテジー

Web上で簡単に人工知能を実装してモンスターと戦わせるゲームを実装中です。



まだインターフェイスやデザインを作っていないので見た目がへぼい・何が起きているのか分からん・内容が薄いですがコアとなる内部ロジックが完成したのでデプロイしました。


AI-RTS

Html5 & JavaScriptなのでInternet Explorer以外では動くと思いますが未確認です。

リアルタイムストラテジーと書きましたが、リアルタイムに戦略を考えるのは人工知能です。
コンセプトは、プレイヤーは人工知能をセットして、実際の戦闘は眺めるだけ、という感じです。
AIを書くウィンドウはこんな感じ。

http://ai-rts.appspot.com/

見た目はおいおい考えます。
言語はJavascriptです。


プレイヤーがセットしたコードはフレーム毎に呼ばれ、キャラはそれに従って攻撃したり移動したりします。

戦闘画面はこんな感じ。


......今のところデザインとかグラフィックスは適当なので何が何やら分からない感じになっています。
開発中の画面というのはこういうものです。



あと、成長要素みたいなのも取り入れて、技をアップグレードするみたいなシステムも実装予定です。


ちなみに私のPCだとデバッグ用にbombの攻撃力を100にしていたりします。



こういう類のゲームは中身よりも外見の方が大事だというのは分かっているので、デザインを誰かに頼む予定です。




プログラミングの理論 計算機プログラムの構造と解釈

プログラミングの勉強というと、どういうことを思い浮かべますでしょうか。
実践的には言語の仕様やSTLを学ぶというのは大切でしょう。情報科学としてはアルゴリズムとデータ構造、あるいは情報数学のようなものになるでしょうか。

もちろん言語・STLの仕様とは科学者工学者の英知の結晶でありますから、吸収できるものはたくさんありますし、アルゴリズム等を知ることは実装の幅を広げてくれるでしょう。しかしそのどちらもプログラミングの理論かといわれると、少し遠いように思えます。

Just let me code.
プログラミングは理論というより手を動かすものじゃないかと思っていたのですが、そんなときに「計算機プログラムの構造と解釈」(Structure and Interpretation of Programming)という本に出会いました。これはまさしく「プログラミングの理論」といえる内容の本です。

プログラムを実装するに当たってどう考えればいいのか、何を考慮しなければならないのか、良いコードとは何か。言語仕様等に依存せずに、抽象化、構造化、関数型プログラミング、オブジェクト指向、論理プログラミングといった考え方を学ぶことが出来ます。詳しい内容はAmazonのレビューに任せ、何故この本が良いのかに絞ってお話をします。

こういう洋書のいい所は、言葉だけで説明するのではなくちゃんとコードでも説明して、なおかつ練習問題を用意してくれることに思えます。(練習のためのコードはschemeですが、その文法を学ぶことを通じてソフトウェア工学を学べるというつくりになっています。)学術書一般において和書に比べて洋書が厚い・高いのはこういう寄り添った説明があるからでしょう。

この本はMITの一年生の1学期の教科書として書かれ、今は多くの大学でも初年時のプログラミングの教科書となっています。初年時の教科書ですからプログラミングを始める人も読めますし、プログラミング経験が豊富な方もこの本で理論を学んではいかがでしょうか。

ひたすらにコードを書くだけでは学べないものが学べます。特にプログラマを目指す人は必ず読むべきだと思います。


2014年9月5日金曜日

Windows版Guake, Qonsoleの使い方

以前紹介しましたGuakeのWindows版, Qonsoleを紹介します。
Qonsole Icon


QonsoleはWindows上でドロップダウン式に呼び出すことの出来るターミナルです。見た目はこんな感じ。




デフォルトではWin+Cでターミナルを呼び出すことが出来ます。
Windowsのターミナルといえばコマンドプロンプトですが、他のターミナルも呼び出すことが出来ます。こんな感じの画面で設定できます。
コンソールの大きさ、透明度、シェルの種類、呼び出しコマンドなどなど、自由にカスタマイズすることが出来ます。



Windowsではターミナルを使わない、と言う方もいるかと思います。まぁUnixと比較して使い辛いことは間違いないでしょう。しかしGUIよりもCUIの方が効率が良い場面はいくらでもあるでしょう。Qonsoleは非常に手軽に起動出来ますから、これを機会にWindowsにも触ってみてはいかがでしょうか。

2014年9月3日水曜日

コピーしたsshキーを使う(Linux, Ubuntu)

デュアルブートなどをしていると、sshキーを共有して使いたいということは多いと思います。

しかしsshキーを他のOSやPCからコピーして使う場合は、単純に.sshにコピーするだけでは使えません。



1. 権限を変える
sshキーとして使うには権限が必要です。

chown usr:usr ~/.ssh/id_rsa*          (usrにはユーザーの名前を入れる)
chmod 0600 ~/.ssh/id_rsa
chmod 0644 ~/.ssh/id_rsa.pub


2. ssh-add
sshキーが変更・追加されたことをsshコマンドに伝える必要があります。

ssh-add

これで動きます。

一台のPCの複数のユーザー・OSでsshキーを共有することはそんなにセキュリティ上問題ありません(一つ割れば何でも出来ますので)。しかし複数台のPCで共通のキーを作るべきではありません。それがssh-copyなどのコマンドがない理由です。

2014年9月1日月曜日

C++初心者が中級者になるための5冊の本

C++は非常に「巨大な」言語です。

とりあえずプログラムが書けるようになるというのと、C++を「理解した」ということは大きな差があるでしょう。思うにC++は、彷徨える初心者が最も多い言語じゃないでしょうか。

C++は沢山の良書と、それ以上に沢山の悪書があります。
そして残念ながら、C++を始めたばかりの方にはそれを見分けることは出来ないでしょう (出来るなら初心者ではないでしょう)。

constとかstaticとか意味は分かるけど、何の為に使うのかが分からない。 ポリモーフィズムもコードは読めるけど、どういう時にどうクラスを設計したらいいのか分からない。

そういう方にお勧めの本を5冊紹介します。



***

Effective C++ (Scott Meyers)

「C++2冊目の本」として確立した名著。
1冊目で文法を学んだら、次にこのEffective C++を読んで間違いないです。
この本は文法そのものに対する解説は深くはしませんが、何故constをつけるのかを考えることによってconstなどの文法への理解が深まります。
C++自体への理解を深めると同時に、50のルールとして、実際のプログラミングに役立てられるようにまとめられています。


More Effective C++ (Scott Meyers)

C++という名前の由来は、Cをインクメントしたものなので、Cをその一部として含みます。しかしCがその大部分を占めているかというと、必ずしもそうではありません。

大まかにC++はC、オブジェクト指向、テンプレート、STLの4つの集合にゆるやかにまとめることが出来ると言われております。Cとは大きく異なる言語です。Cにちょっと機能を足した、というものではありません。(ちなみにC++は++CではなくC++なので、返し値はCだというジョークがあります。)

MoreEffective C++は主にオブジェクト指向の部分と例外について扱います。何故エラーコードではなく例外を投げるのかなど、オブジェクト指向としてのC++について丁寧に解説されています。多くのプロジェクトはオブジェクト指向でしょうから、とりあえずこの本は優先的に読むべきかもしれません。javaでのオブジェクト指向の経験のある方も、C++固有の事情が結構あるので参考になると思います。


C++ Coding Standard (Herb Sutter and Andrei Alexandrescu)

前書きにこの本の真髄が述べられている。標準化(Standardize)の重要性とその方法について解説した本です。標準化というと自由度が損なわれるという意味だと思われる方は是非この本を読むべきでしょう。この本のもう一つの主張は標準というのは自由である、ということです。

プロジェクトメンバーとお作法を統一するなどという狭い意味ではなく、C++の言語の設計思想や言語実装と照らし合わせ、最もスマートな方法(標準)を知ることでパフォーマンス・移植性・頑強性のトレードオフを高い水準で保つことが出来る、という本です。

標準化の方法について、101のルールにまとめて明文化してあります。


Effective STL (Scott Meyers)


 More Effective C++で述べた4つの集合のうち、STLについて解説した本です。
 
STLはオブジェクト指向とテンプレートに内包された集合ですが、それらに比較して重要度が小さいということではありません。また、オブジェクト指向を先に学ばなければならないということでもありません。STLを学ぶべき理由をいくつかあげると、


1. プロジェクト中に実装するデータ構造の殆どはSTLを利用する

2. オブジェクト指向やテンプレートの勉強になる

3. アルゴリズムとデータ構造について学ぶことが出来る


といったことが挙げられます。

Effective STLはプロジェクトにSTLを使うためのTipsをまとめてあります。それらのTipsを知ることは1のプロジェクト中に実装する為の知識となります。また、Scott Meyersは必ずWhyについて言及します。何故そのようにコードを書くべきなのか。それを理解することで2, 3の知識を得ることが出来る、という構成の本になっています。


C++ Template: Complete Guide
(David Vandevoorde and Nicolai M. Josuttis)


Complete Guideの名の通り、全ての方向からテンプレートプログラミングを解説した本。テンプレートの概念的な説明から入り、それがどのように実装されているかも詳述してあります。テンプレートを実装する際の様々なテクニックをリファレンス的に紹介し、テンプレートメタプログラミングの導入と、STLがどのように実装されているかなどの実例も収録されています。

テンプレートがそうであるように、非常に内容の大きい本です。
この本一冊読めばテンプレートの本質とその実装が出来るようになります。テンプレートの魅力を理解できるようになる一冊です。


***


これらの本をすべて(或いは一部)読んだならば、一通りのオープンソースのコードを読みこなすことが出来ると思います。習うより慣れろというのはプログラミングの鉄則ですから、上記の本を読みつつ、オープンソースのコードを読んだり、自分で何か作ったりしてみてはいかがでしょうか。

5冊合わせると約1550ページ(索引除く)ですので、Introduction to Algorithmを越すページ数です。C++は、それくらい大きな言語です。そして、それらを理解してもまだまだ深い世界があるのです。テンプレートメタプログラミングや並列処理など、まだまだトピックはいくらでもあります。

Peter NorvigのTeach Yourself Programming in Ten Yearsという記事があります。
C++に限った話ではないですが、C++は10年かけて学ぶ価値のあるものだというのは皆の共通見解でしょう。



2014年8月31日日曜日

root.diskを利用したLinuxのバックアップ・復旧の方法

復旧の方法はいくらでもありますが、その一つとして紹介します。

Linuxをいじっていると、復旧の手段がなくなるまでシステムを破損することがあると思います(私はよくあります)。Linuxは何でも自由にいじれます。しかし自由であるということは、責任を伴うということです。

私が(今回)やってしまったのは

1. /dev/loop0にルートをマウントした
2. マウントしたままfsckをした (ERROR!)

でした。
マウントしたままであったのをしばらく気づかず、その後も色々操作をしてしまい、複数のシステムファイルをどこかにやってしまいました(正確にはファイルのinodeが消えてしまったのでしょう)。


結局Ubuntuをインストールしなおして、必要なデータを元のUbuntuから取り出し、そちらはアンインストールすることにしました。

データの取り出し方は、Linux to Linuxは非常に簡単で、

sudo mkdir /mnt
sudo mount /path/to/root.disk /mnt
sudo cp -r /mnt/home/user/files /home/user
sudo umount /mnt


とすればディスクイメージからファイルを取り出すことができます。
何をやっているかというと、

1. sudo mount /path/to/root.disk /mnt

ディスクイメージを/mntにマウント。これによって/mntからディスクイメージにアクセスすることができる

2. sudo cp -r /mnt/home/user/files /home/user

/mnt以下の仮想ファイルの必要なものをコピーしてくる

3. sudo umount /mnt

マウントしたイメージを戻す


といった感じです。

そういう訳で、root.diskのバックアップは定期的にとっておくと便利だと思います。Ubuntuはファイルサイズもそんなに大きくならないので、時間もそんなにかかりません(不思議なことにUbuntuを使っているとHDDをあまり使いません。多分ゲームをあまりダウンロードしなくなるからでしょう。)。

もっとも効率良くLinuxを知る方法は、Linuxをクラッシュさせ、復旧を試みることだというのが有名な話です。そういう意味でこの方法は再起不可能なまでにクラッシュさせた場合に使うべき方法かもしれません。あるいは復旧にかける時間がない時などに、手早く必要なファイルを取り出せます。


こういうことを経験していくと、逆にWindowsの設計思想を理解できるようになるように思えます。
Windowsはシステムファイルを完全に隠蔽しているのでなかなか(意図せず)再起不能にさせることができないのです。



2014年8月30日土曜日

MSVC2012はC++11のclass member initializationに未対応の模様

C++11からclass member initializationが導入されましたがMSVC2012は対応していない模様。

class member initializationはC++のクラスをはじめて触る人が必ずやる初期化でしょう。


・C++11

class C
{
  int x = 7; //これ
public:
  C();
};

メンバの宣言に初期化を定義することが出来、これによってクラスCのオブジェクトは全てx=7で初期化されることになります。これはC++11以前は以下のように記述する必要がありました。


・C++11以前


class C
{
  int x;
public:
  C() : x(7) {}
};

全てのコンストラクタで宣言しなければならないということと、、xの宣言と初期化が別の行に書かれることなどの理由からC++11でclass member initializationが導入されました。


しかしながらこのclass member initialization、MSVC2012は対応していない模様。

MSのドキュメントに詳しく記載されています。

Support For C++11 Features (Modern C++)

実際にC++Standardに従っているコンパイラはあまりないということでしょう。c++11対応といってもその機能の全てを網羅しているとは限らない。
リンク先の表を見てみると、よく使われる機能から順に実装されている様子。

class member initializationも2013から対応しています。

MSVC2012依存のプロジェクトはご注意を。



C++11のこういった機能の追加はコンパイラ技術の向上の賜物でしょう。C++の様々な非直感的な仕様は実はコンパイル時(構文解析時)の制約の為なのですが、だんだんと進歩していっているようです。

2014年8月28日木曜日

Ubuntu(Linux)のリカバリーモードで文字化けする場合

残念ながら、Linuxは日本語にやさしくありません。

iBusの導入も漢字圏などの表意文字圏に対するdisregardと言っても過言ではないでしょう。

まぁ日本語にやさしくないというよりかは、英語以外に対するサポートが少ない、というのが正しい見解でしょう。



日本語を導入したUbuntuをリカバリーモードで起動すると文字化けします。
エラーメッセージから何から全て

sudo: PAM ■

としかかかれないので何が何だか分かりません。これではリカバリーは出来ないです。
しかし日本語自体を消すのも負けた気分です。

リカバリーモード中だけ英語にする方法があります。

/usr/share/recovery-mode/recovery-menu

を開き、

# main

と書かれた行を見つけたら

export LANGUAGE=C
# main

とCを指定しましょう。

するとどういう訳か上手くいき、リカバリーモードが英語になります。(治らない場合はリブートしてみましょう。)


ちなみに私がリカバリーモードを使っているのは間違えてlibz.so.1を消してしまったためです。

libz.soはアプリケーションを管理しているライブラリで、これがなくなるとapt-getもwgetも何も出来なくなってしまいます。libz.soはgnome3のppaに置いてあるので取ってくればよい訳ですが、apt-get, wgetも何も使えなくなるのでそれも出来ない、ロック状態に陥ってしまいました。

この場合、LiveCDを持ってきてlibz.soをコピーすることで解決できます。