ようこそQt世界へ、Qtに染まりましょう

今日で夏休みは終わり。
そんな中、今日は部活に出かけていた。まぁ部室に買ったものを置きに来ただけですが。
今日はそれだけだったのですが、どうも聞けば夏休み前なので宿題で忙しくて活動する人がいないらしい。
まぁ確かに宿題が残ってたらつらいわ。
今年は僕は余裕があったので早く終わったけど、夏休み後半は宿題で大変ですわ。


C++でGUIといえばQtらしい。
というのをKDE好きの友人から聞いた気がする。
もっとも彼が言いたかったのは、XといえばKDE、KDEといえばQt、QtといえばC++みたいなことだったが。
まぁしかしC++のライブラリとしてはQtは非常に有名なので。
というわけでQt SDKをダウンロード。
Qt – Download
ここでLGPL/FreeのQt SDKをダウンロードしてインストール。
ここで気付いたんだが、QtってNokiaが作ってたのか。知らんかった。


できたらQt Creatorを起動する。そしてQt4 GUIライブラリを選択。
ここでmainwindow.uiファイルを選ぶと、グラフィカルな編集画面が出てくる。
これでフォームのデザインをする。
Horizonal SliderとLabelとLCD Numberを配置する。
それぞれ名前はslider,label1,lcdとしておきましょうか。これはプロパティのobjectNameで決められる。
あとLCDはsegmentStyleをflatとかにしておいた方が見やすいね。
とりあえずこれでビルドして実行してみると画面が表示される。
まずQtの第一歩としてはこれでOKです。もちろんこれでは何にも出来ませんが。


さて、ここからがQtの世界なのだが、どうもQtのオブジェクトは全部QObjectを継承しているらしい。
そのQObjectにはシグナルとスロットという機能がある。
VBやらC#の言葉を使えば、シグナルはイベントだ、そしてスロットはイベントに登録するメソッドといったところ。
Qtではシグナルとスロットをつなげて使う。これが特徴。
VBやC#ではメソッドを用意してイベントに登録する。まぁ大して変わらんわな。
しかしQt CreatorというIDEはおもしろい。
この編集画面の上の方にアイコンがたくさんならんでいます。
左からウイジェットの編集・シグナル/スロットの編集……という風なアイコンがならんでいる。
この左から2つ目を選んでみる。そしたら配置してあるウイジェットの上にカーソルを乗せると赤くなる。
これは何をする画面なのかというと、シグナルとスロットをつなぐ画面。
というわけで実践だ。
sliderからドラッグし始めてlcdで放す。するとシグナル/スロット接続を設定という画面が出てくる。
ここでシグナルはvalueChanged(int)を選ぶ。
そしたらこれと同じ引数、または引数を減らしたスロットにつなぐことになる。
ちょうどいいことにdisplay(int)というスロットがあるのでここに接続する。
これでOKする。これで接続完了。実行してみる。
するとスライダーの値を変えていったらいちいち反映される。こりゃすばらしい。


もっともこんな風に毎度毎度ちょうどいいスロットがあるわけでもないですけどね。
今回はlabel1の値を”Value is 10.”のように変えたいとする。さすがにlabelにそんな機能はない。
さて、どうするか。こういうときはドラッグ先を何もないところにする。
すると電気用図記号のグランドマークが出てくる。これは地面、すなわちMainWindowにつなぐということ。
シグナルはvalueChanged(int)を選ぶが、つなぐさきがない。そこで編集をクリック。
そしてSlots側で+を選んでスロットを追加する。ここではgetSlider(int)というスロットを追加した。
そしたらこれを選んでOK。これで接続できた。


あとは接続先を具体的に書けばOK。ここで初めてコードを書くことになる。
まずmainwindow.hを選んでclass MainWindowの定義に書き足す。

class MainWindow : public QMainWindow{
//以下を書き足す
private slots:
void getSlider(int value);
};

private slots:以下を書き足すことになります。
あれ? private:は知ってるが、private slots:ってなんだ?
実はこれはQtの拡張です。実はQtはこれをmocってやつでなんかコンパイルできるコードに変換しているらしい。
まぁこういうのを見ると本当にQtってQtの世界を作ってるよなぁと思わされる。
とりあえずこれで宣言は出来たので、内容をmainwindow.cppに書く。

void MainWindow::getSlider(int value){
this->ui->label1->setText(QString("Value is %1").arg(value));
}

uiの下に今回登録したウイジェットのオブジェクトのポインタが入っている。
ここからlabel1を探して、これのsetTextメソッドを呼び出せばいい。
ここでテキストを設定するわけだが、実はこのテキストがstd::stringとかじゃないというのが厄介。
Qtはなんか自分でいろんなライブラリを用意しているらしい。
Qt 4.5 リファレンス
ここで主要なクラスを見ると、ずいぶんたくさんある。なんとstd::vector相当のものとしてQListとかいうのもある。
この中でQStringというのを探す。いろいろな機能がある。
std::stringよりも多機能なのは間違えなさそうでargメソッドを使えばさっきやりたかったことも簡単にできる。
これでOK。これでビルドして実行すると、ラベルも変わっていきますね。


まぁなんというかQt自体がいろいろなものを持っているのでなかなかおもしろい。
例えばネットワーク系のライブラリもQtにありますね。これは便利そう。
もちろんSTLやBoostと組み合わせて使うのは全く問題ない。
が、なんとなくいらない気がする。QSharedPointerがboost::shared_ptrの代わりになりそうだし。
なんかQtで作るプログラムはQtに染まってしまいそうだ。
まぁしかしいろんな考え方があるでしょう。Qtなしで作った部分とQt部分を組み合わせてつかうだとか。
その辺はC++なので柔軟にできるんじゃないかなと思います。まだ調べてないけど。

小選挙区フィルタの威力

今日は選挙だったということで、選挙速報を見ていろいろやっています。
速報といいますが、淡々と小選挙区の開票の数字を確認してはいろいろやっているだけです。
うちの選挙区は多分接戦だろうといわれていたし、実際当確こそすぐに出たけど数字はそんなに差はなさそう。
お隣の選挙区も接戦ですね。もうこれはこの方が勝利するんじゃないかと思ったら、どこかの開票所の数字が加われば逆転したり。
学校の近くの選挙区もまた接戦、これはどっちが勝っても驚かないレベル。
なかなかスリリングな戦いです。


あれ? この選挙のどこがスリリングなんだよと思った人もいるかもしれない。
そうなんですよね。選挙速報で出ている全体の数字っておもしろいぐらい差があるんですよね。
けど実際の得票数は選挙区によりますが、そんなに差はないというのが現実です。
いや、差が大きい選挙区もあるんですよ。けど小さい選挙区の方が多いと思うんですよ。
まぁこのあたりが小選挙区制の不思議なところです。


小選挙区制ってわかりやすくていいんですけど、死票が多いのがまずいところ。
わかりやすいというのは、その中から1人しか通らないので深く考えずいいと思う人に投げればいい。
かつて採用されていた中選挙区制という名の大選挙区制は、1つの選挙区から3~5人を選出するわけだ。
そしたら過半数を取りたい政党は2人か3人を立候補させることになる。
するとどの人に投げ込もうかというので悩む。実はここでいろいろあって小選挙区制になったそうです。
とはいえ、死票が多いのが悪いところなんですね。
ある選挙区ではA党の候補者が10万1千票、B党の候補者が9万9千票、
ある選挙区ではA党の候補者が10万5千票、B党の候補者が10万3千票、
ある選挙区ではA党の候補者が9万8千票、B党の候補者が9万5千票だったら、
まぁ全体的に見ればA党の人が2人とB党の人が1人ずつ行くぐらいがちょうどいい。
実際にこの3つの区域で3人の選挙区を作れば非常にうまく票割りができていたらそうなっていただろう。
ところが実際はA党の人が3人行くのである。なんというひどい。
それが小選挙区制の問題ですわ。


ところで民主党はこの小選挙区制というシステムは好きらしいです。
この小選挙区比例代表並立制というシステムを作ったのは自由民主党のようです。
大きな政党にとってはわりとおいしい仕組みです。
すこしの差で議席を独占できるわけですから。これほどおいしい話はない。
まぁ前回の衆議院総選挙の結果とか今回の速報とか見れば大体わかることですよね。


まぁ僕はあんまりこの仕組みは好きではないんですが、シンプルですからねぇ。
そういう意味では悪くはないのかも知れません。
全部比例代表制だと政党に属さない候補者はないことになるからまずいし、
大選挙区制は選挙区が広いので大変かも。
あと1人しか投票用紙に書けないのはつらいと思う。半数ぐらいはかけるようにした方がいいかな。
けどそういうことをやっていくとどんどん複雑になっていく。
多分この制度は当分は変わらないので良いお付き合いをしていくしかないですね。

高専カンファレンスとかいうのがあった[kosenconf-008tohoku]

きょうはいわき市で高専カンファレンスという大会があったようです。
あんまり意味もわかってなかったのですが、カンファレンスと調べると会議と出てきた。
全国から高専関係者が集まってきて発表したりする大会ですわ。
今回で8回目の大会となるようです。


Twitterというのは高専関係者が多いらしく、
僕もいつのまにやら高専の学生だと知られるようになれば、一気にFollowしてくれる人が増えたりしたわけです。
そこで話題にあがってまして、大会があるとは知ってたのですがいわきとか行けるか!
というわけで全く参加してないのですが、幸いUstreamでインターネット配信されることに。
それでお昼からその大会の様子を見ていました。
お話はいろいろありましたが、技術に関わる話が多かったように思います。
一番始めに発表されていたのが、会場となっていた福島高専の方でして、
お題は屋上緑化と水耕栽培のお話でした。なかなか斬新な話で楽しかったですね。
そういう話が多いのですが、高専をお題にした話とか、中には趣味について語る人もいてなかなか。
中には高専2年生にして発表する人もいて驚きましたね。
多くの人は高専卒業して大学生だったり高専の専攻科生だったり大学院生だったり、就職されたかたもいたり。
今回は長い短いはあるけれど計12人の人が発表されまして、なかなか楽しかったですね。
それをインターネット経由ではありましたが見れて楽しかったね。


たぶん行っていればまた楽しい発見があっただろうとは思うのですが、
実は関西近辺で開催されたことはないんですね。それで具体的な予定もない。
具体的な予定が決まっているのは11月にある東京での大会だけかな。他は構想段階。
なんでやねん。やる人がおらん。そりゃ深刻な問題だ。
実は今回の大会の発起人はその福島高専の教員なんですわ。
何があったかその人からTwitterでFollowされてちょっと気になって聞いてみたんですわ。
「なんで学校を会場に出来るんですか?」「中の人がやるからってのが大きいんじゃないですか?一般の人でも借りれますけど」
確かにそうだと思いましたね。
この質問は会場についてのことですが、大会全体にも言えるんじゃないかな。
そのあたり幸運だったのではないかなとか思っています。
ちなみにこの方も高専卒業の人で、その後高専専攻科、大学院、そして教員として就職ということらしい。


しかしこういうのはなかなかやろうと言ってできるものではないというのはあるわな。
束になれば強いのか、まぁそういうのはあるわな。
友人もTwitterをやっていて、うちの学校でできたら楽しそうやねとは言っておった。
それが現実になるかはわからないですけど、なればいいですね。
なんにせよこの火を消さないようにしませんとな。
ウソも言い続けてれば本当になるかもしれないしね。
ネタ作りに今度の東京大会に行くのもいいかもしれないけどね。遠いのが難点だが。

BoostとOpenSSLで作るHTTPSクライアント

最近boost::asioがSSLに対応していることを知った。
そしたらとりあえずHTTPSでつなげるということなので調べて実際にやってみた。
とはいえ資料がちぐはぐで困ったものですが。
それにあわせて以前作っていたライブラリを大幅に書き換えてみた。


せっかくなのでできたソースコードとDoxygenで作ったライブラリを置いておく。
HTTPClient.tar.bz2 (36MB)
しかしboostつかってるからってboost::shared_ptr使いすぎだろという印象はうけるかもしれない。
理由は2つありまして、1つは継承を使っていろいろやっているから。(参考記事 : 継承したらポインタ使ってnewしないと代入できないぞ)
もう1つはコピーするのがいやだから。文字列いちいちコピーしてたら大変でしょ。
C++0xなら前者はunique_ptr、後者は右辺値参照に期待して生で渡すとかもありだったかもしれん。


使い方はdoxygen以下のドキュメントに書いてあるがこんな風に使う。

boost::shared_ptr<Hidemaro::HTTPClient> http=Hidemaro::HTTPClient::Create("http://www.example.com/foobar");
http->Request();
std::istream &resstream=http->GetResponceStream();
while(!resstream.eof()){
std::string line;
std::getline(resstream,line);
std::cout<< line << std::endl;
}

楽チンですね。結果はストリームで得られるのでファイル入力と同様に扱えるだろう。
しかもhttps://~ とすれば一応はアクセス出来る。
証明書の検証とかしてないから本当はまずいんだが、シンプルにアクセス出来るようにした。
証明書の検証の方法はまた調べるわ。今のところは証明書無視でやっている。
さらに便利なのはテストでローカルのファイルを読みたいときもあるかも知れない。
そんなときfile:///c:/work/test.txtのようにすれば読める。
これは以前.NETのSystem.Net.WebRequestでfileスキームが使えて便利だったので自分でも実現してみた。
(参考記事 : 日陰のas演算子は支えてくれた)


HTTPSを使うにはboost/asio/ssl.hppをincludeすればよいのだが、OpenSSLが必要。
というわけでインストール。Shining Light Productions – Win32 OpenSSL
ここからLiteじゃないやつをダウンロードしてインストール。
その後インストールしたディレクトリのincludeをインクルードディレクトリに設定。
lib\VCとlib\VC\staticをライブラリディレクトリに設定。
これだけで足りるかと思ったんだがライブラリファイルは手動で組み込む必要があるらしい。
Microsoftのコンパイラの場合はこう書いておけばいい。

#pragma comment(lib, "libeay32MDd.lib")
#pragma comment(lib, "ssleay32MDd.lib")

便利ですね。他のコンパイラでもコンパイラオプションで設定すれば大丈夫なはず。
めんどくさいのでこれはさっきのファイルの中には仕込んである。


ところで、このソースコードはヘッダファイルこそまぁきれいなのだが、ソースは恐ろしいものになっていると思う。
まずHTTPClientを継承したクラスの宣言がつらつらと書かれています。
が、外からこのクラスたちを知ることは出来ないんですね。privateなクラスがならんでいるようなもんですよ。
その次にIClientCreatorというクラスをそれを継承したClientCreatorというクラスがある。
これはTクラスのインスタンスを作るクラスです。なんじゃそりゃという感じですよね。

std::shared_ptr<IClientCreator> creator(new ClientCreator<HTTPClientImpl>(80));
std::shared_ptr<HTTPClient> client=creator->Create("libserver.ddo.jp",0,"/foo",false);

ここでHTTPClientImplをHTTPSClientに変えても動く。
なにがしたかったのかというと、HTTPClientImplのインスタンスを作るオブジェクトとかをstd::mapに投げ込みたかったんですよ。
そのための工夫です。C++のテンプレート様々ですね。
mapの内容を書き換えればなんか別のスキームも追加できるかも知れない。
というなかなかおもしろい設計になっています。


あとはBase64変換とURLエンコード用の関数がありますね。
自分でHTTPのクライアントを組み込もうとか言うのなら参考になるんじゃないかなとは思う。
boost::asio::ip::tcpの資料ってそんなには多くないのよね。
それがつらいよね。あとHTTPの具体的な通信方法を知らないと実装できないし。
とはいえBoostなかったらWinSockとかSocketを直接操作しないといけないので移植とかむりだしね。
Boost使うのが無難だとは思いますよ。そんなに変わらないかも知れないけど。

読み間違えにくい数字の書き方

番号を書いてそれを集めて打ち込むとき何かとミスというのはあるもので大変だ。
打ち込むときの問題なら後で検査すればなんとかなりそうなもんだが、
書かれている字が間違えやすいとかなると大変な話だ。
それをなんとかできないだろうかと考えてみた。


まず番号自体に細工するという方法が考えられるな。
チェックディジットをつけるとか。
入力ミスに気付くにはいい方法ですよね。実際バーコードもその目的でつけてある。
JANで使われているモジュラス10/ウェイト3によれば、
例えば123のチェックディジットは、まず右から数えて奇数桁目を3倍にして総和を取るので、3×3+2+1×3=14、
これの1の位を10から引いて6がチェックディジットになる。なので1236としておくわけだ。
それでいいじゃないですか、というのはあるんだが大きな問題がある。
というのはもし入力ミスならいいのだが、書かれている字がどうやっても読み間違えるとなるといろいろまずい。
訂正能力がないからね。だから間違っているのはわかるけど正しいのは何かわからないという状況になると。
やな話だ。
なら訂正もできればいいですね、というわけで出てくるのがRS符号だな。(参考記事 : 2桁増やせば自動で直してくれる難しい式)
しかし10進数だとできないので8進数を使うことになるかな。しかも訂正のためには2桁足さないといけない。
そうなるとやたらと桁数が多くなっちゃいますよね。それが問題だね。


とはいえ、番号に細工はしてないのでそもそもこの2つの方法は議論にもならんわな。
読みにくい字で書くことの方が問題なのでそれをどうにかできんかということがある。
そのためにちょっと頭を働かせてみた。

番号をならべた表ですね。これをうまくつかえばよろしいんじゃないかということです。
まず初めに考えるのが番号に○をつけることですね。
ところがこれほど番号が密集してるとその数字だけにつけるのは難しい。
まぁそういう問題はあるのであんまりよろしくないね。
使わない数字を二重線で消すという方法もありかなと思ったんだがめんどくさすぎる。
結局使えそうなのはその数字を消すという方法ぐらいですね。
しかし鉛筆とかペンで消すと何を消したかというのが一見してわからないかも。
まぁそこまで気にするほどではないとは思うけど。
そこで蛍光マーカーで消してみたがいい感じ。
なかなかいいじゃないですか。


こういう工夫って大切ですよね。
通販の注文をOCR用紙でやることってありますけど、数字の書き方って決まってるんですよね。
だから結構手間がかかる。まぁそれでもマークシートに比べれば楽ですが。
今回の発想はマークシートに近いが、別に読むのは機械じゃないのでゆるくてすむかなと。
まぁこれが採用されるかは知らんが。というか実際の使い勝手がどうかによるよね。

ローラーでボンド塗り塗り

今日は部で工作をしていた。
何かというとボール紙に印刷した紙を貼り付ける作業です。
接着剤は木工用ボンドです。もちろんコニシ製ね。
やはり接着力の面でいいですからね。


とはいえ難しい問題もあるわけです。
というのも相当粘りけが強いんですよね。
だから均等に広げるのってむずかしいんですよ。
去年の工作ではこれに水を足して作業しやすくしたのを手で塗ったものです。
なんで手なのかというと、いい道具がなかったから。まだ手が一番ましだったと。
そこで使いやすい道具を検討することになりました。
その結果選ばれたのは広い面積のペンキ塗りなんかでは使われるローラーバケです。
ころころ回したら塗れます。それの一番小さいやつを買ってきました。


バットも一緒にかってきたので、そこにボンドを出して、水を少し足してローラーでぐりぐりする。
そうすればある程度水とボンドが混じる。けどほとんど混ざってないや。
とりあえずそれでローラーでころころして取って、ボール紙の上で広げる。
そうしたらまぁまぁうまく広がっていってくれる。
そしたらあとはその上に紙を乗せて押しつけて完了。


すごくうまいこといった。去年よりもよっぽどうまく広げられるし速いわ。
均等に広げるのって難しいからねぇ。
やはり薄く広げるのには道具を選ばないといけませんなぁ。
大成功だということできれいに洗って乾かしておいた。またきっと活躍してくれるはず。

不在者投票のうまい使い方

昨日、第三種電気主任技術者試験の受験票が届いた。
受験場所は予想通りの場所だった。
というわけで受験票に貼る写真を箱に撮りに行った。
サイズはパスポート用だということで撮影してきて切って貼って完成。
これで安心ですね。


ちょっと気になって不在者投票制度を調べていた。
不在者投票制度は当日の投票所以外の場所で投票できる制度。
期日前投票制度が始まったのでそんなに話題に上がることはなくなったかなとは思うけど。


現在この制度を使うメインは選挙人名簿に登録されている市町村以外にいる人だと思います。
どういうことかというと、たとえば6月まで奈良市に住んでいたが、大津市に転居した。
この場合大津市の選挙人名簿に載るのは転居してから3ヶ月後になってしまう。
なぜならば引き続き3ヶ月以上住所を置いて初めて選挙人名簿に載るから。
ただしこの場合も転居から4ヶ月間は奈良市の選挙人名簿に載っているので問題ではない。
この場合、やり方はいくつか考えられます。
もっとも単純なのは投票所入場券を持って所定の投票所に行く方法。
転送届を出しておけば多分入場券は新しい住所に届くのでこれを受け取って持って行くと。
ただしこの場合転居前の住所の近くの投票所なので行くのがめんどくさいだろう。
そこで不在者投票制度。


その手順はこうである。
不在者投票宣誓書兼請求書を選挙人名簿のある奈良市選挙委員会に出す。
これは郵便で送ればいいでしょう。多分公示前から送って大丈夫なはず。
そしたら指定した場所に速達・書留で不在者投票セットが送られてくる。
これを申告した選挙管理委員会に持って行って投票する。
多分この場合なら大津市選挙管理委員会でしょう。
ポイントは早め早めにやること。じゃないと間に合わないということになる。
投票日に投票用紙が着かないといけないのでね。
ただし最高裁判所裁判官国民審査は最後の一週間にしか投票できないので注意。
到着したら当日に選挙権があることをチェックして投票箱に投げ込まれて終わり。


なんでこんな話題をしたのかというとちょっとニュース見てたんだが、
首相が不在者投票、厳しい表情で「麻生太郎」 (YOMIURI ONLINE)
驚いた。てっきり住所は総理大臣公邸だと思ってたから。
多分自分の選挙区の区域に住所があるんでしょう。別に立候補だけならその必要は無いんですけどね。
そしたら小選挙区で自分の名前書けるじゃない。
まぁそういうことだと思いますよ。


手間がかかるのでありがたい制度とは言えませんが、
現実にこの制度を使わないと投票できない人はいるでしょうから便利に使って下さい。
そうそう、国政選挙以外でもこの制度は使えます。
出張とかでちょうどその期間いない人は、事前に選挙管理委員会に宣誓書を出しておけばいいはず。
そしたら指定した場所に送ってくれる。そして選挙管理委員会に行けばいい。
ただしだ、選挙期間以外は選挙管理委員会は開いてる時間が短い。
なので注意しないとね。地方選挙でも頼るのはいるところの選挙管理委員会なんです。

余白0mmなのに余白10cmになる不思議

去年作った印刷プログラムのパラメータを書き換えて印刷テストをしていた。
パラメータの説明を書き忘れたので何だったけなとソースコードを見るはめに。
だめですね、ちゃんと説明を書いておかないと。
というわけで書いておこうと思う。


さて、自作したプログラムなのでなかなか調子も悪い。
何が悪いかというと余白の取り扱いで、余白10mmにしても余白がないという不思議。
左余白15mmにして8mm程度の余白ができるんですよ。なんかおかしいですね。
一方右余白は0mmなのに10mmある。不気味ですね。
.NET Frameworkの提供する能力をほぼそのまま使っているからかなぁ。
今回の原稿は最終的に横幅195mmになったんですが、左余白15mm・右余白0mmになりました。
PDFで出すと不気味なんですが、直接出力するとそんなにおかしくない。
なんか変な感じです。


プリンタの操作というのは難しいです。
できるだけパラメータのチェックは仮想プリンタであるPDFプリンタに出力してチェックしています。
だって紙もったいないから。
けど余白パラメータの設定だけはそうもいかないんですね。
今回は3回目でいけた。勘がよかったからかな。
去年、友人が印刷関係のプログラムを作っていたんですが、実際動作させる環境になるとうまくいかんと調整していた覚えがある。
確か同じ型のプリンタで実験してなかったっけと思ったんですけど、なぜかうまくいかんと。


自作プログラムではそうですが、さすがにAdobe Readerとかはどの環境でもきっちり出力できますよね。
すばらしい!! ありがたみがよくわかりますね。
しかし、きっちり印刷できるフレームワークとかないんかねぇ。
調べたことないんだけど、あったら使いたかったなとか。
まぁ今はこのプログラムでやっていきますか。

展開の性能ばかりよいLZMA、Linuxに来る

最近Twitterから教えてもらう技術ネタが多くて楽しいですね。
今日教えてもらったのはLZMAって圧縮の話。
LZMAは7zipの圧縮アルゴリズムの一つとして人気があったと思います。
これが最近GNU/Linux界で人気があると言うことです。


GNU/LinuxにおけるLZMAですが、gzip・bzip2と同様に使うようです。
ちなみにgzipのアルゴリズムDeflateはZIPのアルゴズムとしても使われているらしい。最近知った。
それはさておき、インストールしてみた。

# yum install lzma

これだけです。便利ですね。そしたらlzmaコマンドが入ります。
さて、使い方ですが、gzip・bzip2と同じですのでこんな感じです。

$ lzma target   #targetをLZMAにより圧縮してtarget.lzmaを作り、元ファイルを消す
$ lzma -d target.lzma #target.lzmaを展開して元ファイルを消す
$ lzma -c target > target.lzma #消したくなければ-cで標準出力へ出してリダイレクト
$ lzma -dc target.lzma > target
$ tar cvf - dir/ | lzma -c > out.tar.lzma
$ lzma -dc out.tar.lzma | tar xvf -

これらが基本的なgzip・bzip2の使い方をコマンドを変えて書いたものです。
実はこのコマンドたちは元のファイルを消しちゃうんですよね。おもしろいでしょ。
それがいやならどうするのって-cをつけるんですよ。これCopyのcです。
出力先を標準出力にするってコマンドなんですけど、それだけ考えたらなんでCopyなのさって思うけどね。
こうやってリダイレクトして使うことが想定されてるんですね。おもしろい。
ところがGNU/Linux使いならば、まず最後の2つは使ったことないと思う。
というのもGNU tarというやつはgzipならばzを、bzip2ならばjを付け足せば勝手にやってくれるんだよね。
けど基本に立ち返ればこういうことになるんです。
BSDの人もGNU tarだからこんなことやらないね。Solarisは違うらしい。
なお、最新のGNU tarではLZMA用オプションが追加されているらしい。


さて、速度の面ではどうなのかというのを実験で確かめてみた。
ターゲットはLinuxカーネルのtarballのtarの部分だ。
初めランダムなファイルでやったんだが、それでは圧縮がうまくいかないので実用的なファイルを持ってきた。
tarファイルは338MiBというえらい図体のファイル。まぁ圧縮すると軽くなりますが。
ちなみにMiBは1024KiBを1MiBとする単位、KiBは1024Bytesを1KiBとする単位。
僕は普通のSI接頭語のk・Mを使うのが好きなんだが、ファイルサイズを調べるduの表示が1024を単位としていたのでわかりやすく書いた。


まず、速さの点では未だ定評があるgzipで試す。

$ time gzip  linux-2.6.30.tar
real 1m14.846s
user 1m9.119s
sys 0m3.857s
$ du -h linux-2.6.30.tar.gz
73M linux-2.6.30.tar.gz
$ time gzip linux-2.6.30.tar;ls -l linux-2.6.30.tar.gz; time gzip -d linux-2.6.30.tar.gz
real 0m20.667s
user 0m10.273s
sys 0m4.755s

さすがgzip、すごく速いね。たった1分15秒で338MiBのファイルを73MiBまで圧縮してくれた。
圧縮にかかる時間を考えるとgzipはなかなかありがたいものです。
展開が21秒というのもなかなかです。
なので、とりあえず圧縮というところでgzipは役に立ちます。
大概のソースコードの配布は未だgzipによるtarballですが、
これはbzip2にしたら容量は小さくなるけど、そもそもそんなに重くないから処理が軽いgzipとしているのだと思います。
ただLinuxのカーネルほどにもなるとgzipでも重いんですね。73MiBは十分大きなファイルです。
そこで軽減するために現在はbzip2がメインです。


bzip2はどうかという話ですが同様にやってみた。

$ time bzip2 linux-2.6.30.tar
real 7m21.002s
user 7m12.102s
sys 0m3.446s
$ du -h linux-2.6.30.tar.bz2
57M linux-2.6.30.tar.bz2
$ time bzip2 -d linux-2.6.30.tar.bz2
real 1m50.682s
user 1m41.545s
sys 0m6.188s

重いね。圧縮には7分21秒かかっています。gzipと比べると相当ひどい。
それでサイズは57MiBか、gzipと比べるとよっぽどよくなっていますが、時間がなぁ。
うーん……こういうの見てるとgzipって弱いマシンでは結構有利だよね。
これの試験って実はLibserverでしてるのよね。こいつそんなに強くないからね。
展開も遅く1分50秒もかかっている。
とはいえ、これでも処理速度とのバランスはよい部類に入るらしい。
圧縮速度について言えばそんなに間違ってはいない、というのはLZMAとの比較でわかります。


そして、今日の本題LZMAですが、その結果はなかなか面白いものになっています。

$ time lzma  linux-2.6.30.tar
real 21m11.949s
user 20m47.397s
sys 0m8.025s
$ du -h linux-2.6.30.tar.lzma
48M linux-2.6.30.tar.lzma
time lzma -d linux-2.6.30.tar.lzma
real 0m30.208s
user 0m22.259s
sys 0m5.055s

圧縮に21分12秒もかかるとかひどい。そりゃ歯磨きしたりしている間に終わらんわな。
しかし圧縮能力はすさまじく48MiBにもなっている。すごい!
けどさぁ、21分かけてこれでもあんまりうれしくないよなぁ。というのがbzip2のときにも感じたこと。
しかし配布ファイルに使うにはわるくないというのが展開の結果である。
なんと30秒で展開できている。これはgzipともいい勝負だ。この展開速度こそLZMAの特徴。


実はGNU/Linux界で話題になっているのはこの展開速度の点なんですね。
Linux移植は2009年1月と、この世界では非常に新しい形式なのですが、
2.6.30からカーネルイメージの圧縮に選択して使うことができるそうです。
って僕がさっき圧縮展開のテストに使ってたカーネルのソースをコンパイルしたやつじゃないですか。
というわけで場所を選べば非常に有利であると言うことです。
考えられる使い道はこのような展開することが非常に多いところ、
それと圧縮率が高いが展開は軽いので、配布ファイルでは使われるかも。カーネルとかならいいかもね。


僕の感想ではまぁLZMAは当分は使わなさそう。
けどメインのマシンなら性能もいいから、tar.lzma、使ってみたいですね。
Lhazが対応すればうれしいですね。まぁ多分対応するための素地はあるんだろうが。
そういえば、tarballってtarのヘッダとかもまとめて圧縮するから圧縮率がいいんですよね。
ちなみにtarballってのはtarして圧縮したもの一般を言う言葉らしい。tar.gzもtar.bz2もtar.lzmaもtarballだね。
さっきgzip微妙だなとか言いましたけど、tar.gzはZIPよりもLHAよりも総合的な圧縮率は高いんですね。
確かこれ書いたことあったよな、というわけで探したらあった。(参考記事 : 優秀な圧縮はどれか?そりゃBZip2じゃないの)
当時はくわしい分析はしてませんが、結果は書いてあるとおりで確かにtarballの成績がいいです。
反面ファイル一覧とかは展開しないと取り出せないのでそこが悪いところですが。
7zipでLZMA使ったときよりもtar.lzmaのほうがよいのだろうか。まぁそのあたりはあとで検討してみよう。


(追記) lzmaとxzについて
どうもその後知ったのだが、Linux用にxzってのを作ったらしい。それによりLinuxでLZMAが使えるようになったのだとか。
LZMAのアルゴリズムのLinuxでの呼び名ということになるのかな。ちょっと詳しいことはなんとも。
なのでここで書いた.lzmaは.xzで、コマンドもlzmaコマンドをxzコマンドとしたほうが今後はよさそうです。
基本的には同じものだと思うんですけどね。けどちょっと違う動作をするらしい。
投稿してから記事を書き換える気にはならないので追記として書いておきました。

どっちもいまいちTuple、どっちも便利Tuple

昼に投げといてもう一度Post、というのはちょっと分かったことがあったから。
そういえばC#ってジェネリックメソッドに型推論機能あったんですね。
知らんかったんですが、これでできることは多そうですね。
ということが実はSystem.Tuple.Create<>()だったりするわけですが。


C++は可変長テンプレート引数がきっかけとなってboost::tupleが標準ライブラリに編入。
.NET FrameworkではF#の導入に際してSystem.Tuple<>が導入されることになりました。
ということでこれは注目するべき事であるという話になるわけです。
そもそもタプルとは何かというと、型の違ういくつかのオブジェクトを投げ込む固定長のコンテナですね。
例えば、int・int・doubleの組を表すデータ構造が欲しかったとき。
Cではいちいち構造体を自作していた。

struct mystruct{
int x; int y; double z;
};
struct mystruct a={10,3,3.3}; //POD式初期化

Perl・Rubyではハッシュリストを使うのが普通かな。

a={:x=>10 , :y=>3 , :z=>3.3 } //Ruby

ハッシュ使うとかチートっぽいけどね。
まぁRubyだとこういうことは配列かハッシュでやるというのが相場ですかね。
しかしPythonにはタプルという仕組みがある。

a=(10,3,3.3)
x=a[0]

なお、Pythonのタプルは一度作ったら変更できないというのが特徴ですね。
なので安心してハッシュの添字にできるというのがウリ。


まぁ、Pythonのタプルは基本的には配列と一緒ですわ。
そういう意味で言うとPerl・Ruby・Pythonいずれも配列か何かでそれは実現できると。
しかしC++にせよC#にせよそういうわけにはいかないんですね。
なぜならば型というシステムがあるから。
RubyではFixnumもStringもArrayも同じ変数に入れられる。そして実行するときにそれが何があるか判定する。
けどC++もC#も、コンパイル時にこの変数はこの型のオブジェクトだと決めておくわけですね。
それでコンパイル時にかなりのことがわかるのでエラーが減って便利ですねと。
C# 4.0からはdynamicもあるけど、あれは例外だ。
というわけで型データの飛ばないことが重要だと。


タプルではないけれどC++にはstd::pairってのがありますね。あれは2個だけだが。
firstとsecondというフィールドがあります。まぁこの辺はC++でSTLといろいろやっていれば理解していると思います。
それを何個もにしたいということでboost::tupleとして導入されました。
その実装からして10変数までですね。まぁそれでもたいしたもんです。
そしてC++0xでは可変長引数テンプレートがあるので、無限にいけるはずだと。
可変長引数の使えるGCC4でコンパイル。

#include <iostream>
#include <tuple>
int main(void){
std::tuple<int,int,int,int,int,int,int,int,int,int,int,int> a(1,2,3,4,5,6,7,8,9,10,11,12);
//auto a=std::make_tuple(1,2,3,4,5,6,7,8,9,10,11,12);
std::get<2>(a)=100;
std::cout << std::get<2>(a) << std::endl;
}

なんで全部intやねんとか言わんといてね。実験のために適当にやっただけなんです。
なんかすごいめんどくさい書き方していますが、今のGCCでは無理だが、最終的には//で消したとおりのやり方で行ける。
さて、タプルから要素を取り出す方法がちょっと変な感じですね。
補助関数std::get()を使います。補助関数がいるというのが何とも言えないところです。
多分Nが変われば型が変わるからでしょうねぇ。
なお、C++では値は変更できます。それはまずいと思うのならconstつければOKです。
auto使ってたらどうするか? const autoにすればOKです。


C#のSystem.Tupleは可変長型引数とかないので、7個以下のオブジェクトを収めることしかできない設計です。
それでいいんかいという話だが、まぁその辺はちゃんと考えがあるわけです。
存在するSystem.Tupleのクラス(静的クラスは除く)は
System.Tuple<T1>
System.Tuple<T1,T2>
System.Tuple<T1,T2,T3>
System.Tuple<T1,T2,T3,T4>
System.Tuple<T1,T2,T3,T4,T5>
System.Tuple<T1,T2,T3,T4,T5,T6>
System.Tuple<T1,T2,T3,T4,T5,T6,T7>
System.Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>
驚いたことが2つある。こいつら抽象クラスとか継承していないわけですよ。
だからこれらのTupleのクラスは兄弟クラスですらないわけです。
もう1つですが、8つ目のクラスはTRestというのがあります。これはTupleの型を書くらしい。
一体どうやって使うのかということ。


実際の使い方ですがこんな風にします。

var t1=System.Tuple.Create('a',10);
System.Console.WriteLine("{0}x{1}",t1.Item1,t1.Item2);
var t2=System.Tuple.Create(1,2,3,4,5,6,7,System.Tuple.Create(8,9,10,11,12));
System.Console.WriteLine(t2.Rest.Item2);

まず、基本の使い方ですが、これも補助メソッドで作って型推論で受けるのがおすすめです。
ジェネリックメソッドに型推論機能があることが分かったので安心して使えますね。
要素はItem1とかいう風なプロパティで取り出せます。簡潔でよろしい。
さて、8つ以上の要素を持つためにはどうするかというと、初め7つを投げ込んで、それ以降はそれでタプルにするという方法を取ります。
そのためのSystem.Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>です。
とはいえ、これも作るのは補助メソッドで作って型推論で受けるのがおすすめ。
ここではintが12要素あるタプルを作っています。
しかし面白くないのはこの仕組みを使っても8つ目以上の要素を取り出すにはRestの何番目とやらないといけない。
だからここでは9番目を取り出しているのだが、わかりにくいですね。
というかこれなら8要素のTuple作って、使い方の提案としてこういう使い方を書けば良かったのに。
8要素Tuple作りたい人も7要素+Restに1要素Tuple入れて使わなきゃならんとかどうよ。
あと型名もずいぶん長くなってしまいます。型推論の導き出した型名は
System.Tuple<System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Tuple<System.Int32,System.Int32,System.Int32,System.Int32,System.Int32>>
とかいう長すぎる型名。var便利ですね。


ちなみに、C# 3.0ですでにタプルは存在したという意見もあります。それ匿名クラスね。
しかし匿名なので使い道が限られる。返り値にできないですからね。
あといちいちクラスを生成するのはどうよというのもある。
というわけでやっぱタプルちゃうわというのが普通の考えだと思います。
やっぱりタプルの使い道って返り値だと思いますから。そのための選択肢ができたのはよろしい。
.NETのは2~7要素の品質はかなりいいですから便利に使えると思います。
C++のそれも決して悪くはありません。ちょっと混乱するところではあるけどね。
ああ、もちろん返り値の型名は型推論は使えないのでちゃんと書いてね。
けど受ける方は型推論でOKなので活用しちゃって下さい。