<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DUMASXcycCp7ImA9WhRVFko.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026</id><updated>2012-01-16T10:30:48.998+09:00</updated><category term="技術情報" /><category term="C++" /><category term="論文紹介" /><category term="思うこと" /><category term="経済" /><category term="構想" /><category term="python" /><category term="_Projects" /><category term="proce55ing" /><category term="haskell" /><category term="金融工学" /><category term="Proj-Newline" /><category term="After Effects" /><category term="Qt" /><category term="OMake" /><category term="Ubuntu" /><category term="django" /><category term="システムトレード" /><category term="Motion Graphics" /><category term="_映像作品" /><title>映像奮闘記</title><subtitle type="html">ちょっと映像関係でてきました</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://mglab.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>161</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/lFRu" /><feedburner:info uri="blogspot/lfru" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CE8GQX8-eip7ImA9WhRRE08.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-6282461883160094495</id><published>2011-11-24T20:11:00.001+09:00</published><updated>2011-11-27T00:53:40.152+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-27T00:53:40.152+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="論文紹介" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>直積量子化(Product Quantization)を用いた近似最近傍探索についての簡単な解説</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5CCS_RdjJRRH126-_x5V2_j4j_Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5CCS_RdjJRRH126-_x5V2_j4j_Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5CCS_RdjJRRH126-_x5V2_j4j_Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5CCS_RdjJRRH126-_x5V2_j4j_Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-DtVuHuUeuTY/Ts5Q8u_1V2I/AAAAAAAABBQ/6tWvan7QThE/s1600/nabe.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-DtVuHuUeuTY/Ts5Q8u_1V2I/AAAAAAAABBQ/6tWvan7QThE/s1600/nabe.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://www.flickr.com/photos/chatani/303581016/"&gt;aka motsu-nabe&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/chatani/"&gt;chatani&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;概要&lt;/span&gt;&lt;br /&gt;
冬の寒さも一段と厳しくなってまいりました。おでんや鍋が恋しくなる季節です。&lt;br /&gt;
&lt;br /&gt;
さて、最近ようやっと一仕事が終わりまして、長ったらしい記事が書けるようになりました。ですので、今回は2011年に&lt;a href="http://www.computer.org/portal/web/tpami"&gt;TPAMI&lt;/a&gt;で発表された、近似最近傍探索についての論文『&lt;a href="http://lear.inrialpes.fr/pubs/2011/JDS11/jegou_searching_with_quantization.pdf"&gt;Product quantization for nearest neighbor search&lt;/a&gt;』について簡単に紹介したいと思います。&lt;br /&gt;
&lt;br /&gt;
この論文は2011年に発表された、最近傍探索アルゴリズムの決定打です。シンプルな理論でありながら既存手法を打ち破るほどの強力な性能を有し、速度も非常に高速、かつ省メモリなのでスマートフォンに載せ、リアルタイムで動作させることも可能です。&lt;br /&gt;
&lt;br /&gt;
以前この手法は&lt;a href="http://www.slideshare.net/ren4yu/334-8419048"&gt;CV勉強会@関東&lt;/a&gt;で紹介されたらしいのですが、具体的に紹介しているページは(最近すぎるので当たり前ですが)現在のところあまり見かけていません。ただ個人的にこの手法はあと5年くらいは本線で戦えるものと思っておりますので、きちんと解説した記事を出すことはある程度有意義なものかなぁと、そういう風に考えています。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;最近傍探索の課題&lt;/span&gt;&lt;br /&gt;
&lt;a href="http://ja.wikipedia.org/wiki/%E6%9C%80%E8%BF%91%E5%82%8D%E6%8E%A2%E7%B4%A2"&gt;最近傍探索&lt;/a&gt;は最も古典的な手法でありながら、現在においても頻繁に利用されているアルゴリズムの一つです。近年のプロセッサの性能向上によって大規模なデータ処理が家庭のパソコンでもできるようになり、コンピュータビジョンにおいても数億件規模(10^8~9)の高次元ベクトルデータを最近傍探索を用いて処理することで、良い精度の結果を得ることが当たり前の時代になってきました。&lt;br /&gt;
&lt;br /&gt;
ただそうは言っても、最近傍探索をそのまま用いることは現実的ではなく、いくつかの課題が浮上してきます。具体的には以下のとおりです:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;いかに圧縮した状態でデータを格納するか&lt;/b&gt;: ベクトルデータをそのままの状態で保持することはメモリ容量の圧迫へ繋がります。例えば128要素のベクトルを考えた場合、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;float&lt;/span&gt;を使用した場合でも&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;32×128=4096bit&lt;/span&gt;を1エントリで消費してしまいます。IOアクセスが生じてしまうと速度は一気に低下してしまうため、ベクトルデータはすべてメモリ上に展開しておくことが望ましいー&lt;br /&gt;しかし、今回我々が扱いたいエントリ数というのは数億とかそういったオーダーです。そのオーダーのベクトルをそのまま格納するのは現在のメモリ容量だとなかなか厳しい。ですので、情報量を保ったままベクトルをいかに圧縮できるかが、実用的な面において重要な課題となります。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;いかに高速に解を見つけられるか&lt;/b&gt;: 次元数の多いベクトルの距離計算は基本的に低速です。さらにそのまま実装してしまうとすべてのエントリに対して距離の計算をする必要があるため速度はO(N)となり、実用的ではありません。1エントリあたりの計算コストを削減したり、そもそも明らかに異なる(クエリより離れすぎている)エントリを計算しないことで、計算を高速に行うことも同じく重要となります。&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
これらの課題を克服するため、近年では近似最近傍探索と呼ばれる手法が盛んに研究されております。その中でも有名なアルゴリズムは&lt;a href="http://d.hatena.ne.jp/mamoruk/20091113/p1" style="font-style: italic;"&gt;LSH(Locality-Sensitive Hashing)&lt;/a&gt;であり、ハッシュ関数によって抽出される近傍エントリのみを計算することで、高速に最近傍探索を行います。ただこの手法は計算用のハッシュを別に格納する構造であるため、全体のサイズは減少するのではなく増大してしまいます。&lt;br /&gt;
&lt;br /&gt;
また、&lt;a href="http://research.preferred.jp/"&gt;Preferred Research&lt;/a&gt;で紹介されている&lt;i&gt;&lt;a href="http://research.preferred.jp/2011/02/minhash/"&gt;MinHash&lt;/a&gt;&lt;/i&gt;は、ベクトルの要素数が定まっておらず、成分が{0,1}の2値しかとらないような特殊なベクトルを計算する際においては有効な手法でありますが、そうでない場合においてはいったんベクトルをバイナリ表現に落とし込まなければならないので一般的に精度は低下してしまいます。今回紹介する直積量子化は、対象のベクトルが高次元であり、かつユークリッド距離による最近傍探索を行いたい場合において威力を発揮する手法です。&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;スカラ量子化&lt;/span&gt;&lt;br /&gt;
直積量子化について説明を行う前に、まず量子化とは何かについて説明していきます。物理をかじったことのある方ですと『&lt;i&gt;量子化 = 物理量を演算子へ変換する&lt;/i&gt;』ものと思っちゃいますけど、そっちの量子化ではなくある数を特定のビット列で表現することの量子化です。&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-smfm4tK3VP8/Ts5hxOy83JI/AAAAAAAABBc/bkq-MGudgQI/s1600/pic01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-smfm4tK3VP8/Ts5hxOy83JI/AAAAAAAABBc/bkq-MGudgQI/s1600/pic01.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;分割された領域に、特定のビットを割り当てる&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
例えば、0〜1の間をとる数を2ビットで表現しろという問題を考えた場合、普通は上図のように0〜1を4分割し、それぞれの数値を割り当てることで表現を行います。このように、少ないビット数で対象の数値を表現することを一般に『&lt;b&gt;スカラ量子化(Scalar Quantization)&lt;/b&gt;』といいます。スカラ量子化によってfloat型(32bit)の数値は、精度を犠牲にすることによって僅か2bitで表現することができるようになりました。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;ベクトル量子化&lt;/span&gt;&lt;br /&gt;
ところで、このスカラ量子化は対象のデータが数値であった場合には効率的ですが、ベクトルの場合だと効率的とは言えません。&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-48F6YKJBC08/Ts5hxZhc9xI/AAAAAAAABBg/EQbMto1gcgI/s1600/pic02.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-48F6YKJBC08/Ts5hxZhc9xI/AAAAAAAABBg/EQbMto1gcgI/s1600/pic02.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;スカラ量子化では、ベクトルを効率良く表現することができない&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
例えば上の図について考えてみましょう。この点群を1エントリ辺り1ビットで表現しようとした場合、スカラ量子化によって各成分を量子化してしまっては最低でも2ビットが必要となりますが、物事を空間的に考えることで発想を転換します。つまり、それぞれのクラスタを代表する点を予めコードブックとして保持しておき、各点は一番近い代表点のインデックスを保持しておくのです。これによってそれぞれの点は僅か1ビットで表現することができるようになりました。このような手法のことを一般に『&lt;b&gt;ベクトル量子化(Vector Quantization)&lt;/b&gt;』といいます(*1)。&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-TrkK6ppGwgA/Ts5hxjzk3wI/AAAAAAAABBo/RbSiygqWYoo/s1600/pic03.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-TrkK6ppGwgA/Ts5hxjzk3wI/AAAAAAAABBo/RbSiygqWYoo/s1600/pic03.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;ベクトル量子化によって、ベクトルを2つの代表点によって表せるようになった&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
*1: 本手法のクラスタリングには&lt;i&gt;k-means algorithm&lt;/i&gt;を使用しています。k-meansに関しては『&lt;a href="http://d.hatena.ne.jp/nitoyon/20090409/kmeans_visualise"&gt;クラスタリングの定番アルゴリズム「K-means法」をビジュアライズしてみた&lt;/a&gt;』が視覚的に分り易いのでそちらを参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;直積量子化&lt;/span&gt;&lt;br /&gt;
ベクトル量子化はスカラ量子化よりも少ないビット数で効率良くベクトルを表現できるのですが、同時に欠点もあります。次元が増大するにつれて使用するコードブックが指数的に増えてしまうのです。&lt;br /&gt;
&lt;br /&gt;
これは次元の呪いに起因するものです。数次元〜数十次元くらいだったらそんなに問題とはならないんですけど、数百とか数千次元になってくるととんでもない量のコードブックが必要となり現実的でない。『&lt;b&gt;直積量子化(Product Quantization)&lt;/b&gt;』はこの次元の呪いを解決するために用いられる、スカラ量子化とベクトル量子化の中間を行く手法です。&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-9XkqLhwYOqo/Ts5hwou692I/AAAAAAAABBY/obDNqsL0vm4/s1600/pic04.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-9XkqLhwYOqo/Ts5hwou692I/AAAAAAAABBY/obDNqsL0vm4/s1600/pic04.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;高次元のベクトルを直積表現によって分解する&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
具体的な手法は下記の通りです。まず、N次元のベクトルをM分割し、N/M次元のサブベクトルを生成します。そして、そのサブベクトルをそれぞれベクトル量子化することによって、インデックスを(i&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;1&lt;/span&gt;, i&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;2&lt;/span&gt;, ..., i&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;M&lt;/span&gt;)のタプルで表現します。そうすれば次元の呪いは発生せず、データ表現も比較的低ビットで抑えられます。&lt;br /&gt;
&lt;br /&gt;
例として128次元のベクトルを考えてみましょう。まず、このベクトルを16分割することで8次元のサブベクトルへ落とし込みます。そして、そのサブベクトルをベクトル量子化によって8bit表現に持ってきた場合、対象のベクトルは8×16=128bitで表現でき、かつ使用するコードブックサイズも16×256=4096と少数で済みます。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;float&lt;/span&gt;型のサイズで考えると30倍以上の圧縮効率です。このように、少数のコードブックサイズで効率よくベクトルを表現できることが直積量子化の利点です。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;距離計算&lt;/span&gt;&lt;br /&gt;
さて、直積量子化によって各ベクトルのエントリを圧縮した状態で格納したとしましょう。あるクエリベクトルが与えられたとして、そのユークリッド距離が最小となるエントリを見つけるにはどうすればいいでしょうか？&lt;br /&gt;
&lt;br /&gt;
幸運なことに、ユークリッド距離の計算は各要素毎に独立しています。つまり、ただ単にクエリベクトルを各サブベクトルに分け、それぞれの領域で距離を計算し、その和を計算するだけで良いのです。よって、直積量子化を用いて最近傍探索を近似的に行うためには:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;クエリベクトルをM分割し、N/M次元のサブベクトルに分解する&lt;/li&gt;
&lt;li&gt;クエリのサブベクトルと、それぞれのコードブックに記された代表ベクトル間の距離を予め計算しておく&lt;/li&gt;
&lt;li&gt;それぞれのエントリがどのインデックスに位置しているのか確認し、2で計算した距離を参照して足し算を行う&lt;/li&gt;
&lt;li&gt;最小距離をもつエントリを候補として提出する&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
ことで実現できます。これが直積量子化を用いた、近似最近傍探索の核となるアルゴリズムです。&lt;/div&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;詳細について&lt;/span&gt;&lt;br /&gt;
この距離計算は非対称性からある程度のバイアスがかかっているため、実際の距離を正確に見積もるためにはこのバイアスを取り除く必要があったりします。また、具体的な距離計算がコードブックだけで済むので省力化されているとはいえ、計算量は依然としてO(N)であり、そこらへんも大規模なデータ数では足を引っ張る原因となります。&lt;br /&gt;
&lt;br /&gt;
んじゃあこれをどうやって解決するのかについては、現論文&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lear.inrialpes.fr/pubs/2011/JDS11/jegou_searching_with_quantization.pdf"&gt;http://lear.inrialpes.fr/pubs/2011/JDS11/jegou_searching_with_quantization.pdf&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
を参照してください。上記2つの懸念についての解決案が記述されており、上の知識があれば多分すらすらと読めるはずです。&lt;br /&gt;
本当はこれも解説しなきゃなんないんですけど、書いている内に疲れたちゃったのでとりあえずコアなとこだけということで勘弁してください。気が向いたら更新します。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-6282461883160094495?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/uN1nfbplTVA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/6282461883160094495/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=6282461883160094495" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/6282461883160094495?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/6282461883160094495?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/uN1nfbplTVA/product-quantization.html" title="直積量子化(Product Quantization)を用いた近似最近傍探索についての簡単な解説" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-DtVuHuUeuTY/Ts5Q8u_1V2I/AAAAAAAABBQ/6tWvan7QThE/s72-c/nabe.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/11/product-quantization.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ICSXk6fyp7ImA9WhdUFU8.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-1696960389247493692</id><published>2011-09-24T01:44:00.000+09:00</published><updated>2011-10-02T12:19:28.717+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-02T12:19:28.717+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>OpenCVアルゴリズムを高速に記述できる補助ライブラリcvutilを公開します</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LzdlaFxtiG44BTuijDWTWVk173c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LzdlaFxtiG44BTuijDWTWVk173c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LzdlaFxtiG44BTuijDWTWVk173c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LzdlaFxtiG44BTuijDWTWVk173c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mmWWbAxTxAk/Tny12-AfG3I/AAAAAAAABBM/nOCZvailhs8/s1600/dunny.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-mmWWbAxTxAk/Tny12-AfG3I/AAAAAAAABBM/nOCZvailhs8/s1600/dunny.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://www.flickr.com/photos/kayveeinc/3137473002/"&gt;The Dunny Collective - Brisbane River&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/kayveeinc/"&gt;KayVee.INC&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;概要&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
OpenCVを用いてアルゴリズムを組む際、&lt;b&gt;ある画像からある画像へ変換処理&lt;/b&gt;を行ったり、&lt;b&gt;関数fを用いて新規に画像を生成&lt;/b&gt;したり、&lt;b&gt;画像の結果を1つの値へと集約する&lt;/b&gt;などの定型的な処理は非常に多く行われておりますが、並列処理を行いかつ速度を考慮したプログラムを組もうとするとある程度のコード量を必要とするためそれなりの手間となります。また画像処理によくあるループ文のネストが大量に発生するため、普通に組んでしまうと一見何をやっているのか非常に分かりづらいコードとなってしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;はこのような冗長な作業を定型化し、複数のアルゴリズム関数と&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;C++0x&lt;/span&gt;に新しく搭載されたラムダ式を使用して高速にアルゴリズムを記述することができます。このようにして作られたアルゴリズムは自動的にOpenMPによって並列化されるため、研究用途などの速度をある程度担保しつつもメンテナンスのし易いコードを記述するための手助けとなります。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;インストール&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;は&lt;a href="https://github.com/"&gt;github&lt;/a&gt;にて公開しております。ダウンロード先は下記のURLを参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://github.com/rezoo/cvutil"&gt;https://github.com/rezoo/cvutil&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;はヘッダオンリーのライブラリです。バージョンがOpenCV 2.x系統であれば、対象の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;include&lt;/span&gt;ディレクトリに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;をコピーするだけで使用できます。&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;C++0x&lt;/span&gt;のラムダ式を用いることで端的に記述することができますが、関数オブジェクトを使用すればある程度古いコンパイラでも正常に動作するでしょう(そこまでして使う利点があるのかどうかは分かりませんが)。&lt;br /&gt;
&lt;br /&gt;
ちなみに、元々は自分用に作られた適当なライブラリなので、バージョンアップに伴ってある程度破壊的な変更を行うこともありますのでご了承ください。その際はバージョンを0.1上げることによって対応します。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;アルゴリズム一覧&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
ここでは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;に搭載されているアルゴリズム一覧の一部を紹介いたします。これらのアルゴリズムは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;STL&lt;/span&gt;のそれと似ているため、C++を触ったことのある方は名前から直感的に機能を類推できるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;transform_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transform_image&lt;/span&gt;関数は対象の画像を、ユニタリー関数を通して出力先へ変換します。cvutilの中では最も汎用性の高い関数となります。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;cvutil::transform_image(src, dst, [](uchar x) {
    return cv::saturate_cast&amp;lt;uchar&amp;gt;(x*2); });
&lt;/pre&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-jLp6tCaOa3U/Tnw_Qcjn4VI/AAAAAAAABBA/YNdGJ7VMZ2g/s1600/result.jpg" imageanchor="1"&gt;&lt;img border="0" height="160" src="http://1.bp.blogspot.com/-jLp6tCaOa3U/Tnw_Qcjn4VI/AAAAAAAABBA/YNdGJ7VMZ2g/s320/result.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
この関数は複数の画像を高度に合成するような場合においても利用できます。アリティ(渡される引数の数)によって、最も適したアルゴリズムが自動的に呼び出されます。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;cvutil::transform_image(src1, src2, dst, [](uchar x, uchar y) {
    return (x + y)/2; });&lt;/pre&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-4fF4DX7mvqk/Tnw_Q774iMI/AAAAAAAABBE/463G-sg3pYM/s1600/result2.jpg" imageanchor="1"&gt;&lt;img border="0" height="132" src="http://4.bp.blogspot.com/-4fF4DX7mvqk/Tnw_Q774iMI/AAAAAAAABBE/463G-sg3pYM/s400/result2.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;generate_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;generate_image&lt;/span&gt;関数はバイナリー関数を用いて、出力先に画像を新しく生成します。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;generate_image&lt;/span&gt;をそのまま用いることは通常ありませんが、x, y座標を元に画像を生成する関数&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;generate_image_xy&lt;/span&gt;や、画像中央に原点がある右手系の座標系u, v座標を元とした関数&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;generate_image_uv&lt;/span&gt;は比較的使い勝手が良いと思います。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;int width = 512;
int height = 512;
cv::Mat_&amp;lt;cv::Vec3b&amp;gt; dst2(height, width);
cvutil::generate_image_xy(dst2, [=](int x, int y) {
    return cv::Vec3b(0, x*256/width, y*256/height); }); // BGR
&lt;/pre&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-YPvu_5NwENo/TnxGtkeTACI/AAAAAAAABBI/kmzh3vcz8NE/s1600/result3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/-YPvu_5NwENo/TnxGtkeTACI/AAAAAAAABBI/kmzh3vcz8NE/s200/result3.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;reduce_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce_image&lt;/span&gt;関数は対象の画像を、バイナリー関数を通して1つの結果へと集約し、その値を返します。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;cv::Mat_&amp;lt;uchar&amp;gt; src3(3, 3);
src3(0, 0) = 0; src3(0, 1) = 1; src3(0, 2) = 2;
src3(1, 0) = 3; src3(1, 1) = 4; src3(1, 2) = 5;
src3(2, 0) = 6; src3(2, 1) = 7; src3(2, 2) = 8;
int result = cvutil::reduce_image(src3, (int)0, std::plus&amp;lt;int&amp;gt;()); // 36&lt;/pre&gt;
上のサンプルは全要素に対しての足し算を行っています。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transfrom&lt;/span&gt;の並列化は兎も角、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;の並列化は一般的に面倒なのですが、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce_image&lt;/span&gt;はそこらへんの処理もきちんと並列化してくれます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;transform_reduce_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transform_reduce&lt;/span&gt;関数は1枚または複数の画像を対象の関数で1つの値へ変換した後に、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;関数を適用します。2種類の結果を合併した集約結果を返す場合などに役立つと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;minmax_element_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;minmax_element_image関数は画像の最小値と最大値を返します。&lt;/span&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;std::pair&amp;lt;uchar, uchar&amp;gt; minmax_result =
    cvutil::minmax_element_image(src); // (min, max)&lt;/pre&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;integrate_image&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;integrate_image&lt;/span&gt;関数は画像を2次元に積分します。具体的には、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;inclusive_scan&lt;/span&gt;関数を2次元的に適用します。バイナリー関数に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;std::plus&lt;/span&gt;を適用した場合、この関数は積分画像の生成と等価です。また、画像の型が対象の二項演算子に関してアーベル群を成していた場合、任意の矩形領域に関しての&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;integrate_image&lt;/span&gt;によって生成された画像を用いて、定数時間による計算が可能となります(参考: &lt;a href="http://mglab.blogspot.com/2011/04/reducescan.html"&gt;並列環境におけるreduceとscanアルゴリズム&lt;/a&gt;)。&lt;br /&gt;
&lt;br /&gt;
OpenCVにも積分画像を生成する関数は存在しているのですが、この関数は並列化を行いかつ任意の二項演算子を適用できる点が異なります。
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;cv::Mat_&amp;lt;uchar&amp;gt; src3(3, 3), dst3(3, 3);
src3(0, 0) = 0; src3(0, 1) = 1; src3(0, 2) = 2;
src3(1, 0) = 3; src3(1, 1) = 4; src3(1, 2) = 5;
src3(2, 0) = 6; src3(2, 1) = 7; src3(2, 2) = 8;
cvutil::integrate_image(src3, dst3, std::plus&amp;lt;uchar&amp;gt;());
// [0, 1, 2;     [0,  1,  3;
//  3, 4, 5;  =&amp;gt;  3,  8,  15;
//  6, 7, 8]      9,  21, 36]&lt;/pre&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;はその他にも色々と関数がありますが、多分名前からどんなことやってるのか大体は理解できると思いますので、とりあえず代表的な関数をいくつか紹介いたしました。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;License&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
自分用に作っているだけなのですが、一応ライセンスは&lt;a href="http://ja.wikipedia.org/wiki/MIT_License"&gt;MIT License&lt;/a&gt;を適用します。誰でも自由に無制限に使ってかまいません。&lt;br /&gt;
&lt;br /&gt;
とりあえずはそんな感じです。もし何か使っていく上で質問や疑問、あるいはご指摘等ございましたらお気軽にコメントまたは&lt;a href="http://www.blogger.com/profile/09706721371333005060"&gt;メール&lt;/a&gt;をお願いします。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;追記&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
お気づきの通り、本来の文脈ならば、アルゴリズムに渡す引数は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;&lt;/span&gt;ではなく何かしらの抽象構造&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;を渡すべきなのです。C++のSTL Algorithmはコンテナでなくイテレータという抽象に依存することによって、任意のデータ構造による適用が可能となり、さらに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transformed_iterator&lt;/span&gt;など、変形を遅延させるような構造を取ることができる。つまり、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvutil&lt;/span&gt;においても本来はそのような『&lt;b&gt;抽象に依存する&lt;/b&gt;』データ構造を起点にアルゴリズムを組んでいくべきなのです。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;// こんな感じで書けたら最高なんだけど…
cvutil::transform_image(
    cvutil::make_resized_view(src, dst.size()),
    dst,
    any_functor);&lt;/pre&gt;
ただこのアナロジーを画像に適用しましょうとなるとなかなか難しく、現状としては&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;a href="http://www.boost.org/doc/libs/1_47_0/libs/gil/doc/index.html"&gt;boost.GIL&lt;/a&gt;&lt;/span&gt;しか存在していない。そういった意味で確かに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;boost.GIL&lt;/span&gt;は魅力的なライブラリなのですが、GILに適用するalgorithmが殆ど存在していませんし、なによりコンパイル時間が&lt;b&gt;boooooooooooost&lt;/b&gt;してしまう。ぱぱっと書いてぱぱっと書き捨てられるような構造がむしろ研究にとっては重要なわけで、そんな面倒なことするよりも多少汚いOpenCVを採用したほうが使い勝手としては向上するよねという、まぁそういった言い訳です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-1696960389247493692?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/j-AVJ0Qsaok" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/1696960389247493692/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=1696960389247493692" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/1696960389247493692?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/1696960389247493692?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/j-AVJ0Qsaok/opencvcvutil.html" title="OpenCVアルゴリズムを高速に記述できる補助ライブラリcvutilを公開します" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-mmWWbAxTxAk/Tny12-AfG3I/AAAAAAAABBM/nOCZvailhs8/s72-c/dunny.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/09/opencvcvutil.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMDQHc7eip7ImA9WhdVF0Q.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-2941447673320979850</id><published>2011-09-16T14:45:00.000+09:00</published><updated>2011-09-24T01:47:51.902+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-24T01:47:51.902+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>OpenCVの画素値アクセスについて</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WGNL6Lm8hV4fKZbCEPs44KPHFsY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WGNL6Lm8hV4fKZbCEPs44KPHFsY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WGNL6Lm8hV4fKZbCEPs44KPHFsY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WGNL6Lm8hV4fKZbCEPs44KPHFsY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-XpQWL5UuOZ8/TnKtXcnIoDI/AAAAAAAABA8/-1e_c9Cesrk/s1600/fireking.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-XpQWL5UuOZ8/TnKtXcnIoDI/AAAAAAAABA8/-1e_c9Cesrk/s1600/fireking.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://www.flickr.com/photos/mkwilliams/4627921577/"&gt;Fire King&lt;/a&gt;" by&amp;nbsp;&lt;a href="http://www.flickr.com/photos/mkwilliams/"&gt;A Continuous Lean&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
何度も何度も繰り返されている議題ですが、今回は画像処理に良くある『&lt;b&gt;全画素を変換する&lt;/b&gt;』という処理のパフォーマンスについて考察します。&lt;br /&gt;
あなたはOpenCVの&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;&lt;/span&gt;を使って、全ての画素値をある関数&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;func&lt;/span&gt;で変換するという処理を行いたいとします。それで、たぶんなんですけど、普通に何も考えず組むとしたらこんな感じのコードになると思います:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;for(int y=0; y&amp;lt;src.rows; ++y) {
    for(int x=0; x&amp;lt;src.cols; ++x) {
        dst(y, x) = func(src(y, x));
    }
}&lt;/pre&gt;
なんの変哲もない普通のループです。このコードは普通に動きます。おわり。ちゃんちゃん。&lt;br /&gt;
&lt;br /&gt;
…そういきたいのですが、パフォーマンスを気にする方々はここでいろいろとした疑問が沸き起こってくるわけです。それじゃあどこが悪いのか。1つずつ疑問点を上げ、その上で上記のコードがある程度の合理性を持っているコードであることを示していきます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;疑問1: 関数呼び出しを行っているからその分遅い？&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;src(y, x)&lt;/span&gt;という処理は結局&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat&amp;lt;T&amp;gt;::operator()&lt;/span&gt;という関数を呼び出していることに相当します。なので、関数呼び出しを数十万のピクセルに対して行っているため、関数呼び出しにかかるコストが無視できないレベルで発生していくのではないか？？&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;回答: 遅くならない&lt;/span&gt;&lt;br /&gt;
OpenCVの&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;::operator()&lt;/span&gt;はインライン展開されます。なので、関数の呼び出しに対して発生する速度的なコストは発生しません。安心して使いましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;疑問2: 掛け算を余計に行なっているために遅い？&lt;/span&gt;&lt;br /&gt;
結局&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;::operator()&lt;/span&gt;の行っていることはコードに直すとこんな感じです。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;src(y, x) == ((T*)(src.data + src.step.p[0]*y))[x]
&lt;/pre&gt;
でも、この項をよく見てみると、xのループに対してyの値は固定されているため、第二項の計算は正直不要でしょう。なのに掛け算の計算でコストが余分にかかってしまうため、速度が遅くなるのでは？？&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;回答: 遅くなるけどそんなに問題じゃない&lt;/span&gt;&lt;br /&gt;
確かに遅くなりますが、そこまで問題となる箇所ではありません。時代は3GHzに突入しているのです。整数の掛け算にかかるコストなんてたかが知れています。&lt;br /&gt;
&lt;br /&gt;
そんなところよりも、別の箇所を改善したほうが大抵の場合劇的に向上します。仮に、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;func&lt;/span&gt;の中に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;std::exp&lt;/span&gt;や&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;std::log&lt;/span&gt;が含まれていたとすると…&lt;br /&gt;
&lt;pre class="prettyprint"&gt;dst(y, x) = std::exp(-(src(y, x) - mu)*(src(y, x) - mu)); // ぐぎゃー
dst(y, x) = -src(y, x)*std::log(src(y, x)); // おもいー&lt;/pre&gt;
…それだけで大分重くなってしまいます。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;sqrt, sin, cos&lt;/span&gt;はまだ我慢できるにしても(それでも掛け算よりは結構重い)、指数、対数関数は普通に使うとかなり重いんです。CV系統などの精度を求めないような計算でしたら、スプライン関数などの近似式に置き換えることを検討しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&amp;lt;T&amp;gt;(), operator()&lt;/span&gt;は範囲チェックを行ってくれる&lt;/span&gt;&lt;br /&gt;
昔のOpenCVには&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&amp;lt;T&amp;gt;()&lt;/span&gt;と同じような処理をしてくれる&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CV_IMAGE_ELEM&lt;/span&gt;マクロなんて言うものもありましたが、これはもう時代遅れの代物です。なぜなら、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat&lt;/span&gt;の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&amp;lt;T&amp;gt;()&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;&lt;/span&gt;の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;operator()&lt;/span&gt;は与えられたx, y座標が範囲内のものであるかどうか、きちんとチェックを行ってくれるからです。範囲外である場合には警告を送ってくれます。そういった意味でも&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CV_IMAGE_ELEM&lt;/span&gt;より&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&lt;/span&gt;や&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;operator()&lt;/span&gt;を利用していくべきでしょう。&lt;br /&gt;
&lt;br /&gt;
『&lt;b&gt;余計な範囲チェックを行っているために遅くならないのか？&lt;/b&gt;』という疑問もあるかもしれませんが、この範囲チェックは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Release&lt;/span&gt;モードで消去されます。なので実際の動作には全く影響されないのです。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;
cv::Mat::at&amp;lt;T&amp;gt;(), cv::Mat_&amp;lt;T&amp;gt;::operator()&lt;/span&gt;は早い&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&amp;lt;T&amp;gt;(), operator()&lt;/span&gt;はきちんと考えられているメンバ関数です。ポインタを用いてがりがり書いたコードよりは少し遅いかもしれませんが、この遅さは全体のアルゴリズムに影響するような遅さではありません。ほっと胸を撫で下ろし、安心して使いましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;でもやっぱり速度が気になる&lt;/span&gt;&lt;br /&gt;
とはいっても、きちんと書かれていないという神経質な方もいるかもしれません。&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;at&amp;lt;T&amp;gt;()&lt;/span&gt;なんて負けた気がして使いたくない&lt;/b&gt;……その場合のコードは大体以下のようになります。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;for(int y=0; y&amp;lt;src.rows; ++y) {
    uchar* src_ptr = src.ptr&amp;lt;uchar&amp;gt;(y);
    uchar* dst_ptr = dst.ptr&amp;lt;uchar&amp;gt;(y);
    for(int x=0; x&amp;lt;src.cols; ++x) {
        dst_ptr[x] = func(src_ptr[x]);
    }
}&lt;/pre&gt;
これだけじゃあ高速化されたといっても微々たるものなので、せっかくですからOpenMPによる並列化を行ってみましょう。さらに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;assert&lt;/span&gt;でサイズが合っているかチェックを行うようにして…そうすると最終的なループはこんな感じになります。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;assert(src.size == dst.size);
#pragma omp parallel for
for(int y=0; y&amp;lt;src.rows; ++y) {
    uchar* src_ptr = src.ptr&amp;lt;uchar&amp;gt;(y);
    uchar* dst_ptr = dst.ptr&amp;lt;uchar&amp;gt;(y);
    for(int x=0; x&amp;lt;src.cols; ++x) {
        dst_ptr[x] = func(src_ptr[x]);
    }
}&lt;/pre&gt;
…&lt;b&gt;大分行数が増えてしまいました。&lt;/b&gt;ただ自分がやりたいことは全画素に対して&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;func&lt;/span&gt;を適用させたい、ただそれだけなのに、ここまで行数を書く必要があるのです。しかもぱっと見で何をしたいのか良く分からない。面倒ですし分かりにくい。&lt;br /&gt;
&lt;br /&gt;
ここで、C++を少しかじったことのある人でしたら、&lt;i&gt;ユニタリー関数を適用させる表式のアルゴリズム関数を適用すればいいんじゃね？&lt;/i&gt;といった考えに至るのは自然な発想でしょう。こんなふうに:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;template&amp;lt;typename SrcType,
         typename DstType,
         typename UnaryFunction&amp;gt;
void transform_image(const cv::Mat_&amp;lt;SrcType&amp;gt;&amp;amp; src,
                     cv::Mat_&amp;lt;DstType&amp;gt;&amp;amp; dst,
                     UnaryFunction unary_op) {
    assert(src.size == dst.size);
    #pragma omp parallel for
    for(int y=0; y&amp;lt;src.rows; ++y) {
        // equivalent to ptr&amp;lt;T&amp;gt;(y)
        const SrcType* src_ptr = src[y];
        DstType* dst_ptr = dst[y];
        for(int x=0; x&amp;lt;src.cols; ++x) {
            dst_ptr[x] = unary_op(src_ptr[x]);
        }
    }
}
&lt;/pre&gt;
上の形の式をヘッダファイルあたりに定義してやれば、後は以下のようなラムダ式を利用して書くだけで自動的に最適なループ処理を行ってくれます:
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;transform_image(src, dst, [](uchar x) -&amp;gt; uchar {
    return cv::saturate_cast&amp;lt;uchar&amp;gt;(x*2);
});&lt;/pre&gt;
この表式ですと、どんな変数がなんの変数に影響を及ぼすのか、全画素に対してどのような処理を行うのか一目瞭然です。また、引数に渡す&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unary_op&lt;/span&gt;はコンパイラの最適化処理によって自動的にインライン展開されるため速度的なオーバーヘッドはありませんし、OpenMPによる並列化も行ってくれます。また任意の関数オブジェクトを作用させることができるので、非常に使い回しの効く関数となっています。&lt;br /&gt;
&lt;br /&gt;
画素云々について言及している方はこれまで数多く見かけましたが、このような画像に特化したアルゴリズム関数について言及している方は、何故か誰もいないというのが現状です。なのでまぁ自分用にざっくり書いているコードなのでいろいろと不備はありますけど、上記のようなアルゴリズムを詰め合わせた補助ライブラリを近いうちに上げていきたいと思います。&lt;br /&gt;
&lt;br /&gt;
追記(2011/09/24): 記事のとおり、補助ライブラリである&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;cvutil&lt;/b&gt;&lt;/span&gt;を&lt;a href="https://github.com/rezoo/cvutil"&gt;github&lt;/a&gt;に上げました。詳細は別記事『&lt;a href="http://mglab.blogspot.com/2011/09/opencvcvutil.html"&gt;&lt;b&gt;OpenCVアルゴリズムを高速に記述できる補助ライブラリcvutilを公開します&lt;/b&gt;&lt;/a&gt;』を参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;補足&lt;/span&gt;&lt;br /&gt;
『イテレータを使って標準のアルゴリズムを適用すればいいだけなのでは？』と思う方もいるかもしれません。つまりこんな感じですね:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;std::transform(src.begin(), src.end(), dst.begin(), [](uchar x) -&amp;gt; uchar {
    return cv::saturate_cast&amp;lt;uchar&amp;gt;(x*2);
});
&lt;/pre&gt;
確かにこの式でも動くんですけど、速度は遅いです。なぜならこのイテレータの指しているデータは、メモリ上に連続していないからです。言い換えると、任意の自然数Nに対して『&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;amp;(*(iter + N)) == &amp;amp;(*iter) + N&lt;/span&gt;』であることが保障されていないため、きちんと対象のデータを指し示すように補正しなければならない。その補正処理に余分な負担がかかって遅くなってしまう。ただ、もしメモリ上に連続であるならば直接ポインタをイテレータとして入れてやることで、(きちんと動作する保障はないですが)高速に動作してくれるでしょう。並列化はされていませんけれど。&lt;br /&gt;
&lt;br /&gt;
また、上記の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transform_image&lt;/span&gt;は並列化は行われておりますが、SIMDによる高速化は行われておりません。これをジェネリックに行うというのは現状としてなかなか厳しいのですが、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Boost.SIMD&lt;/span&gt;の登場によってある程度の希望の光は見えてくるのではないかと思っています。&lt;br /&gt;
&lt;br /&gt;
追記:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;(2011/09/16)コードをコンパイルが通るように若干の修正。ucharを暗黙的に使うのではなく明示的に指定するようにした&lt;/li&gt;
&lt;li&gt;(2011/09/17)記事を書いていて初めて知ったんですけど、&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ptr&amp;lt;T&amp;gt;(y)&lt;/span&gt;は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::Mat_&amp;lt;T&amp;gt;&lt;/span&gt;だと&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;operator[]&lt;/span&gt;でオーバーロードされていた&lt;/b&gt;んですね。恐らくこれを用いることがOpenCV側の意図しているところだろうと判断し、上の式を書き換えました。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-2941447673320979850?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/1LDiN0arEu4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/2941447673320979850/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=2941447673320979850" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2941447673320979850?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2941447673320979850?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/1LDiN0arEu4/opencv.html" title="OpenCVの画素値アクセスについて" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-XpQWL5UuOZ8/TnKtXcnIoDI/AAAAAAAABA8/-1e_c9Cesrk/s72-c/fireking.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/09/opencv.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08BQXg8eip7ImA9WhZaEEw.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-3769699234948820969</id><published>2011-06-26T01:20:00.006+09:00</published><updated>2011-06-26T01:37:30.672+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-26T01:37:30.672+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>boost.gilを利用して透過画像を作る</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/a_oy-nep28IOqX4aui1lis-JFiQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a_oy-nep28IOqX4aui1lis-JFiQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/a_oy-nep28IOqX4aui1lis-JFiQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a_oy-nep28IOqX4aui1lis-JFiQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="text-align: center;"&gt;『&lt;b&gt;対象の画像から、特定の色の箇所だけを透明にした透過画像を作る&lt;/b&gt;』&lt;/div&gt;&lt;br /&gt;
こういった課題に一ヶ月近くかかって出来なかったとかいう話を聞いて、流石にそれはかかり過ぎだろうと脊髄反射で言ってしまったわけですけど、それじゃあ自分だったらどうだろうとか後で思ってちょっとやってみることにしました。好き勝手言って出来なかったとか恥ずかしすぎですから、やっぱりそこらへんは実際にやってみる責任みたいなものは感じているわけです。というわけでboost.gilを使って書いてみた結果が以下。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#include &amp;lt;boost/gil/gil_all.hpp&amp;gt;
#include &amp;lt;boost/gil/extension/io/png_io.hpp&amp;gt;

using namespace boost::gil;

template&amp;lt;typename Pixel&amp;gt;
struct transparent_functor {
public:
    explicit transparent_functor(Pixel bg_pixel): bg_color_(bg_pixel) {};
    Pixel operator()(const Pixel&amp;amp; src) {
        if(src == bg_color_) {
            Pixel dst = src;
            get_color(dst, alpha_t()) = 0;
            return dst;
        } else {
            return src;
        }
    }
private:
    Pixel bg_color_;
};

int main() {
    const char* filename = "src.png";
    const rgba8_pixel_t background_color(0, 255, 0, 255);

    rgba8_image_t src_image;
    png_read_image(filename, src_image);
    rgba8_image_t dst_image(src_image.dimensions());

    transform_pixels(
        const_view(src_image),
        view(dst_image),
        transparent_functor&amp;lt;rgba8_pixel_t&amp;gt;(background_color));
    
    png_write_view("dst.png", view(dst_image));

    return 0;
}
&lt;/pre&gt;結果としてはこんな感じです。上が元の画像で、下が結果の画像。正常に抜き出されていることが分かります:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-E6-DQMwciDc/TgYI6Rtl9MI/AAAAAAAABAg/rWugv8b-G-c/s1600/src.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/-E6-DQMwciDc/TgYI6Rtl9MI/AAAAAAAABAg/rWugv8b-G-c/s200/src.png" width="200" /&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/-c4UBKp9jRm8/TgYI99E-VbI/AAAAAAAABAk/EI5D8jJffBs/s1600/dst.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/-c4UBKp9jRm8/TgYI99E-VbI/AAAAAAAABAk/EI5D8jJffBs/s200/dst.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;余談&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;プログラムより文章を紡ぎ出すのに時間がかかって、改めて自分の文章力の無さにうんざりしています&lt;/li&gt;
&lt;li&gt;というか最近暑い！自分は寝たいのに梅雨ですごい蒸し暑いから寝付けず気になってこんな不毛なことやっちゃってるわけです。今度こそ寝ます！！！&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-3769699234948820969?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/MXU60eQNGD4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/3769699234948820969/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=3769699234948820969" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3769699234948820969?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3769699234948820969?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/MXU60eQNGD4/boostgil.html" title="boost.gilを利用して透過画像を作る" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-E6-DQMwciDc/TgYI6Rtl9MI/AAAAAAAABAg/rWugv8b-G-c/s72-c/src.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/06/boostgil.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcESXk-eCp7ImA9WhZVGUk.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-7378038496980691460</id><published>2011-06-02T00:40:00.002+09:00</published><updated>2011-06-02T00:43:28.750+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-02T00:43:28.750+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="haskell" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Thrustから見る、reduceを用いたアルゴリズム実装</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HkcT3q3gE6D4_33-KD0vHRRgoHc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HkcT3q3gE6D4_33-KD0vHRRgoHc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HkcT3q3gE6D4_33-KD0vHRRgoHc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HkcT3q3gE6D4_33-KD0vHRRgoHc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-kNjHF-x-EEk/TeZLdrbn2aI/AAAAAAAABAE/TJHSxBXoHN0/s1600/John+Martin+-+The+Great+Day+of+His+Wrath.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-kNjHF-x-EEk/TeZLdrbn2aI/AAAAAAAABAE/TJHSxBXoHN0/s1600/John+Martin+-+The+Great+Day+of+His+Wrath.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"The Great Day of His Wrath" by John Martin&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;はじめに&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;世はまさに大並列時代&lt;/b&gt;。火を手にした人類が飛躍的な進化を遂げたように、並列化のパラダイムは、今まで到底不可能と思われていた速さで計算を行うことができるようになりました。&lt;br /&gt;
&lt;br /&gt;
ところが、どんな手法にも欠点は存在するもので、実際に実装しようとすると非常に難しい。何故かというと、並列には並列化特有の問題が存在しており、愚直に実装してしまうとCPUより早くなってしまうどころか遅くなってしまうことだってあり得るのです。これを回避するにはGPUの内部構造についてきちんと理解をした上で、実装したいアルゴリズムそれぞれの場合に特化したコーディングを行う必要がある。&lt;br /&gt;
&lt;br /&gt;
しかしよくよく考えるとおかしな話です。&lt;b&gt;私たちが実装したいのはあくまで手法であり、ハードウェアではありません&lt;/b&gt;。なぜこのような詳細について把握する必要があるのでしょう。これはきちんとした抽象化がなされていない結果生み出された、言ってみれば妖です。この妖によって余計な手間が生み出され、コーディング量は増大し、余計なバグが生成され、絶望した開発者はうつになり、自殺者は増え、世界は暗雲に包まれるー&lt;br /&gt;
&lt;br /&gt;
そのような混沌の中、ある一筋の光、&lt;a href="http://code.google.com/p/thrust/"&gt;Thrust&lt;/a&gt;が現れました。ThrustはCUDAを抽象化し、C++のパラダイムを用いることで本質にのみ注力できるよう開発されたライブラリです。ユーザはただ&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Iterator&lt;/span&gt;に対してアルゴリズムを適用するかの如く&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;device_vector&amp;lt;T&amp;gt;&lt;/span&gt;と各種アルゴリズムを駆使することで、流れるようなプログラムを組むことが可能となります。このような抽象を用いることで、&lt;b&gt;ユーザは詳細な内部構造について頭を悩ませる必要が無くなりました&lt;/b&gt;。誰が書いているのか分からないから使いたくない？ThrustはNVIDIAに所属している開発者&lt;a href="http://research.nvidia.com/users/jared-hoberock"&gt;Jared Hoberock&lt;/a&gt;と&lt;a href="http://graphics.cs.uiuc.edu/~wnbell/"&gt;Nathan Bell&lt;/a&gt;氏によって書かれています。2人とも並列化のプロフェッショナルなので、普通の人が愚直に実装するよりも大抵の場合効率的でしょう。&lt;br /&gt;
&lt;br /&gt;
さて、Thrustには並列化を行うための多種多様なアルゴリズムが存在しています。そして、Thrustはオープンソースです。これはつまり、このソースコードを読めば並列化のプロがどのようにして各種アルゴリズムの並列化を実装しているのかが分かるということです。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Reductions&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
ということで、最近はThrustのソースコードをちょくちょく読んでいるところです。まだ読み始めた最中なのですが、特に感動したのは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Reductions&lt;/span&gt;の項でした。&lt;br /&gt;
&lt;br /&gt;
数々あるSTLのアルゴリズムを普通に実装しようとすると、一つ一つのアルゴリズムすべてに対して、コアレッシングなどのGPGPU特有の問題を回避したコードを記述しなければならず、非常に面倒です。Thrustはこの問題を&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce関数&lt;/span&gt;によって解決しました。この関数は並列化が可能なので、これを用いて書かれた関数は自動的に並列化されます。つまり、Thrustはいわば『&lt;b&gt;全から一を返す&lt;/b&gt;』アルゴリズムすべてを&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を用いて記述することによって、&lt;b&gt;冗長な記述を回避&lt;/b&gt;しているのです。&lt;br /&gt;
&lt;br /&gt;
この&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を用いた並列化の実装について簡単に説明していくことが、今回の記事の目的です。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を初めて聞いた方は前回の記事『&lt;a href="http://mglab.blogspot.com/2011/04/reducescan.html"&gt;並列環境におけるreduceとscanアルゴリズム&lt;/a&gt;』を参照してください。&lt;br /&gt;
&lt;br /&gt;
ここで、本来のThrustはC++によって記述しているのですが、そのままC++で書くと非常に冗長で解り辛くなってしまうので、今回は本質のみを抽出するためHaskellを用いて説明します。あまりHaskellに慣れていないので不適切な書き方等あるかもしれませんが、そのへんはご指摘頂けると幸いです。また、今回の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;には&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;foldr&lt;/span&gt;関数を代わりに用いています。分かると思いますが一応。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;実装&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;max_element, min_element, minmax_element&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;その名の通りリストの中の最大値、最小値、最大と最小値のタプルを返します。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;*Main&amp;gt; max_element [1,3,2,4,3,1]
4
*Main&amp;gt; min_element [1,3,2,4,3,1]
1
*Main&amp;gt; minmax_element [1,3,2,4,3,1]
(1,4)&lt;/pre&gt;ここらへんはまぁ普通に分かります:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;max_element :: Ord a =&amp;gt; [a] -&amp;gt; a
max_element list = foldr max (head list) list

min_element :: Ord a =&amp;gt; [a] -&amp;gt; a
min_element list = foldr min (head list) list

minmax_element :: Ord a =&amp;gt; [a] -&amp;gt; (a, a)
minmax_element list = foldr minmax_func (first, first) $ zip list list where
    first = head list
    minmax_func (min1, max1) (min2, max2) = (min min1 min2, max max1 max2)
&lt;/pre&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;all_of, any_of, none_of&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;all_of, any_of, none_of関数は&lt;/span&gt;対象のリストと真偽値を判定する関数を引数に取り、&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;すべて当てはまっている&lt;/li&gt;
&lt;li&gt;一つ以上当てはまっている&lt;/li&gt;
&lt;li&gt;すべて当てはまっていない&lt;/li&gt;
&lt;/ul&gt;場合にはTrueを返す関数です。pythonでは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;all(), any()&lt;/span&gt;, C++ではまんまのやつがありますね。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;*Main&amp;gt; all_of (\x -&amp;gt; x &amp;gt; 3) [1,3,2,4,3,1]
False
*Main&amp;gt; any_of (\x -&amp;gt; x &amp;gt; 3) [1,3,2,4,3,1]
True
*Main&amp;gt; none_of (\x -&amp;gt; x &amp;gt; 3) [1,3,2,4,3,1]
False
&lt;/pre&gt;これも実装的にはらくちん:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;all_of :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Bool
all_of binary_pred list = foldr (&amp;amp;&amp;amp;) True $ map binary_pred list

any_of :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Bool
any_of binary_pred list = foldr (||) False $ map binary_pred list

none_of :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Bool
none_of binary_pred list = all_of (not . binary_pred) list
&lt;/pre&gt;関数合成を用いてエレガントに解決。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;inner_product, transform_reduce&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;inner_product&lt;/span&gt;は2つのリストに二項演算子を作用させてから、その結果からなるリストを&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;する関数です。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transform_reduce&lt;/span&gt;はリストをいったんユニタリー関数を用いて変形させてから、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を実行する関数です。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;*Main&amp;gt; inner_product (*) (+) 0 [0,1,2] [3,4,5]
14 -- = 0*3 + 1*4 + 2*5

*Main&amp;gt; transform_reduce (\x -&amp;gt; x*2) (+) 0 [1,2,3]
12 -- = 1*2 + 2*2 + 3*2
&lt;/pre&gt;C++だといろいろ冗長に書かないといけないですけど、Haskellだったら余裕です:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;inner_product :: (a -&amp;gt; b -&amp;gt; c) -&amp;gt; (c -&amp;gt; c -&amp;gt; c) -&amp;gt; c -&amp;gt; [a] -&amp;gt; [b] -&amp;gt; c
inner_product binary_op1 binary_op2 init list1 list2 =
    foldr binary_op2 init $ map operate $ zip list1 list2 where
        operate (x, y) = binary_op1 x y

transform_reduce :: (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; b -&amp;gt; b) -&amp;gt; b -&amp;gt; [a] -&amp;gt; b
transform_reduce unary_op binary_op init list =
    foldr binary_op init $ map unary_op list
&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;count_if, count&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;count_if&lt;/span&gt;は条件に合致している要素数を返す関数で、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;count&lt;/span&gt;は指定した値と同じ要素の数を返す関数です。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;*Main&amp;gt; count_if (\x -&amp;gt; x &amp;lt; 3) [1,2,3,4,5]
2
*Main&amp;gt; count 3 [1,3,2,2,3]
2&lt;/pre&gt;&lt;pre class="prettyprint"&gt;count_if :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Int
count_if binary_pred list = foldr (+) 0 count_list where
    count_list = map transform_func list where
        transform_func x = if binary_pred x then 1 else 0

count :: Eq a =&amp;gt; a -&amp;gt; [a] -&amp;gt; Int
count value list = count_if (== value) list
&lt;/pre&gt;Thrustでは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;True&lt;/span&gt;だったら1, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;False&lt;/span&gt;だったら0となるリストを作成して、それを足していく手法をとっていました。&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;count&lt;/span&gt;は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;count_if&lt;/span&gt;が思いつけば楽勝でしょう。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: large;"&gt;&lt;b&gt;find_if, find_if_not&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;find_if&lt;/span&gt;はリストの中で条件に合致している『一番最初の要素』を示すイテレータを返します。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;find_if_not&lt;/span&gt;は逆で、条件に合致していない『一番最初の要素』を示すイテレータを返します。今回は単純に要素のラベル番号を返すようにしました。なかったら最後のラベル+1が帰ってきます。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;*Main&amp;gt; find_if (\x -&amp;gt; x &amp;gt; 3) [1,3,2,5,4]
3
*Main&amp;gt; find_if (\x -&amp;gt; x &amp;gt; 7) [1,3,2,5,4]
5
*Main&amp;gt; find_if_not (\x -&amp;gt; x &amp;gt; 3) [1,3,2,5,4]
0
&lt;/pre&gt;これは微妙に入り組んでいます:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;find_if :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Int
find_if binary_pred list = snd result where
    result = foldr find (False, length list) tuple_list where
        find (b1, i1) (b2, i2)
            | b1 &amp;amp;&amp;amp; b2  = (True, min i1 i2)
            | b1        = (b1, i1)
            | b2        = (b2, i2)
            | otherwise = (False, max i1 i2)
        tuple_list = zip (map binary_pred list) [0..]

find_if_not :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Int
find_if_not binary_pred list = find_if (not . binary_pred) list
&lt;/pre&gt;ただ、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;find_if&lt;/span&gt;はちょっと本家と違います。インデックスが小さい項が常に左の引数となるため省略してるんだとは思いますけど、対称性を満たしていないのがちょっと気持ち悪いので、ここでは交換則を満たすように関数を変形しています。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;実際の実装と課題&lt;/span&gt;&lt;br /&gt;
ここではhaskellを用いて実装しましたが、もちろん実際の実装は異なっており、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;zip&lt;/span&gt;は&lt;a href="http://wiki.thrust.googlecode.com/hg/html/classthrust_1_1zip__iterator.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;zip_iterator&lt;/span&gt;&lt;/a&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;map&lt;/span&gt;は&lt;a href="http://wiki.thrust.googlecode.com/hg/html/classthrust_1_1transform__iterator.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;transform_iterator&lt;/span&gt;&lt;/a&gt;, タプルは&lt;a href="http://wiki.thrust.googlecode.com/hg/html/classthrust_1_1tuple.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;tuple&lt;/span&gt;&lt;/a&gt;を用いて実装しています。これらのイテレータの評価は遅延的に行われるので、複数のメモリアクセスが発生せず、アルゴリズムの高速化に貢献します。&lt;br /&gt;
&lt;br /&gt;
これらの&lt;a href="http://wiki.thrust.googlecode.com/hg/html/group__fancyiterator.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;fancy iterator&lt;/span&gt;&lt;/a&gt;を使用した戦略は非常に賢いとは思いますが、同時に欠点もあります。複数のイテレータを大量に組み合わせるために、通常のSTL algorithmのように&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;begin&lt;/span&gt;と&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;end&lt;/span&gt;を使用してしまうと、両方に対して&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;fancy iterator&lt;/span&gt;を組み合わせなければならないため、2倍の手間がかかってしまうのです。&lt;br /&gt;
&lt;br /&gt;
これらの解決案としては&lt;a href="http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/index.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;boost::range&lt;/span&gt;&lt;/a&gt;のようなRange構造を実装することです。これをパイプ演算子で繋げていくような形をとっていけば、明快で分かりやすく、速度も十分保証されたプログラムを記述できることでしょう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-7378038496980691460?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/J3-2jiVcr8s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/7378038496980691460/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=7378038496980691460" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7378038496980691460?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7378038496980691460?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/J3-2jiVcr8s/thrustreduce.html" title="Thrustから見る、reduceを用いたアルゴリズム実装" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-kNjHF-x-EEk/TeZLdrbn2aI/AAAAAAAABAE/TJHSxBXoHN0/s72-c/John+Martin+-+The+Great+Day+of+His+Wrath.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/06/thrustreduce.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EDQn8_fSp7ImA9WhZWFkg.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-2775051686265562446</id><published>2011-05-18T01:55:00.004+09:00</published><updated>2011-05-18T02:01:13.145+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-18T02:01:13.145+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>Wiresharkを用いたHTMLの初歩的なスクレイピング</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LOWSNm4WQzInaUJkmkUq7vovpj8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LOWSNm4WQzInaUJkmkUq7vovpj8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LOWSNm4WQzInaUJkmkUq7vovpj8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LOWSNm4WQzInaUJkmkUq7vovpj8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;a href="http://mglab.blogspot.com/2011/05/google-art-project.html"&gt;前回&lt;/a&gt;はぽんとスクリプトを上げて「これで画像がダウンロードできますよ」とやったわけだけど、もちろん実際に&lt;a href="http://www.googleartproject.com/"&gt;Google Art Project&lt;/a&gt;の資料が上げられているわけでもないので、きちんとHTMLやJavascriptのソースを見ながら読解していくことになる。&lt;br /&gt;
&lt;br /&gt;
簡単な動作機構だったら単にHTMLのソース見るだけで良いのだけど、&lt;a href="http://www.googleartproject.com/"&gt;Google Art Project&lt;/a&gt;のような複雑な機構だとそうもいかない。行数が多いと面倒だし大抵の場合難読化されてたりで一筋縄ではいかないからだ。そこで、今回はパケット解析というもうひとつの武器を利用することで内部構造を別の側面から理解することにした。思考の流れを書き綴っていくので、HTMLのスクレイピングをやってみたい方にとって何か参考になれば幸いです。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;b&gt;目標: 高画質な絵画をGoogle Art Projectを利用して手に入れる&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;
まず&lt;a href="http://www.googleartproject.com/"&gt;Google Art Project&lt;/a&gt;のサイトへアクセス。絵画ごとに固有のURLが割り当てられており、このURLを解析すれば絵画を入手できると判断。見るからにソースコードからの解析は面倒くさそうだったので、パケット解析ソフトウェア&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;a href="http://ja.wikipedia.org/wiki/Wireshark"&gt;Wireshark&lt;/a&gt;&lt;/span&gt;を用いて解析を行った。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-2yu2emlgI5c/TdKf5bqqwVI/AAAAAAAAA_g/c5KPobqlmJk/s1600/initial.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="276" src="http://2.bp.blogspot.com/-2yu2emlgI5c/TdKf5bqqwVI/AAAAAAAAA_g/c5KPobqlmJk/s400/initial.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;本質のみに注力するため&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;http&lt;/span&gt;プロトコルのみキャプチャ。適当なURLにアクセスし、ズームを1回行い、パケットキャプチャを中断。解析を開始。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-tPRm_dTYFLo/TdKhe_6nW-I/AAAAAAAAA_k/Fo9Jx6PvAnM/s1600/wireshark.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="356" src="http://2.bp.blogspot.com/-tPRm_dTYFLo/TdKhe_6nW-I/AAAAAAAAA_k/Fo9Jx6PvAnM/s400/wireshark.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;画像本体らしきURLにアクセスしているパケットを発見。複数のアクセスがあるってことはたぶん画像は複数に分割されていてそれを読み込んでいるんだろう。調べると&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/unique-id=xi-yj-zk&lt;/span&gt;の形でアクセスしていたので、対応する&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;xy&lt;/span&gt;座標とズーム値&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;z&lt;/span&gt;によって対応する画素値にアクセスすることができると推測。試しにURLにアクセスしてみると、問題なくダウンロードができた。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HpKbAmalC4E/TdKhoIZRNLI/AAAAAAAAA_o/hb4jWyPMKGo/s1600/unnamed.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/-HpKbAmalC4E/TdKhoIZRNLI/AAAAAAAAA_o/hb4jWyPMKGo/s200/unnamed.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;また、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;x,y&lt;/span&gt;の値を変更してのアクセスを行った結果も問題なくアクセスできた。ただ、どうやら範囲外の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;xy&lt;/span&gt;値にアクセスすると404が返されるらしい。当たり前といえば当たり前。アクセス禁止などのペナルティはないっぽいので、(ちょっと礼儀悪いけど)404が返されたらそれが範囲外と解釈することにする。&lt;br /&gt;
&lt;br /&gt;
一旦まとめてみる。&lt;b&gt;画像は分割されており、これらのアクセスはなんかよく分からない&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unique-id&lt;/span&gt;という、おそらく絵画について表しているパラメータと&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;x,y,z&lt;/span&gt;座標の2つだけでダウンロードができる&lt;/b&gt;。ついでに、&lt;b&gt;リファラー, cookie, 認証などの面倒な作業をせずとも直接のダウンロードが許されている&lt;/b&gt;ことも分かる。そこらへんはGoogleさん寛容なんだなぁと思い、まぁAPIを提供してるくらいだからなぁ、とかいろいろ考える。&lt;br /&gt;
&lt;br /&gt;
他の画像に対してのホストを確認してみると、どうやら&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[lh3〜lh6]&lt;/span&gt;までの複数のホストへとアクセスしているらしい。このホストアクセスがランダムか、それとも固有のホストを呼び出さなければならないのか確認してみたかったので、試しにホストだけを変更して、その他のパラメータは固定したままでのアクセスを試みる。結果としては問題なくダウンロードできた。たぶん負荷を分散するという単純な理由から、ランダムに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Javascript&lt;/span&gt;側で割り振っているんだろう。ここで初めてHTMLのソースを閲覧。"&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cmn/js/content.js&lt;/span&gt;"のソースを開き(難読化はされてないようだ)"&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ggpht&lt;/span&gt;"を検索。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ny15wE4J8d8/TdKiCeBk5YI/AAAAAAAAA_s/cPXpuRfQSyM/s1600/ggpht.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="222" src="http://4.bp.blogspot.com/-ny15wE4J8d8/TdKiCeBk5YI/AAAAAAAAA_s/cPXpuRfQSyM/s320/ggpht.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;リストに入れているところからすると、画像へのアクセスはたぶんこのリストの中だけに限られているんじゃないかなと思う。試しに&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;lh7&lt;/span&gt;へアクセス。404が正常に返された。的中。この指針で間違いないので次へ進む。&lt;br /&gt;
&lt;br /&gt;
次に気になるのは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unique-id&lt;/span&gt;だ。一体何処から仕入れているのか知らないと全く手のつけようがない。考えられるのは2つで、&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;アクセス毎に固有の&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unique-id&lt;/span&gt;を発行し、一定期間のみアクセスできるようにしている&lt;/li&gt;
&lt;li&gt;HTMLかどこかに参照しやすいように書かれており、それを抜き出してアクセスする&lt;/li&gt;
&lt;/ul&gt;という発想だ。自分は前者を疑っていたので、それっぽいパケットがあるかどうか監視。結果としてはまったく存在していなかった。というと後者かなと思い、対象のHTMLから&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unique-id(今回の場合だと"vtzd432xqzOpi_3X8JAJ_buly36QKI0n9zGeeWNgBcwsYJTsAKK5mbM9Pgg")&lt;/span&gt;を検索。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-wDxycMqis18/TdKiQLcSIvI/AAAAAAAAA_w/UL66XHDw7l0/s1600/unique.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="222" src="http://3.bp.blogspot.com/-wDxycMqis18/TdKiQLcSIvI/AAAAAAAAA_w/UL66XHDw7l0/s320/unique.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;ビンゴ！これで駒はすべて揃った。まとめに入る。対象の絵画をダウンロードするためには、&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;取得したい絵画のアドレスへアクセス&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;div id="microscope" data-microId="unique-id"&amp;gt;&lt;/span&gt;となっている項を取得、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unique-id&lt;/span&gt;を得る&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;http://lh3.ggpht.com/ - http://lh6.ggpht.com/&lt;/span&gt;のいづれかにアクセス。&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;http://lh3.ggpht.com/unique-id=xi-yj-zk&lt;/span&gt; のような形で画像を取得&lt;/li&gt;
&lt;li&gt;取得した複数の画像を繋ぎ合わせる&lt;/li&gt;
&lt;/ol&gt;後は非常に簡単でただこの単純なアルゴリズムに従って書き下していくだけ。その産物が&lt;a href="http://mglab.blogspot.com/2011/05/google-art-project.html"&gt;こいつ&lt;/a&gt;。こんなに早く仕上がるってことは、たぶんGoogleさんは本格的にダウンロードを禁止したいわけじゃないんだろう。&lt;br /&gt;
&lt;br /&gt;
スクレイピングとしては楽な部類で、普通だともうちょっと複雑な認証をかましてくるので自動化しにくい。&lt;a href="http://ja.wikipedia.org/wiki/CAPTCHA"&gt;Captcha&lt;/a&gt;入ると流石に無理だけど、おそらく現在の文字認識技術をきちんと応用すれば解けるんじゃないかと思っている。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;余談&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;こういう解析は楽しい。どんな感じの楽しさかっていうと、与えられたパズルを解いていく感覚にちょっと近い&lt;/li&gt;
&lt;li&gt;自分はだいたい1時間くらいで解いたけど、早い人はたぶんもっと早いんだろうなって思う。まだまだ精進が足りない&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-2775051686265562446?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/fONtFOyfUk0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/2775051686265562446/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=2775051686265562446" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2775051686265562446?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2775051686265562446?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/fONtFOyfUk0/wiresharkhtml.html" title="Wiresharkを用いたHTMLの初歩的なスクレイピング" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-2yu2emlgI5c/TdKf5bqqwVI/AAAAAAAAA_g/c5KPobqlmJk/s72-c/initial.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/05/wiresharkhtml.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIGSXo7fCp7ImA9WhZWFEo.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-3904743285554502443</id><published>2011-05-16T01:20:00.002+09:00</published><updated>2011-05-16T01:22:08.404+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T01:22:08.404+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Google Art Projectを利用して高画質の絵画を手に入れる</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FvQaoWUKJqu2lzzMiwRaFfS8xVk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FvQaoWUKJqu2lzzMiwRaFfS8xVk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FvQaoWUKJqu2lzzMiwRaFfS8xVk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FvQaoWUKJqu2lzzMiwRaFfS8xVk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4qxD3xZRxLQ/Tc_e0nb9jxI/AAAAAAAAA-g/kRjY7SnPsX0/s1600/Vincent+van+Gogh+-+The+Starry+Night.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-4qxD3xZRxLQ/Tc_e0nb9jxI/AAAAAAAAA-g/kRjY7SnPsX0/s1600/Vincent+van+Gogh+-+The+Starry+Night.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://en.wikipedia.org/wiki/The_Starry_Night"&gt;The Starry Night&lt;/a&gt;" by&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Vincent_van_Gogh"&gt;Vincent van Gogh&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;2011年2月2日、Googleさんは&lt;a href="http://www.googleartproject.com/"&gt;Google Art Project&lt;/a&gt;というサイトをリリースしました。どういうサイトかっていうと&lt;a href="http://www.moma.org/"&gt;MoMAニューヨーク近代美術館&lt;/a&gt;や&lt;a href="http://www.tate.org.uk/britain/"&gt;Tate Britain&lt;/a&gt;など、世界中の美術館にある有名な絵画を渡り歩くことができるという趣旨のサイトで、誰もが一度は見たことがある絵画がー家に居ながらー非常にリアリスティックな解像度で見ることができる。恐ろしい時代になったもんです。&lt;br /&gt;
&lt;br /&gt;
ところがこのサイト、高解像度で見られるのは非常にいいことなのですが、&lt;b&gt;肝心のダウンロードができない&lt;/b&gt;。せっかく高解像度なんですから保存できてもいいはずなのに、だけどできない。&lt;a href="http://maps.google.co.jp/"&gt;Google Map&lt;/a&gt;なんかは常に最新の情報に更新しなければならないので、ダウンロードに制限をかけているのは合理性があるんですけど、絵画とか全く更新する必要がないでしょう。著作権も切れてるのに。よく分からないです。&lt;br /&gt;
&lt;br /&gt;
ということで、なければ自分でなんとかしようという精神で、1時間くらいでちゃっちゃとPythonでスクリプト組んでダウンロードするようにしてみました。即興で組んだのでいろいろ粗い面はありますけど、そこら辺は勘弁してください。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#!/usr/bin/env python
#-*- coding: utf-8 -*-

import sys
import re
import urllib2
import random
from PIL import Image

def usage():
    print "%s [URL]" % sys.argv[0]
    return 1

def get_id(url):
    response = urllib2.urlopen(url)
    if response.code != 200:
        raise TypeError
    data = response.read()
    return re.search(
        r'&amp;lt;div id="microscope" data-microId="(.+)"&amp;gt;', data).group(1)

def get_filename(x, y):
    return "%i_%i.jpg" % (x, y)

def download_image(target_id, x, y, z):
    urllist = [
        "http://lh3.ggpht.com/",
        "http://lh4.ggpht.com/",
        "http://lh5.ggpht.com/",
        "http://lh6.ggpht.com/"
    ]
    base_url = random.choice(urllist)
    url = "%s%s=x%i-y%i-z%i" % (base_url, target_id, x, y, z)

    try:
        response = urllib2.urlopen(url)
    except urllib2.HTTPError:
        return False
    with file(get_filename(x, y), "wb") as fp:
        fp.write(response.read())
    return True

def download_and_get_max_x(target_id, x, z):
    result = download_image(target_id, x, 0, z)
    if result:
        return download_and_get_max_x(target_id, x+1, z)
    else:
        return x

def download_and_get_max_y(target_id, y, z):
    result = download_image(target_id, 0, y, z)
    if result:
        return download_and_get_max_y(target_id, y+1, z)
    else:
        return y

def combine_images(name, max_x, max_y):
    x_size = 512
    y_size = 512

    result = Image.new("RGB", (max_x*x_size, max_y*y_size))
    for y in range(max_y):
        for x in range(max_x):
            image = Image.open(get_filename(x, y))
            result.paste(image, (x*x_size, y*y_size))
    result.save(name)

def main():
    if len(sys.argv) == 1:
        return usage()
    depth = 3
    target_addr = sys.argv[1]
    target_id = get_id(target_addr)
    max_x = download_and_get_max_x(target_id, 0, depth)
    max_y = download_and_get_max_y(target_id, 1, depth)
    for y in range(1, max_y):
        for x in range(1, max_x):
            download_image(target_id, x, y, depth)
    combine_images("result.png", max_x, max_y)

if __name__ == "__main__":
    sys.exit(main())
&lt;/pre&gt;&lt;br /&gt;
使い方は簡単で、&lt;br /&gt;
&lt;pre class="prettyprint"&gt;$ python artproject.py http://www.googleartproject.com/museums/tate/mariana-248
&lt;/pre&gt;のようにURLを指定してあげると勝手に取得して結合してくれます。こんな感じで:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-XWNkInj07vs/Tc_43wAMsII/AAAAAAAAA-o/YCXBDT0oU5I/s1600/Sir+John+Everett+Millais+-+Mariana.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-XWNkInj07vs/Tc_43wAMsII/AAAAAAAAA-o/YCXBDT0oU5I/s1600/Sir+John+Everett+Millais+-+Mariana.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://www.googleartproject.com/museums/tate/mariana-248"&gt;Mariana&lt;/a&gt;" by &lt;a href="http://ja.wikipedia.org/wiki/%E3%82%B8%E3%83%A7%E3%83%B3%E3%83%BB%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%AC%E3%83%83%E3%83%88%E3%83%BB%E3%83%9F%E3%83%AC%E3%83%BC"&gt;John Everett Millais&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;あぁそれにしてもお美しい……巷では&lt;a href="http://www.salvastyle.com/menu_pre_raphael/millais_ophelia.html"&gt;オフィーリアちゃん&lt;/a&gt;が有名だけど、やっぱり&lt;a href="http://www.asahi.com/millais/detail/gallery.html"&gt;マリアナさん&lt;/a&gt;のほうが綺麗だよ。絶対。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;余談&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;もともとの動機としては高解像度な絵画の壁紙が欲しくて、いろいろと探し回ったわけですが、どうも&lt;a href="http://www.googleartproject.com/"&gt;Google Art Project&lt;/a&gt;しか高解像度の絵画が載っていないので仕方なくといった次第です。&lt;/li&gt;
&lt;li&gt;利用はどうやら&lt;a href="http://www.google.com/accounts/TOS"&gt;Google's Terms of Service&lt;/a&gt;に準じているようです。ざっと見した感じだとダウンロードを禁止する条項はないですし著作権も切れているので全く問題ないように思えるんですが、もし警告とかきたらチキンですから遠慮無く取り下げます。ご了承ください。&lt;/li&gt;
&lt;li&gt;このネタを題材に時間があればHTMLのスクレイピング、パケット解析についての入門記事を書いてみたいです。&lt;/li&gt;
&lt;li&gt;なんだかんだ言ってちゃんと実物見たほうが綺麗。ミレイの作品は以前東京に行ったときに&lt;a href="http://www.bunkamura.co.jp/"&gt;Bunkamura&lt;/a&gt;で見ました。Bunkamuraはそういう催し物よくやっていて、そこらへんが東京羨ましかったり&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-3904743285554502443?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/KbsxH2Btdi0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/3904743285554502443/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=3904743285554502443" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3904743285554502443?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3904743285554502443?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/KbsxH2Btdi0/google-art-project.html" title="Google Art Projectを利用して高画質の絵画を手に入れる" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-4qxD3xZRxLQ/Tc_e0nb9jxI/AAAAAAAAA-g/kRjY7SnPsX0/s72-c/Vincent+van+Gogh+-+The+Starry+Night.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/05/google-art-project.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4ARn0-fyp7ImA9WhZQEUU.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-1612212843484164691</id><published>2011-04-19T01:28:00.001+09:00</published><updated>2011-04-19T12:49:07.357+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-19T12:49:07.357+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="haskell" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>並列環境におけるreduceとscanアルゴリズム</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Iqhqu6wF1FjcFcH7fVWLU55gMog/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Iqhqu6wF1FjcFcH7fVWLU55gMog/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Iqhqu6wF1FjcFcH7fVWLU55gMog/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Iqhqu6wF1FjcFcH7fVWLU55gMog/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-MEW_KtXY3Oo/Taxk9HVs47I/AAAAAAAAA9s/A8ejQkgK3wI/s1600/fireking.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-MEW_KtXY3Oo/Taxk9HVs47I/AAAAAAAAA9s/A8ejQkgK3wI/s1600/fireking.jpg" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px;" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;"&lt;a href="http://www.flickr.com/photos/cmyk1219/3064510251/"&gt;fireking&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/cmyk1219/"&gt;cmyk1219&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;1. 概要&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;と&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;はGPGPUなどの並列環境下において重要な役割を果たす関数だけど、あまりこれらの関数、特にscanについて言及している記事はあまり見かけない。なので今回は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;と&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;について調べた結果をまとめていきたいと思う。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;2. reduce, scan関数の概要&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;2.1. reduce&lt;/b&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;については&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;が分かればより理解しやすくなるので、ひとまずは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;から始めることにする。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;とは、端的に言うと、対象のリストを与えられた二項演算子で纏め上げる関数だ。とは言っても、いきなりそんなことを言われてもよく分からない。まずは例を見ていこう:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; import operator
&amp;gt;&amp;gt;&amp;gt; reduce(operator.add, [1, 2, 3, 4, 5])
15
&amp;gt;&amp;gt;&amp;gt; reduce(operator.sub, [1, 2, 3, 4, 5])
-13
&amp;gt;&amp;gt;&amp;gt; reduce(operator.mul, [1, 2, 3, 4, 5])
120&lt;/pre&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;において重要なのは二項演算子であり、上記の場合、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;は以下のような演算を行う。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;(((1 + 2) + 3) + 4) + 5 = 15
(((1 - 2) - 3) - 4) - 5 = -13
(((1 * 2) * 3) * 4) * 5 = 120&lt;/pre&gt;これにより、最初の演算は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;sum&lt;/span&gt;関数、3番目の関数は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;prod&lt;/span&gt;関数と等価であることが分かる。&lt;br /&gt;
リストの型は何も数値に限られている訳ではない:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; reduce(operator.and_, [True, False, True])
False
&amp;gt;&amp;gt;&amp;gt; reduce(operator.or_, [True, False, True])
True&lt;/pre&gt;これより、上記2つの演算は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;all&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;any&lt;/span&gt;関数と機能的に等価であることが分かるのだけれど、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;all&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;any&lt;/span&gt;関数のほうが効率的なので、実際はちゃんと&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;all&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;any&lt;/span&gt;関数を使うべきだ。&lt;br /&gt;
&lt;br /&gt;
他にも&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を用いて様々な関数、アルゴリズムを記述できるが、あまりにも多いので今回は後回しにして、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;を重点的に解説していく。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2.2. scan&lt;/b&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;関数は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;と比べて文献が少ない。言及している文章もあまり見かけないが、並列処理において&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;は重要な関数だ。残念ながらpythonで実装されていないけれど、仮に実装されていたとしたら以下のような働きをする:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; scan(operator.add, [1, 2, 3, 4, 5])
[1, 3, 6, 10, 15]
&amp;gt;&amp;gt;&amp;gt; scan(operator.sub, [1, 2, 3, 4, 5])
[1, -1, -4, -8, -13]
&amp;gt;&amp;gt;&amp;gt; scan(operator.mul, [1, 2, 3, 4, 5])
[1, 2, 6, 24, 120]&lt;/pre&gt;きちんと書き下せばどのような働きをしているのか分かりやすい:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;[1, 1+2, (1+2)+3, ((1+2)+3)+4, (((1+2)+3)+4)+5]&lt;/pre&gt;結局のところ、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;は先頭から&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;していった結果をリストにまとめ、それを返す関数となる。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;は別名&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;prefix sum&lt;/span&gt;とも呼ばれている。&lt;br /&gt;
ちなみに、haskellでは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scanl1(scanl)&lt;/span&gt;という名前で実装されている。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;Prelude&amp;gt; :type scanl1
scanl1 :: (a -&amp;gt; a -&amp;gt; a) -&amp;gt; [a] -&amp;gt; [a]
Prelude&amp;gt; scanl1 (+) [1,2,3,4,5]
[1,3,6,10,15]&lt;/pre&gt;また、&lt;a href="http://www.nvidia.co.jp/object/cuda_home_new_jp.html"&gt;CUDA&lt;/a&gt;ライブラリである&lt;a href="http://code.google.com/p/thrust/"&gt;thrust&lt;/a&gt;には&lt;a href="http://thrust.googlecode.com/svn/tags/1.1.0/doc/html/group__prefixsums.html"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;inclusive_scan&lt;/span&gt;(&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;exclusive_scan&lt;/span&gt;)&lt;/a&gt;という名前で実装されている。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#include &amp;lt;thrust/scan.h&amp;gt;
int data[6] = {1, 0, 2, 2, 1, 3};
thrust::inclusive_scan(data, data + 6, data); // in-place scan
// data is now {1, 1, 3, 5, 6, 9}&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;3. 並列による制限&lt;/span&gt;&lt;br /&gt;
何故並列下において&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;が重要になってくるのか、それは、両方ともメニーコアな環境において効率的に動作するアルゴリズムが複数提唱されているからだ。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;,&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;は並列と相性がいい。つまり、既存のアルゴリズムをどうにかして&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;,&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;に落とし込むことができれば、並列化の恩恵を受けれられると。&lt;br /&gt;
&lt;br /&gt;
ただし、並列環境においては、演算にいくつかの制限が生じてくる。具体的には、集合Gと演算子"・"の組において、&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;演算子"・"は交換則"a・b = b・a"を満たしていなければならない&lt;/li&gt;
&lt;li&gt;演算子"・"は結合則"(a・b)・c = a・(b・c)"を満たしていなければならない&lt;/li&gt;
&lt;/ul&gt;後者に関してはあたり前の話で、これが成り立っていなければ並列に計算を行うことができない。前者については多少曖昧で、実際には満たさなくてもよいアルゴリズムも作ることはできるけど、コアレッシングなどの問題を考えると満たしていることが強く求められる。実際、thrustの&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;は交換則を満たしていることを前提としている。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;の場合はこの2つの制限で十分だけれど、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;の場合は上記2つの制限に加えてさらに2つの制限を満たしておくと都合がいい。具体的には、集合Gと演算子"・"の組において、&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;ただ一つの単位元"e"が存在する&lt;/li&gt;
&lt;li&gt;演算子"・"は任意の元"a"に対して"a・a&lt;sup&gt;-1 =&amp;nbsp;&lt;/sup&gt;a&lt;sup&gt;-1&lt;/sup&gt;・a = e"を満たす、ただ一つの逆元"a&lt;sup&gt;-1&lt;/sup&gt;"が存在する&lt;/li&gt;
&lt;/ul&gt;これら4つの制限を満たしている集合Gと演算子"・"の組を『&lt;b&gt;&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%BC%E3%83%99%E3%83%AB%E7%BE%A4"&gt;アーベル群&lt;/a&gt;&lt;/b&gt;』という。要するに、scan関数は、対象の型から成る集合と二項演算子の組がアーベル群を成していれば都合がいいということになる。&lt;br /&gt;
&lt;br /&gt;
具体例を出そう。整数と和の組&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(Integer, (+))&lt;/span&gt;は明らかに上記4つの制限を満たす。よって、この組は並列に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;オペレーションを適用でき、かつ都合が良い。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;1 + 2 == 2 + 1
(1 + 2) + 3 == 1 + (2 + 3)
1 + (-1) == (-1) + 1 == 0&lt;/pre&gt;&lt;br /&gt;
真偽値と論理積の組&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(Bool, (&amp;amp;&amp;amp;))&lt;/span&gt;は上記2つの制限を満たすため並列に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;,&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;オペレーションを実行可能だが、後半2つの制限は満たしていないため都合は良くない。&lt;br /&gt;
&lt;br /&gt;
3次元の回転行列と積の組&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(Matrix, (*))&lt;/span&gt;は交換則を満たしていないため―少なくともthrustでは―並列に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce, scan&lt;/span&gt;オペレーションを実行することはできない。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;3.1. 都合が良いとは？&lt;/b&gt;&lt;br /&gt;
とは言っても、一体アーベル群であればどこがどう都合がいいのか？それは、リスト中において局所的に&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を行いたい場合に役に立つ。&lt;br /&gt;
&lt;br /&gt;
リスト&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[a&lt;sub&gt;0&lt;/sub&gt;, ... , a&lt;sub&gt;n&lt;/sub&gt;]&lt;/span&gt;にscanオペレーションを実行して&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%26%26%20%7B%5Crm%20scan%7D%5C;%5C;(%5Coplus)%5C;%5C;[a_0,%20%5Ccdots%20,%20a_n]%20%5C%5C%0A%26%26%20%3D%20[a_0,%20a_0%20%5Coplus%20a_1,%20%5Ccdots%20,%20a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_n]%20%5C%5C%0A%26%26%20%5Cequiv%20[b_0,%20%5Ccdots,%20b_n]"&gt;&lt;img src="http://formula.s21g.com/?%26%26%20%7B%5Crm%20scan%7D%5C;%5C;(%5Coplus)%5C;%5C;[a_0,%20%5Ccdots%20,%20a_n]%20%5C%5C%0A%26%26%20%3D%20[a_0,%20a_0%20%5Coplus%20a_1,%20%5Ccdots%20,%20a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_n]%20%5C%5C%0A%26%26%20%5Cequiv%20[b_0,%20%5Ccdots,%20b_n].png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;/span&gt;を手に入れたとする。この場合、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;i &amp;lt; j&lt;/span&gt;において&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;b&lt;sub&gt;j&lt;/sub&gt;+b&lt;sub&gt;i&lt;/sub&gt;&lt;sup&gt;-1&lt;/sup&gt;&lt;/span&gt;を計算すると、&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%26%26%20b_j%20%5Coplus%20b_i%5E%7B-1%7D%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5Coplus%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_i)%5E%7B-1%7D%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5Coplus%20(a_i%5E%7B-1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_0%5E%7B-1%7D)%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20a_0%5E%7B-1%7D)%20%5Coplus%20%5Ccdots%20%5Coplus%20(a_i%20%5Coplus%20a_i%5E%7B-1%7D)%20%5Coplus%20(a_%7Bi+1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5C%5C%0A%26%26%20%3D%20a_%7Bi+1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j"&gt;&lt;img src="http://formula.s21g.com/?%26%26%20b_j%20%5Coplus%20b_i%5E%7B-1%7D%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5Coplus%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_i)%5E%7B-1%7D%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5Coplus%20(a_i%5E%7B-1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_0%5E%7B-1%7D)%20%5C%5C%0A%26%26%20%3D%20(a_0%20%5Coplus%20a_0%5E%7B-1%7D)%20%5Coplus%20%5Ccdots%20%5Coplus%20(a_i%20%5Coplus%20a_i%5E%7B-1%7D)%20%5Coplus%20(a_%7Bi+1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j)%20%5C%5C%0A%26%26%20%3D%20a_%7Bi+1%7D%20%5Coplus%20%5Ccdots%20%5Coplus%20a_j.png" /&gt;&lt;/a&gt;&lt;br /&gt;
となる。つまり、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;i+1&lt;/span&gt;から&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;j&lt;/span&gt;までの要素についての&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;reduce&lt;/span&gt;を僅か&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;O(1)&lt;/span&gt;で求めることができる。&lt;br /&gt;
&lt;br /&gt;
これには大きな利点がある。例えば、大規模な時系列データを、その周りのデータから平均化(平滑化)したいとする。各要素ごとに計算を行うのは明らかに非効率であるので、まず&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;オペレーションを&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(+)&lt;/span&gt;に対して適用し、その後で差分を計算し、正規化を行ってやればよい。結局、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan (+)&lt;/span&gt;のやっていることはf(x)の不定積分F(x)を求めることと本質的に等価となる。この考え方はCVでは、&lt;a href="http://www.kec.jp/committee/johoshi/pdf/jyohoshi_210-3.pdf"&gt;積分画像&lt;/a&gt;として様々な箇所で用いられる。&lt;br /&gt;
&lt;br /&gt;
そしてさらに、この操作はアーベル群であれば何でも良い……とは言っても、アーベル群であることは結構厳しい制限となる。&lt;br /&gt;
&lt;br /&gt;
例を出すと、リスト中の任意の範囲ーiからjの成分がすべてある条件式に適合しているかどうか確かめたいとする。&lt;br /&gt;
関数型の考え方だと、まずは&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;map&lt;/span&gt;関数を用いて(C++でなら&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;a href="http://www.boost.org/doc/libs/1_35_0/libs/iterator/doc/transform_iterator.html"&gt;transform_iterator&lt;/a&gt;&lt;/span&gt;を用いて)リストの成分を&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Bool&lt;/span&gt;に変え、その後で&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;を利用することを思いつくかもしれない。しかし、残念ながら&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(Bool, (&amp;amp;&amp;amp;))&lt;/span&gt;はアーベル群でないので、そのまま愚直に適用することができない。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;Prelude&amp;gt; scanl1 (&amp;amp;&amp;amp;) $ map (&amp;lt;3) [1,2,3,2,1]
[True,True,False,False,False]
-- 最後の2要素については条件を満たしているのに、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;False&lt;/span&gt;で埋もれてしまって分からない！
&lt;/pre&gt;この場合は、単純にアーベル群である&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(Integer, (+))&lt;/span&gt;を&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;scan&lt;/span&gt;に適用してやればよい。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;Prelude&amp;gt; scanl1 (+) $ map (\x-&amp;gt;if x&amp;lt;3 then 1 else 0) [1,2,3,2,1]
[1,2,2,3,4]
-- きちんと第3要素のみ条件から外れていることが分かる
&lt;/pre&gt;Pythonっぽく書くとたぶんこんな感じ:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; import operator
&amp;gt;&amp;gt;&amp;gt; f = lambda x: 1 if x &amp;lt; 3 else 0
&amp;gt;&amp;gt;&amp;gt; scan(operator.add, [f(x) for x in [1,2,3,2,1]])
&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;4. より詳しく知りたい方は&lt;/span&gt;&lt;br /&gt;
scanアルゴリズムのGPGPU実装に関する詳細については、現在のところ『&lt;a href="http://developer.download.nvidia.com/compute/cuda/1_1/Website/projects/scan/doc/scan.pdf"&gt;Parallel Prefix Sum (Scan) with CUDA(Mark Harris, NVIDIA)&lt;/a&gt;』が一番分かりやすい。より詳しく知りたい方はそちらをどうぞ。&lt;br /&gt;
&lt;br /&gt;
というより、基本NVIDIAの出しているテキストは分かりやすい。すごいことです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-1612212843484164691?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/BIWq-E_M3m8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/1612212843484164691/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=1612212843484164691" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/1612212843484164691?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/1612212843484164691?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/BIWq-E_M3m8/reducescan.html" title="並列環境におけるreduceとscanアルゴリズム" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-MEW_KtXY3Oo/Taxk9HVs47I/AAAAAAAAA9s/A8ejQkgK3wI/s72-c/fireking.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/04/reducescan.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAGR3w9fCp7ImA9WhZSFUo.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-3558874644010750760</id><published>2011-03-31T19:17:00.004+09:00</published><updated>2011-03-31T22:22:06.264+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-31T22:22:06.264+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="思うこと" /><title>Moving</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/R8ErmvOfPHAJJF5I0jPkBSbJn1M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/R8ErmvOfPHAJJF5I0jPkBSbJn1M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/R8ErmvOfPHAJJF5I0jPkBSbJn1M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/R8ErmvOfPHAJJF5I0jPkBSbJn1M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-u8-nN8JKFac/TZQ7YuQ7C0I/AAAAAAAAA9o/Tq_kv37Jr_A/s1600/moving.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-u8-nN8JKFac/TZQ7YuQ7C0I/AAAAAAAAA9o/Tq_kv37Jr_A/s1600/moving.jpg" style="background:none; border:0;" /&gt;&lt;/a&gt;&lt;/div&gt;本当は4/1に書く予定でしたが、そういえば4/1はエイプリルフールでしたので今日書きます。&lt;br /&gt;
&lt;br /&gt;
えーと、本日、&lt;a href="http://www.phys.tohoku.ac.jp/"&gt;東北大学理学部物理学科&lt;/a&gt;を卒業し、明日から&lt;a href="http://www.is.tohoku.ac.jp/"&gt;東北大学大学院情報科学研究科&lt;/a&gt;に入学します。所属する研究室はコンピュータビジョンなど、主に視覚的な情報について研究している研究室ですので、たぶんこれから書く記事はそれ系統の内容が多くなると思います。このブログのタイトルに少し近づきました。&lt;br /&gt;
&lt;br /&gt;
元々このブログは映像を作り、その技術的な情報についてログを残せるよう立ち上げたブログでした。確かに現在は映像の「え」の字もないブログに仕上がっていますが、もちろん今でも映像は好きですし、好きなプロダクションさんの映像はいつも観に行くようにしています。そして全く役に立たなかったかと言われればそういうわけではなくて、個人的に仕事を頼まれることもありましたし、Webサイトや印刷物のデザインをする際にも役立ちましたし、ここで得た知見のお陰で様々な方とお話することもできました。&lt;br /&gt;
&lt;br /&gt;
物理学科に入ったのも元々は相対論や量子力学の深遠な世界について知りたいために入りました。正直に言って完全に理解できたかというと怪しいところでありますし、理学から工学という他分野に移るわけで、一見すると今までの知識が役立たなくなるように見えます。が、実はそうでもなく、統計力学(*1)や相対論で使っている手法をコンピュータビジョンに輸入している論文があったり、案外様々な場面で役立ったりしているわけで(*2)。&lt;br /&gt;
&lt;br /&gt;
全然違う領域に見えても絡んでくる領域というものは少なからずあるものです。ということで、映像と物理がお互いに絡み合っている、コンピュータビジョンの道に進むことを決めました。&lt;br /&gt;
&lt;br /&gt;
これからもどうぞよろしくお願いします。&lt;br /&gt;
&lt;br /&gt;
p.s. 家族は無事でした、よかったよかった&lt;br /&gt;
&lt;br /&gt;
*1 ここで宣伝ですが、田崎先生の『&lt;a href="http://www.gakushuin.ac.jp/~881791/statbook/"&gt;統計力学I, II&lt;/a&gt;』はお薦めです。この本はぜひ理学系だけでなく工学系の方々にも読んでもらいたい本です。値段も2冊併せて7,000円くらいと安い。新品のゲームソフト1本買うくらいならこれを買いましょう&lt;br /&gt;
*2 もちろん線形代数や基本的な偏微分も数式や概念を学んだりする上で役立ちました。一番学んで良かったのはブラケット記法とヒルベルト空間、あれは素晴らしい&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-3558874644010750760?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/i31fnlt5Erg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/3558874644010750760/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=3558874644010750760" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3558874644010750760?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3558874644010750760?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/i31fnlt5Erg/moving.html" title="Moving" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-u8-nN8JKFac/TZQ7YuQ7C0I/AAAAAAAAA9o/Tq_kv37Jr_A/s72-c/moving.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/03/moving.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQCSHczfCp7ImA9Wx9aGEk.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8404045610306988711</id><published>2011-03-11T20:51:00.001+09:00</published><updated>2011-03-11T20:52:49.984+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-11T20:52:49.984+09:00</app:edited><title>自分は無事です</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-E3DliAFR_ZAyRrlKgyWlSDfntM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-E3DliAFR_ZAyRrlKgyWlSDfntM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-E3DliAFR_ZAyRrlKgyWlSDfntM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-E3DliAFR_ZAyRrlKgyWlSDfntM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;自分は出張で京都にいましたので、無事です。もし身内の方が見ていましたらご安心ください。&lt;br /&gt;
ただ暫くは京都に滞在することになると思います。早く交通機関が復旧してほしいです。&lt;br /&gt;
&lt;br /&gt;
ただ家族がどうなっているのか全く分からない。怖いです、不安です。&lt;br /&gt;
&lt;br /&gt;
[文句]&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;iPhoneではSoftbankの災害用伝言ダイヤルに『登録できない』！！！&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;/span&gt;明らかにsoftbank側の怠慢、糞だ。糞すぎる&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8404045610306988711?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/kenruMEQQoA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8404045610306988711/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8404045610306988711" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8404045610306988711?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8404045610306988711?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/kenruMEQQoA/blog-post.html" title="自分は無事です" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/03/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8AQns7eyp7ImA9Wx9UF0Q.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-4978435918952051073</id><published>2011-02-16T02:22:00.001+09:00</published><updated>2011-02-16T02:27:23.503+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-16T02:27:23.503+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OMake" /><title>OMakeのContributionsに載ったった</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PGyxJPCH-Q2euBZdKpLy5bmHbPU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PGyxJPCH-Q2euBZdKpLy5bmHbPU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PGyxJPCH-Q2euBZdKpLy5bmHbPU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PGyxJPCH-Q2euBZdKpLy5bmHbPU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-V_SRKuybluc/TVqyjKnJEAI/AAAAAAAAA9Q/_sgbJR-Ku8s/s1600/screenshot.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-V_SRKuybluc/TVqyjKnJEAI/AAAAAAAAA9Q/_sgbJR-Ku8s/s1600/screenshot.jpg" style="background: none; border: 0;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;&lt;a href="http://omake.metaprl.org/contribs.html"&gt;The OMake build system: User Contributions&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style="text-align: center;"&gt;やったね！&lt;/div&gt;&lt;br /&gt;
余談&lt;br /&gt;
翻訳をすることは勉強にもなって非常にいいですし皆さんにもぜひやって欲しいのですが、&lt;br /&gt;
その分、なんというか、日本の中へと篭ってしまうことにも繋がっている気がします。&lt;br /&gt;
&lt;br /&gt;
英語に臆することなく積極的にアウトプットできるよう、自分自身の心構えをもう少しきちんとしなければならんですね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-4978435918952051073?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/GxSiskhfrrs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/4978435918952051073/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=4978435918952051073" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/4978435918952051073?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/4978435918952051073?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/GxSiskhfrrs/omakecontributions.html" title="OMakeのContributionsに載ったった" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-V_SRKuybluc/TVqyjKnJEAI/AAAAAAAAA9Q/_sgbJR-Ku8s/s72-c/screenshot.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/02/omakecontributions.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIEQXY-eSp7ImA9WhZSFUs.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8434402719664994307</id><published>2011-02-15T03:54:00.012+09:00</published><updated>2011-03-31T19:31:40.851+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-31T19:31:40.851+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>boost.GILで組む、ジェネリックな画像処理のアルゴリズム</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/afMf9q4Dr1jSVi5Sip7SZ-0tJq4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/afMf9q4Dr1jSVi5Sip7SZ-0tJq4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/afMf9q4Dr1jSVi5Sip7SZ-0tJq4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/afMf9q4Dr1jSVi5Sip7SZ-0tJq4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-g2BJr9YJaZQ/TVl5Zy6fYSI/AAAAAAAAA9I/k_CWYhBF3EY/s1600/human.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-g2BJr9YJaZQ/TVl5Zy6fYSI/AAAAAAAAA9I/k_CWYhBF3EY/s1600/human.jpg" style="background: none; border: 0;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/gelinh/3279386782/"&gt;Image dans le néant&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/gelinh/"&gt;gelinh&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://opensource.adobe.com/wiki/display/gil/Generic+Image+Library"&gt;boost.GIL&lt;/a&gt;は凄い！開発者の頭の良さがビシビシと伝わってくる！&lt;br /&gt;
ということで、今回はGILに関しての紹介記事を書こうと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;概要&lt;/span&gt;&lt;br /&gt;
あなたは画像処理のエキスパート。顧客の依頼で、8bitのRGB画像を処理するアルゴリズムを記述していたとします。ところが対象となるデバイスの仕様を調べていた際に、実はRGBA画像にも対応させなければいけないことが分かりました。面倒だと思いながら書いていた矢先、さらにBGRやABGR,さらには16や24bitにも対応したアルゴリズムを記述しなければならないことが判明しました。なんということでしょう…これらの画像すべてに対してアルゴリズムを書くなんて、とてもじゃないですがやってられない。&lt;i&gt;やめてくれ！&lt;/i&gt;って感じです。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/"&gt;boost&lt;/a&gt;に付いてくる&lt;a href="http://opensource.adobe.com/wiki/display/gil/Generic+Image+Library"&gt;GIL&lt;/a&gt;を用いることで、画像に対する操作をよりジェネリックに行うことが出来ます。具体的に言うと、あなたはGILの作法に従ってアルゴリズムを書き下すだけで、メモリに展開されている画像データの色空間、色深度、レイアウト、配置順に『&lt;b&gt;関わらず&lt;/b&gt;』、任意のデータ配置に対して適用できるアルゴリズムを作ることができるのです。最初に提示した問題が一気に解決しちゃいました。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;長所と短所&lt;/span&gt;&lt;br /&gt;
長所&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;画像処理に対してジェネリックなアルゴリズムを記述でき、少ない記述量で全てをカバーできる。処理速度も普通に書き下した場合と同等(静的なポリモーフィズムしか使っていないので、コンパイル時に必要な計算はすべて終わっている)。&lt;/li&gt;
&lt;li&gt;様々なアダプタが存在している(e.g. &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;subimage_view, rotated180_view&lt;/span&gt;)ので、ばんばん遅延評価して一気に処理を行うことが可能。&lt;/li&gt;
&lt;li&gt;普通の人が普通に書くよりも、GILのアルゴリズムに従って書いたほうが大抵の場合早い&lt;/li&gt;
&lt;li&gt;ソースコードが比較的読みやすい。コード量も短くなる。&lt;/li&gt;
&lt;li&gt;誰が作ったかわかんないもの利用したくねーという方も安心のAdobe製。画像処理の専門家が作ってるのでとても合理的。&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
短所&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;テンプレートを多用しており『&lt;b&gt;非常に難解&lt;/b&gt;』。&lt;/li&gt;
&lt;li&gt;全てを抽象化しているために『&lt;b&gt;非常に難解&lt;/b&gt;』。&lt;/li&gt;
&lt;li&gt;C++と画像処理の両方に秀でていなければ記述できないので、使っている人が殆どいない。&lt;/li&gt;
&lt;li&gt;英語のサイトですら文献が殆どない&lt;/li&gt;
&lt;/ul&gt;正直なところ、短所の部分がかなり厳しい。かなりC++をやりこんでいないと使えないということは、それだけでユーザ層を大分狭めます。仕方がないことですけど。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Viewの概要&lt;/span&gt;&lt;br /&gt;
GILでは、画像に対する操作はすべて『&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;』を起点にして行われます。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;は以下のような構造を持ち、ジェネリックな操作を行えるよう工夫してあります。&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;|-- Locator&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;| &amp;nbsp; &amp;nbsp;`-- Pixel&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;| &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; |-- Channel&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;| &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; `-- Layout&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;| &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|-- Color Space&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;| &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;`-- Channel Mapping&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;`-- dimensions&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;(&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;上図はMemory basedで、画素のメモリ配置がInterleavedな場合のView構造)&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
以下のリストで、それぞれの名称がどのような役割を持っているのか説明します。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;&lt;/b&gt;: (x, y)座標における画素値の他、特定のX、Y方向におけるイテレータや全ピクセルにわたって捜査できるxyイテレータなど、「様々な手法によって画素にアクセスできる手段」を提供する、一種の抽象的なクラスを表しています。画像の幅、高さを表す&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dimensions&lt;/span&gt;と、後述する&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Locator&lt;/span&gt;を持ちます。(注: 画像のデータを実際に保持している『わけではありません』。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;View&lt;/span&gt;はあくまで、対象の画素値へとアクセスするための『手段』を提供しているだけに過ぎないのです)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Locator&lt;/span&gt;&lt;/b&gt;: 画像の2次元的な『位置』を表します。ランダムアクセスイテレータの2次元版のようなものと考えれば理解が早いと思います。具体的に言いますと、&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;*loc&amp;nbsp;&lt;/span&gt;あるいは&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;*(loc + point2(dx, dy))&amp;nbsp;&lt;/span&gt;などで現在の画素値や(dx, dy)だけ離れた位置の画素値を取得することは出来ますが、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Locator&lt;/span&gt;の現在地(xy座標)や画像の大きさ(width, height)を取得することはできません。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Pixel&lt;/span&gt;&lt;/b&gt;: &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Locator&lt;/span&gt;によって返される画素値を表します。後述する&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Channel&lt;/span&gt;と&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Layout&lt;/span&gt;を持ちます。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Channel&lt;/span&gt;&lt;/b&gt;: 画素の色深度を表します(8bit, 16bit, etc…)。各型の取りうる最大値、最小値も取得できます。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Layout&lt;/span&gt;&lt;/b&gt;: 色空間のレイアウトを表します。ちょっと分かりにくいので、下の2つを読んだほうが早いでしょう。&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;Color Space&lt;/b&gt;&lt;/span&gt;&lt;b&gt;:&lt;/b&gt; 色空間を表します(e.g. RGB, CMYK, HSV, Gray, etc…)。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Channel Mapping&lt;/span&gt;&lt;/b&gt;: 実メモリ上での配置順を表します(e.g. RGB, BGR, etc…)。ただし、この情報はInterleave画像のみ用います(Planar画像だと配置順は関係ないため)。&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;アルゴリズムを用いて書いてみる&lt;/span&gt;&lt;br /&gt;
それでは実際にGILに付属しているアルゴリズムを用いて実際に書き下してみます。以下の2つのアルゴリズムを用いてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;boost::gil::transform_pixel(const View&amp;amp; src, const View&amp;amp; dst, F functor)&lt;/span&gt;&lt;br /&gt;
対象のピクセルを受け取って別のピクセルを返す関数を、全ピクセルに対して適用します。この関数は、画素値と出力値が1対1対応である場合に用います(e.g. 明度、コントラスト, レベル補正, トーンカーブ, etc...)。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;boost::gil::transform_pixel_positions(const View&amp;amp; src, const View&amp;amp; dst, F functor)&lt;/span&gt;&lt;br /&gt;
周囲のピクセルの値を元に結果となるピクセルを返す関数を、全ピクセルに対して適用します。transform_pixelとは、受け取る引数がロケータであるという点が異なっており、周囲の画素値を元に実際の出力値を求める場合に有効です(e.g. Blur, Sovel, Laplacian, etc...)。&lt;br /&gt;
&lt;br /&gt;
実際にやってみれば、どんな感じか分かるでしょう:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#include &amp;lt;boost/gil/gil_all.hpp&amp;gt;
#include &amp;lt;boost/gil/extension/io/jpeg_io.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

using namespace boost::gil;

struct change_brightness {
public:
    change_brightness(): weight_(1.0) {};
    explicit change_brightness(float weight): weight_(weight) {};

    template&amp;lt;typename Pixel&amp;gt;
    Pixel operator()(Pixel src) {
        typedef typename channel_type&amp;lt;Pixel&amp;gt;::type channel_type;
        Pixel dst;
        for(int c=0; c&amp;lt;num_channels&amp;lt;Pixel&amp;gt;::value; ++c) {
             dst[c] = cv::saturate_cast&amp;lt;channel_type&amp;gt;(
                     static_cast&amp;lt;float&amp;gt;(src[c] * weight_));
        }
        return dst;
    }
private:
    float weight_;
};

struct change_brightness_locator {
public:
    change_brightness_locator(): weight_(1.0) {};
    explicit change_brightness_locator(float weight): weight_(weight) {};

    template&amp;lt;typename Locator&amp;gt;
    typename Locator::value_type operator()(Locator loc) {
        typedef typename Locator::value_type pixel_type;
        typedef typename channel_type&amp;lt;Locator&amp;gt;::type channel_type;
        pixel_type src = loc(0, 0);
        pixel_type dst;
        for(int c=0; c&amp;lt;num_channels&amp;lt;Locator&amp;gt;::value; ++c) {
            dst[c] = cv::saturate_cast&amp;lt;channel_type&amp;gt;(
                    static_cast&amp;lt;float&amp;gt;(src[c]) * weight_);
        }
        return dst;
    }
private:
    float weight_;
};

template&amp;lt;typename Locator&amp;gt;
struct x_gradient_functor {
public:
    explicit x_gradient_functor(Locator loc)
    : left_(loc.cache_location(-1, 0)),
      right_(loc.cache_location(1, 0)) {};

    typename Locator::value_type operator()(Locator loc) {
        typedef typename Locator::value_type pixel_type;
        typedef typename channel_type&amp;lt;Locator&amp;gt;::type channel_type;
        pixel_type src_left = loc[left_];
        pixel_type src_right = loc[right_];
        pixel_type dst;
        for(int c=0; c&amp;lt;num_channels&amp;lt;Locator&amp;gt;::value; ++c)
            dst[c] = (src_left[c] - src_right[c])/2;
        return dst;
    }

private:
    typename Locator::cached_location_t left_;
    typename Locator::cached_location_t right_;
};

template &amp;lt;typename SrcView, typename DstView&amp;gt;
void x_gradient(const SrcView&amp;amp; src, const DstView&amp;amp; dst) {
    assert(src.dimensions() == dst.dimensions());
    transform_pixel_positions(
            subimage_view(src, 1, 0, src.width()-2, src.height()),
            subimage_view(dst, 1, 0, src.width()-2, src.height()),
            x_gradient_functor&amp;lt;typename SrcView::locator&amp;gt;(src.xy_at(0, 0)));
}

int main() {
    const char* filename = "lena.jpg";
    rgb8_image_t src_image;

    jpeg_read_image(filename, src_image);
    rgb8_image_t dst_image(src_image.dimensions());

    transform_pixels(
            const_view(src_image),
            view(dst_image),
            change_brightness(1.5));
    jpeg_write_view("result_normal.jpg", view(dst_image));

    transform_pixel_positions(
            const_view(src_image),
            view(dst_image),
            change_brightness_locator(2.0));
    jpeg_write_view("result_locator.jpg", view(dst_image));

    x_gradient(const_view(src_image), view(dst_image));
    jpeg_write_view("result_gradient.jpg", view(dst_image));

    return 0;
}
&lt;/pre&gt;&lt;br /&gt;
また、画像の出力例を下記に示します:&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ptcBO7aC7h8/TVqoHbEs-pI/AAAAAAAAA9M/BDcVqGbBZhU/s1600/out.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="100" src="http://3.bp.blogspot.com/-ptcBO7aC7h8/TVqoHbEs-pI/AAAAAAAAA9M/BDcVqGbBZhU/s400/out.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;左から、元画像, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;change_brightness, change_brightness_locator, x_gradient&lt;/span&gt;の結果&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;change_brightness_locator()&lt;/span&gt;については、&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;for_each_pixel&lt;/span&gt;用のアルゴリズムをlocatorを用いて適用させた場合にどうなるか確認するためだけに実装しましたので、実務的ではありません。また、値を型の持つ最大、最小値に丸めるために&lt;a href="http://opencv.jp/"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;OpenCV&lt;/span&gt;&lt;/a&gt;の&lt;a href="http://opencv.jp/opencv-2svn/cpp/operations_on_arrays.html?#saturate_cast"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cv::saturate_cast&lt;/span&gt;&lt;/a&gt;を使用しています。&lt;br /&gt;
&lt;br /&gt;
main()についてはどんなことをやってるのか大体感覚的に理解できるはずですので、とりあえず3つのファンクタに関して説明を加えていきます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;typedef typename channel_type&amp;lt;Pixel&amp;gt;::type channel_type;&lt;/pre&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;channel_type&amp;lt;T&amp;gt;::type&lt;/span&gt;で実際に使われているチャネルの型を取得できます。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;T&lt;/span&gt;にはピクセル、ロケータ、ビューのどれを指定しても構いません。今回の場合ですと8bitのチャネルを指定しているので、型には&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;unsigned char&lt;/span&gt;が入ります。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;num_channels&amp;lt;Pixel&amp;gt;::value&lt;/pre&gt;ピクセルを構成しているチャネルの数を取得できます。この場合ですと色空間がRGBなので値には3が入ります。この値はコンパイル時に決定されるので、最適化を用いることでループ展開が行われ、速度的なオーバーヘッドはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;typedef typename Locator::value_type pixel_type;&lt;/pre&gt;ロケータが返すピクセルの型を取得できます。この場合ですと&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;rgb8_pixel_t&lt;/span&gt;が入ります。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;pixel_type src = loc(0, 0);&lt;/pre&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;()&lt;/span&gt;演算子によって現在のピクセル値を取得しています。他にも&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;*&lt;/span&gt;演算子でイテレータっぽくアクセスすることもできます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;explicit x_gradient_functor(Locator loc)
    : left_(loc.cache_location(-1, 0)),
      right_(loc.cache_location(1, 0)) {};&lt;/pre&gt;ロケータの変動値をキャッシュしておくことで、高速化を図ります。&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Locator::cached_location_t&lt;/span&gt;によってロケータのキャッシュ型を取得します。キャッシュを使ったアクセスには[]演算子を用います。&lt;br /&gt;
仰々しく言っていますが、要は&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;std::ptrdiff_t&lt;/span&gt;みたいなものです。移動する値は同じなんだから記憶しておきましょうということです。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;subimage_view(src, 1, 0, src.width()-2, src.height())&lt;/pre&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;subimage_view()&lt;/span&gt;によって画像の領域を切り出しています。これはアダプタで、実際の評価は遅延的に行われます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;まとめ&lt;/span&gt;&lt;br /&gt;
大体こんな感じでアルゴリズムを組んでいくのがGIL流です。遅延評価とアルゴリズムを武器に、ジェネリックなアルゴリズムを作っていきましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;余談&lt;/span&gt;&lt;br /&gt;
C++に関しての記事を投稿するのは正直に言って『少々怖い』です。大筋では合っていると思いますが、完全に合っているという自信があまりないからです。ですが、GILに関しては本当に、本当に参考となる文献が少ない。サンプルコードも多くない。こういった中でこの記事が少しでも参考程度になっていただければ幸いです。&lt;br /&gt;
&lt;br /&gt;
それと、ざっくり組んでしまったのでこうしたほうがいいよとか、間違い等あれば遠慮なく言ってもらえると助かります。&lt;br /&gt;
&lt;br /&gt;
(2/16) 追記: ソースコード若干の修正、説明や画像例の追加。&lt;br /&gt;
(3/31) typo: e.q. -&gt; e.g.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8434402719664994307?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/0gNMpdrg2WY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8434402719664994307/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8434402719664994307" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8434402719664994307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8434402719664994307?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/0gNMpdrg2WY/boostgil.html" title="boost.GILで組む、ジェネリックな画像処理のアルゴリズム" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-g2BJr9YJaZQ/TVl5Zy6fYSI/AAAAAAAAA9I/k_CWYhBF3EY/s72-c/human.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2011/02/boostgil.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08GSXkyeip7ImA9WhZTGEs.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-862477428900033842</id><published>2010-12-18T18:25:00.010+09:00</published><updated>2011-03-23T16:37:08.792+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-23T16:37:08.792+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>画像をぼかす: いろんなボケ、リアルなボケ</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/gPInvYrM3xoME8_woSthDCXJ8TM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gPInvYrM3xoME8_woSthDCXJ8TM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/gPInvYrM3xoME8_woSthDCXJ8TM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gPInvYrM3xoME8_woSthDCXJ8TM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;『&lt;i&gt;画像をぼかす&lt;/i&gt;』と一口に言っても、その方法にはいろんなものがあります。一番有名なのはPhotoshopの『ガウスぼかし』に見られるような&lt;a href="http://en.wikipedia.org/wiki/Gaussian_blur"&gt;Gaussian Blur&lt;/a&gt;ですが、残念ながらこれはカメラに見られるようなリアルなぼかしと比べるとどうしても見劣りします。原因はいくつか考えられて、一つはGaussian Blurに使われているガウス関数の勾配が穏やかなため、現実のレンズのシチュエーションを考慮していないという点があります。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;それじゃあ勾配を急にした関数ー&lt;i&gt;例えば&lt;a href="http://en.wikipedia.org/wiki/Fermi%E2%80%93Dirac_statistics"&gt;フェルミ分布関数&lt;/a&gt;のような&lt;/i&gt;ーをカーネルに採用すれば良いのかというとそういうわけではありません。有名な&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%8A_%28%E7%94%BB%E5%83%8F%E3%83%87%E3%83%BC%E3%82%BF%29"&gt;Lena画像&lt;/a&gt;で試してみましょう。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8ZDtm3iI/AAAAAAAAA8M/k3gJHypmpCw/s1600/lena_normal_thumb.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="132" src="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8ZDtm3iI/AAAAAAAAA8M/k3gJHypmpCw/s400/lena_normal_thumb.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;左が元画像、中央がカーネルにガウス関数を用いた画像、右がフェルミ分布関数を用いた画像。&lt;br /&gt;
確かに中央よりは綺麗だけど、それでもまだリアルとは言えない&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;それじゃあ他に何が違うのでしょう？端的に言うと、&lt;b&gt;黒も白も等価に扱って平均してしまうのがマズい&lt;/b&gt;。&lt;br /&gt;
&lt;br /&gt;
画像をぼかすという行為は要は畳込み積分で、周囲のピクセル値を特定のウェイトで平均してやってることになります。で、普通にブラーしてしまうとピクセルの輝度に関わらず常に一定の割合で平均してしまいますので、なんか濁ったような画像が生成されてしまうと。&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TQo8gQg8MII/AAAAAAAAA8Q/7VNK9GKk-Cg/s1600/lena_normalblur.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TQo8gQg8MII/AAAAAAAAA8Q/7VNK9GKk-Cg/s400/lena_normalblur.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;通常のブラー。カーネルにはよりリアルに見せるため正六角形を用いている&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;それではどのようなアプローチを用いればいいのでしょうか？レンズブラーを観察してみると、明るい箇所が強調されてぼかされていることが分かります。言い換えると、輝度の高いピクセルが優先的に混合されている、つまり予めRGBの全ピクセル値を適当な単調増加関数で写像してから畳込み積分を行って、その後対応する逆関数で戻してやればいい。要は&lt;a href="http://www.hirax.net/dekirukana5/bokeboke1/"&gt;hirax.net&lt;/a&gt;とやっていることは同じで、expしてからボカしてlogすると、こういうわけです。&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_8d0SChK7UaQ/TQo8kFITdlI/AAAAAAAAA8U/To5sxAaKFEw/s1600/lena_realblur.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/_8d0SChK7UaQ/TQo8kFITdlI/AAAAAAAAA8U/To5sxAaKFEw/s400/lena_realblur.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;結果の画像。比較的リアルにボカされていることが分かる&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8rtUUORI/AAAAAAAAA8c/Vfzu_19f0JY/s1600/lena_thumb.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="131" src="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8rtUUORI/AAAAAAAAA8c/Vfzu_19f0JY/s400/lena_thumb.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;並べてみれば、違いがはっきり(クリックで拡大)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Lenaさんだけでは少し分かりづらいので、適当な背景写真に適用してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_8d0SChK7UaQ/TQo8oDEhYSI/AAAAAAAAA8Y/uYLsehDl0TE/s1600/forest.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="266" src="http://4.bp.blogspot.com/_8d0SChK7UaQ/TQo8oDEhYSI/AAAAAAAAA8Y/uYLsehDl0TE/s400/forest.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;森林画像&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;まず、通常の手法でぼかしてしまうとどうなるでしょう？&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8u9sEFjI/AAAAAAAAA8g/ix9IDOV4iDs/s1600/forest_normalblur.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="266" src="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8u9sEFjI/AAAAAAAAA8g/ix9IDOV4iDs/s400/forest_normalblur.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;森林画像(通常のブラー)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;お世辞にも綺麗なボケとは言えません。それじゃあ今回の手法でぼかしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8d0SChK7UaQ/TQo8wrz-cTI/AAAAAAAAA8k/PIG8oWjdd1M/s1600/forest_realblur.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="266" src="http://3.bp.blogspot.com/_8d0SChK7UaQ/TQo8wrz-cTI/AAAAAAAAA8k/PIG8oWjdd1M/s400/forest_realblur.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;森林画像(リアルブラー)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;なんということでしょう…&lt;/b&gt;リアルなボケ画像ができました。&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TQo8yVpA_WI/AAAAAAAAA8o/4QbsgHZW3oc/s1600/forest_thumb.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="88" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TQo8yVpA_WI/AAAAAAAAA8o/4QbsgHZW3oc/s400/forest_thumb.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;比較画像(クリックで拡大)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;今回組んだOpenCVのソースコードを下記に示します。2.2でコンパイルしましたが、多分2.0以上だったら普通に通ると思います。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;
#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/core/operations.hpp&amp;gt;

struct exp_each_element
{
public:
    exp_each_element(float factor): factor_(factor/256.0){};
    cv::Vec3f operator()(cv::Vec3b &amp;amp;color) {
        return cv::Vec3f(
                std::exp(static_cast&amp;lt;float&amp;gt;(color[0])*factor_),
                std::exp(static_cast&amp;lt;float&amp;gt;(color[1])*factor_),
                std::exp(static_cast&amp;lt;float&amp;gt;(color[2])*factor_));
    }
private:
    const float factor_;
};

struct log_each_element
{
public:
    log_each_element(float factor): factor_(factor/256.0){};
    cv::Vec3b operator()(cv::Vec3f &amp;amp;color) {
        return cv::Vec3b(
                cv::saturate_cast&amp;lt;uchar&amp;gt;(std::log(color[0])/factor_),
                cv::saturate_cast&amp;lt;uchar&amp;gt;(std::log(color[1])/factor_),
                cv::saturate_cast&amp;lt;uchar&amp;gt;(std::log(color[2])/factor_));
    }
private:
    const float factor_;
};

cv::Mat make_fermi_kernel(float radius, float range) {
    const int size = static_cast&amp;lt;int&amp;gt;(2.0*range + radius)*2 + 5;
    const float mu = static_cast&amp;lt;float&amp;gt;(size/2);
    const float range_inversed = 1.0 / range;
    cv::Mat dst(size, size, CV_32F);
    for(int i=0; i&amp;lt;size; ++i) {
        for(int j=0; j&amp;lt;size; ++j) {
            const float u = static_cast&amp;lt;float&amp;gt;(i - mu);
            const float v = static_cast&amp;lt;float&amp;gt;(j - mu);
            const float r = std::sqrt(u*u + v*v);
            dst.at&amp;lt;float&amp;gt;(i, j) =
                    1.0/(std::exp(range_inversed*(r - radius)) + 1.0);
        }
    }
    cv::normalize(dst, dst, 1.0, 0, CV_L1);
    return dst;
}

cv::Mat make_regular_polygon_kernel(int number, float radius) {
    const int size = static_cast&amp;lt;int&amp;gt;(2.0*radius) + 1;
    const float center = static_cast&amp;lt;float&amp;gt;(size)/2.0;
    std::vector&amp;lt;cv::Point&amp;gt; dst_vector;
    for(int i=0; i&amp;lt;number; ++i) {
        const float theta = 2.0*M_PI*i/number;
        const cv::Point point = cv::Point(
                center + radius*std::cos(theta),
                center + radius*std::sin(theta));
        dst_vector.push_back(point);
    }
    cv::Mat dst(size, size, CV_32F);
    const cv::Scalar color(1.0, 1.0, 1.0, 1.0);
    cv::fillConvexPoly(dst, &amp;amp;dst_vector[0], number, color);
    cv::normalize(dst, dst, 1.0, 0, CV_L1);
    return dst;
}

int main(int argc, char** argv) {
    const std::string source = argc &amp;gt;= 2 ? argv[1] : "lena_std.tif";
    const std::string destination = argc &amp;gt;= 3 ? argv[2] : "out.jpg";
    const float factor = 6.0;

    cv::Mat image = cv::imread(source);
    CV_Assert(image.type() == CV_8UC3);
    cv::Mat kernel = make_regular_polygon_kernel(6, 8.0);

    cv::Mat exp_image(image.size(), CV_32FC3);
    std::transform(image.begin&amp;lt;cv::Vec3b&amp;gt;(), image.end&amp;lt;cv::Vec3b&amp;gt;(),
            exp_image.begin&amp;lt;cv::Vec3f&amp;gt;(), exp_each_element(factor));

    cv::filter2D(exp_image, exp_image, -1, kernel);

    std::transform(exp_image.begin&amp;lt;cv::Vec3f&amp;gt;(), exp_image.end&amp;lt;cv::Vec3f&amp;gt;(),
            image.begin&amp;lt;cv::Vec3b&amp;gt;(), log_each_element(factor));

    cv::imwrite(destination, image);
    return 0;
}
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;余談&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;実質80行くらいで完成したので嬉しいです。可読性も多分結構読みやすい部類だと思う&lt;/li&gt;
&lt;li&gt;C++のコードが何やってるか分からない方は、まず関数オブジェクトとSTLについて調べてみましょう。あれはいいもんです&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;追記(11/03/23)&lt;/b&gt;&lt;br /&gt;
&lt;blockquote&gt;どんなデバイスであるか、たとえば、それが入力デバイスであるのか、出力でバイスであるのか、はたまた、計算処理デバイスであるのか次第で「輝度値の単位系」をどのように保持（処理）するべきかは違うことでしょう。&lt;br /&gt;
大切なことは、取り扱う「値」がどんな単位であるのかを見失わないことなのか、と思います。&amp;nbsp;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;&lt;a href="http://hirax.net/techlog/2011/03/06.html"&gt;hirax.net::「コンピュータ画像処理」と「輝度値の単位系」&lt;/a&gt;&lt;/span&gt;&amp;nbsp;&lt;/blockquote&gt;自分がこのような『任意の単調増加関数で良い』という具合で筆を進めたのには2つ理由があります。&lt;br /&gt;
&lt;br /&gt;
まず1つ目が、『&lt;b&gt;全てのデジタルカメラにおいて、ピクセルは輝度の対数の次元を取っているのだろうか？&lt;/b&gt;』という単純な疑問です。&lt;br /&gt;
&lt;br /&gt;
きちんと物理的/工学的な意味合いを持つ画像処理にするためには、格納されているピクセルデータの次元がきちんと揃えられている必要があります。自分自身も普通に考えて輝度の対数が格納されているんだろうということで、任意ではなく指数関数に制限された関数系を使いましょうと運びたかったのですが、そうするための証拠が不足していた。&lt;br /&gt;
&lt;br /&gt;
もしかしたら自分の予想もつかない方法で処理されている可能性があるわけで、そういった証拠が十分にないことから、単調増加関数と少し曖昧とした意味合いを含ませたのです。&lt;br /&gt;
&lt;br /&gt;
もう一つの理由は『&lt;b&gt;今回の画像処理は物理的に正確である必要がない&lt;/b&gt;』という理由です。これが大きかった。&lt;br /&gt;
&lt;br /&gt;
そもそも今回の画像処理はどういう目的があるのでしょうか？ぼけて普通よりもリアルに見えて面白い、それで終わりです。物理的に計測をするわけではなく、ざっくり『それっぽく』見えればそれでいいという類のものです。そのような目的の下では、下手に物理的正確さを求めて処理時間を長くするよりは、計算速度の早いフェイクのほうがより適しています。&lt;br /&gt;
&lt;br /&gt;
だから何も指数関数に制限する理由はあまりないわけで、より早くてよりそれっぽく見えれば、そちらのほうが優れていると、そう言えるわけです(ただ、今回の計算量からすると最も大きなオーダーとなっているのは畳み込み積分の箇所で、単調増加関数自体のコストはそれに比べれば微々たるものでしょう)。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-862477428900033842?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/ZS5r9t9ahVg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/862477428900033842/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=862477428900033842" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/862477428900033842?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/862477428900033842?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/ZS5r9t9ahVg/blog-post.html" title="画像をぼかす: いろんなボケ、リアルなボケ" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_8d0SChK7UaQ/TQo8ZDtm3iI/AAAAAAAAA8M/k3gJHypmpCw/s72-c/lena_normal_thumb.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/12/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEACQHs_eyp7ImA9Wx5bEUw.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-3012840923102683992</id><published>2010-10-27T02:03:00.002+09:00</published><updated>2010-10-27T02:06:01.543+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-27T02:06:01.543+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OMake" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>OMakeマニュアル 日本語訳 PDFバージョンをリリースしました</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/noiHcb1TslB0g0dqV2n7JYIvv_k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/noiHcb1TslB0g0dqV2n7JYIvv_k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/noiHcb1TslB0g0dqV2n7JYIvv_k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/noiHcb1TslB0g0dqV2n7JYIvv_k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TMcFWuRs3hI/AAAAAAAAA8I/duIQ3VhIQEs/s1600/cute.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TMcFWuRs3hI/AAAAAAAAA8I/duIQ3VhIQEs/s1600/cute.jpg" style="background: none; border: 0;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/clickflashphotos/3440590766/"&gt;Aint they cute?&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/clickflashphotos/"&gt;Nicki Varkevisser&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
題名の通りで、以前から取り組んでおりました『&lt;a href="http://omake-japanese.sourceforge.jp/"&gt;OMakeマニュアル 日本語訳&lt;/a&gt;』の全ページを一つに纏めたPDFバージョンをリリースしました。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://omake-japanese.sourceforge.jp/OMake.pdf"&gt;http://omake-japanese.sourceforge.jp/OMake.pdf&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
よりダウンロードできます。電子書籍でまとめてご覧になりたい方や、職場などの環境で使いたいけれどネットが使えないのでごりごり印刷したい…といった場合に便利です。&lt;br /&gt;
&lt;br /&gt;
元々は&lt;a href="http://www.shibu.jp/"&gt;渋川さん&lt;/a&gt;の『&lt;a href="http://sphinx-users.jp/cookbook/pdf/latex.html"&gt;LaTeX経由でのPDF作成&lt;/a&gt;』という記事を拝見しまして、試験的にPDF版を作成してみたところ、思いのほか綺麗に製本されていることからきちんとリリースしてみようと思い立った次第です。殆ど素の状態から手を加えていないので暫定的ですが、後はきちんとスタイルを組んでいって、もうちょっと読みやすいレイアウトにしていけばいいかなって感じです。&lt;br /&gt;
&lt;br /&gt;
思えば個人的な暇潰しから始まったこのプロジェクトも現在はPDFにして約200ページにもなり、きちんと一つの事柄に集中して取り組めたことは、学部時代のいい経験になったと考えています。まあ、これからも暇があればちょくちょくレイアウト、文章含めて修正していきますので、どうぞ今後ともよろしくお願いします。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-3012840923102683992?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/6mFojoFM8eI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/3012840923102683992/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=3012840923102683992" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3012840923102683992?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3012840923102683992?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/6mFojoFM8eI/omake-pdf.html" title="OMakeマニュアル 日本語訳 PDFバージョンをリリースしました" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/TMcFWuRs3hI/AAAAAAAAA8I/duIQ3VhIQEs/s72-c/cute.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/10/omake-pdf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUNRn85fCp7ImA9Wx5VEUo.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-7406054387089197894</id><published>2010-10-04T01:58:00.004+09:00</published><updated>2010-10-04T16:28:17.124+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-04T16:28:17.124+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="経済" /><category scheme="http://www.blogger.com/atom/ns#" term="金融工学" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>確率微分方程式を解くー幾何ブラウン運動、バシチェックモデルの場合</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0ENYVBEfr9lTxFFqNxZfm6sR6go/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0ENYVBEfr9lTxFFqNxZfm6sR6go/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0ENYVBEfr9lTxFFqNxZfm6sR6go/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0ENYVBEfr9lTxFFqNxZfm6sR6go/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8d0SChK7UaQ/TKhEp1fC13I/AAAAAAAAA7w/UKFyxZk-BXM/s1600/New+York+Fashion+Week+Fall+2007.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8d0SChK7UaQ/TKhEp1fC13I/AAAAAAAAA7w/UKFyxZk-BXM/s1600/New+York+Fashion+Week+Fall+2007.jpg" style="background: none; border: 0;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/artcomments/382733093/"&gt;New York Fashion Week Fall 2007: Doo Ri&lt;/a&gt;" by&amp;nbsp;&lt;a href="http://www.flickr.com/photos/artcomments/"&gt;Art Comments&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
確率微分方程式という分野がある。どういうものかっていうと、要は確率過程を微分方程式によって表そうという試みであり、微分方程式の中に微小の確率変数が含まれている。具体的にはこんな感じ。&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%3D%20a(x,%20t)%7B%5Crm%20d%7Dt%20+%20b(x,%20t)%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%3D%20a(x,%20t)%7B%5Crm%20d%7Dt%20+%20b(x,%20t)%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
このdWはブラウン運動を表していて、時間がたつにつれてうねうねと確率的に動く。期待値と標準偏差はそれぞれ0と√tで、時間がたつにつれて動く場所もどんどん広がっていく。この運動はランダムウオークとか酔歩とも呼ばれていて、酔っ払ったおっさんがうねうねとあちこちに歩いているように見えることからこういう名前がついたそうな。上のような式で表すことができる確率過程を一般には『伊藤過程』と言って、他にもストラトノビッチ確率解析とかいうのもあるらしいけど、詳しくやっていないので分かりません。&lt;br /&gt;
&lt;br /&gt;
これの何が便利かっていうと確率過程を通常の微分方程式のように扱えるところで、確率変数をまるで微分方程式を解くかのように求めることができる。とは言っても通常の微分方程式にはない規則がいくつかあって、初めはすごく奇妙に思えるかもしれない。&lt;br /&gt;
&lt;br /&gt;
具体的には、以下のように確率変数x(t)とy(t)を定めた場合、&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%26%3D%26%20a(x,%20t)%7B%5Crm%20d%7Dt%20+%20b(x,%20t)%7B%5Crm%20d%7DW_t%5C%5C%0Ay(t)%20%26%3D%26%20g(x,%20t)"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%26%3D%26%20a(x,%20t)%7B%5Crm%20d%7Dt%20+%20b(x,%20t)%7B%5Crm%20d%7DW_t%5C%5C%0Ay(t)%20%26%3D%26%20g(x,%20t).png" /&gt;&lt;/a&gt;&lt;br /&gt;
このy(t)もまた伊藤過程に従い、確率微分方程式dyは以下のルールに従う。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dy(t)%20%26%3D%26%20%5Cfrac%7B%5Cpartial%20g%7D%7B%5Cpartial%20t%7D%7B%5Crm%20d%7Dt%20+%20%5Cfrac%7B%5Cpartial%20g%7D%7B%5Cpartial%20x%7D%7B%5Crm%20d%7Dx%20+%20%5Cfrac%7B1%7D%7B2%7D%5Cfrac%7B%5Cpartial%5E2%20g%7D%7B%5Cpartial%20x%5E2%7D(%7B%5Crm%20d%7Dx)%5E2"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dy(t)%20%26%3D%26%20%5Cfrac%7B%5Cpartial%20g%7D%7B%5Cpartial%20t%7D%7B%5Crm%20d%7Dt%20+%20%5Cfrac%7B%5Cpartial%20g%7D%7B%5Cpartial%20x%7D%7B%5Crm%20d%7Dx%20+%20%5Cfrac%7B1%7D%7B2%7D%5Cfrac%7B%5Cpartial%5E2%20g%7D%7B%5Cpartial%20x%5E2%7D(%7B%5Crm%20d%7Dx)%5E2.png" /&gt;&lt;/a&gt;&lt;br /&gt;
普通だったら消えるはずの2乗の項が残ってしまう。それじゃあ(dx)^2はどのようにして計算するのかというと、以下の公式に従う。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?(%7B%5Crm%20d%7Dt)%5E2%20%26%3D%26%20%7B%5Crm%20d%7Dt%7B%5Crm%20d%7DW_t%20%3D%20%7B%5Crm%20d%7DW_t%20%7B%5Crm%20d%7Dt%20%3D%200%20%5C%5C%0A(%7B%5Crm%20d%7DW_t)%5E2%20%26%3D%26%20%7B%5Crm%20d%7Dt"&gt;&lt;img src="http://formula.s21g.com/?(%7B%5Crm%20d%7Dt)%5E2%20%26%3D%26%20%7B%5Crm%20d%7Dt%7B%5Crm%20d%7DW_t%20%3D%20%7B%5Crm%20d%7DW_t%20%7B%5Crm%20d%7Dt%20%3D%200%20%5C%5C%0A(%7B%5Crm%20d%7DW_t)%5E2%20%26%3D%26%20%7B%5Crm%20d%7Dt.png" /&gt;&lt;/a&gt;&lt;br /&gt;
なんと、(dW)^2がdtに変化してしまう！これを『伊藤の公式』という。なんでそうなるのか？それを知りたい方は専門書を漁ればいくらでも載っているので、そこらへんを参照すればいいと思う。ここが通常の微分方程式と違うところで、逆を言えばそこさえ守ればきちんと積分によって求めることができる。専門書だとこの箇所がすごく分かり辛い表現で説明されているけど、詳細をはしょればこんな感じなはず。&lt;br /&gt;
&lt;br /&gt;
それじゃあ、まず手始めに&lt;a href="http://ja.wikipedia.org/wiki/%E7%A2%BA%E7%8E%87%E5%BE%AE%E5%88%86%E6%96%B9%E7%A8%8B%E5%BC%8F"&gt;幾何ブラウン運動&lt;/a&gt;と呼ばれるモデル&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%3D%20%5Cmu%20x(t)%20%7B%5Crm%20d%7Dt%20+%20%5Csigma%20x(t)%20%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dx(t)%20%3D%20%5Cmu%20x(t)%20%7B%5Crm%20d%7Dt%20+%20%5Csigma%20x(t)%20%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
を求めてみる。これは株価の変動を表す最も簡単なモデルなんだけど、何故これが株価の変動を表しているのかっていうのは、とりあえず解いてみれば判明するはず。&lt;br /&gt;
&lt;br /&gt;
さて、普通の考えだったら『変数分離法を用いてxを分離させて、そのまま積分すればよくね？』って発想になるんだけど、何度も言っているようにこれは確率微分方程式なので、まずは伊藤の補題を用いて変数変換を行い、xを分離させてみることにする。y = ln(x)とおくと、伊藤の補題より&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dy%20%26%3D%26%20%5Cfrac%7B1%7D%7Bx%7D%7B%5Crm%20d%7Dx%20-%20%5Cfrac%7B1%7D%7B2x%5E2%7D%20(%7B%5Crm%20d%7Dx)%5E2%5C%5C%0A%20%26%3D%26%20%5Cfrac%7B1%7D%7Bx%7D(%5Cmu%20x%20%7B%5Crm%20d%7Dt%20+%20%5Csigma%20x%20%7B%5Crm%20d%7DW_t)%20-%20%5Cfrac%7B1%7D%7B2x%5E2%7D(%5Csigma%5E2%20x%5E2%20%7B%5Crm%20d%7Dt)%5C%5C%0A%20%26%3D%26%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)%7B%5Crm%20d%7Dt%20+%20%5Csigma%20%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dy%20%26%3D%26%20%5Cfrac%7B1%7D%7Bx%7D%7B%5Crm%20d%7Dx%20-%20%5Cfrac%7B1%7D%7B2x%5E2%7D%20(%7B%5Crm%20d%7Dx)%5E2%5C%5C%0A%20%26%3D%26%20%5Cfrac%7B1%7D%7Bx%7D(%5Cmu%20x%20%7B%5Crm%20d%7Dt%20+%20%5Csigma%20x%20%7B%5Crm%20d%7DW_t)%20-%20%5Cfrac%7B1%7D%7B2x%5E2%7D(%5Csigma%5E2%20x%5E2%20%7B%5Crm%20d%7Dt)%5C%5C%0A%20%26%3D%26%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)%7B%5Crm%20d%7Dt%20+%20%5Csigma%20%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
となる。(-1/2 σ^2)の項が出てくるところがミソで、普通に変数変換してしまうと出現しない。これで定数部分だけに分離できたので、そのまま愚直に積分を行うと、&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?y(t)%20%26%3D%26%20y(0)%20+%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)t%20+%20%5Csigma%20W(t)%20%5C%5C%0Ax(t)%20%26%3D%26%20x(0)%5Cexp%5Cleft(%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)t%20+%20%5Csigma%20W(t)%20%5Cright)"&gt;&lt;img src="http://formula.s21g.com/?y(t)%20%26%3D%26%20y(0)%20+%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)t%20+%20%5Csigma%20W(t)%20%5C%5C%0Ax(t)%20%26%3D%26%20x(0)%5Cexp%5Cleft(%20(%5Cmu%20-%20%5Cfrac%7B1%7D%7B2%7D%5Csigma%5E2)t%20+%20%5Csigma%20W(t)%20%5Cright).png" /&gt;&lt;/a&gt;&lt;br /&gt;
となる。これは対数正規分布の形となっているため、株価の変動を表す簡単なモデルとなっていることは容易に理解できると思う。&lt;br /&gt;
&lt;br /&gt;
それでは、次に&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%90%E3%82%B7%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%BB%E3%83%A2%E3%83%87%E3%83%AB"&gt;Vasicekモデル&lt;/a&gt;と呼ばれるモデル&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dr(t)%20%3D%20a(b-r(t))%7B%5Crm%20d%7Dt%20+%20%5Csigma%20%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dr(t)%20%3D%20a(b-r(t))%7B%5Crm%20d%7Dt%20+%20%5Csigma%20%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
について求めてみる。これは主に国債金利の利子率の時間的変動を表すモデルで、いったいこいつの何が重要なんじゃいっていうと、金融商品のリスクを推定する際に使われる。金融商品の価格は利子率によって変動するので、利子率の変動を推定することは金融商品のリスクを推定することに繋がる(*1)。つまり、今の自分のポートフォリオがどれくらいのリスクを持っているのか判断できる。そもそもこの記事を書くきっかけになったのはこいつが原因で、wikipediaさんにはただ『積分するとこれになりますよ』って書いてあるだけで、どうやって積分するのかについては書いていなかった。しょうがないので自分で手を動かして、ようやっと理解できたので公開してみようと。&lt;br /&gt;
&lt;br /&gt;
さて、まずはu=b-rとおいて変数変換すると、&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Du%20%26%3D%26%20-%7B%5Crm%20d%7Dr%20%5C%5C%0A%26%3D%26%20-au%20%7B%5Crm%20d%7Dt%20-%20%5Csigma%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Du%20%26%3D%26%20-%7B%5Crm%20d%7Dr%20%5C%5C%0A%26%3D%26%20-au%20%7B%5Crm%20d%7Dt%20-%20%5Csigma%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
となる。ただ普通にChain Ruleやってるように見えるけど、たまたま結果が同じだっただけで、どんな変数変換でもきちんと伊藤の補題を使わなきゃいけない。そんで、物理やってる人はピンとくるかもしれないけど、これは&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%82%B8%E3%83%A5%E3%83%90%E3%83%B3%E6%96%B9%E7%A8%8B%E5%BC%8F"&gt;ランジュバン方程式&lt;/a&gt;の形となっているので、積分には同様の手法を利用できる。まぁ自分はピンとこなかったんですけど。それはさておき、v=e^(at)uとおいてさらに変数変換してやると、&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%7B%5Crm%20d%7Dv%20%26%3D%26%20ae%5E%7Bat%7Du%20%7B%5Crm%20d%7Dt%20+%20e%5E%7Bat%7D%7B%5Crm%20d%7Du%5C%5C%0A%26%3D%26%20ae%5E%7Bat%7Du%20%7B%5Crm%20d%7Dt%20+%20e%5E%7Bat%7D(-au%7B%5Crm%20d%7Dt%20-%20%5Csigma%7B%5Crm%20d%7DW_t)%5C%5C%0A%26%3D%26%20-%5Csigma%20e%5E%7Bat%7D%7B%5Crm%20d%7DW_t"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20d%7Dv%20%26%3D%26%20ae%5E%7Bat%7Du%20%7B%5Crm%20d%7Dt%20+%20e%5E%7Bat%7D%7B%5Crm%20d%7Du%5C%5C%0A%26%3D%26%20ae%5E%7Bat%7Du%20%7B%5Crm%20d%7Dt%20+%20e%5E%7Bat%7D(-au%7B%5Crm%20d%7Dt%20-%20%5Csigma%7B%5Crm%20d%7DW_t)%5C%5C%0A%26%3D%26%20-%5Csigma%20e%5E%7Bat%7D%7B%5Crm%20d%7DW_t.png" /&gt;&lt;/a&gt;&lt;br /&gt;
となり、いい感じに余計な項が消えてブラウン運動だけになった。よってこれを積分してやると&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?v(t)%20%26%3D%26%20v(0)%20-%20%5Csigma%20%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s%5C%5C%0A%26%3D%26%20b%20-%20r(0)%20-%20%5Csigma%20%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s%0A"&gt;&lt;img src="http://formula.s21g.com/?v(t)%20%26%3D%26%20v(0)%20-%20%5Csigma%20%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s%5C%5C%0A%26%3D%26%20b%20-%20r(0)%20-%20%5Csigma%20%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s%0A.png" /&gt;&lt;/a&gt;&lt;br /&gt;
あとはごちゃごちゃ整理してやると&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?r(t)%20%3D%20r(0)e%5E%7B-at%7D%20+%20b(1-e%5E%7B-at%7D)%20+%20%5Csigma%20e%5E%7B-at%7D%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s"&gt;&lt;img src="http://formula.s21g.com/?r(t)%20%3D%20r(0)e%5E%7B-at%7D%20+%20b(1-e%5E%7B-at%7D)%20+%20%5Csigma%20e%5E%7B-at%7D%5Cint_%7B0%7D%5E%7Bt%7De%5E%7Bas%7D%7B%5Crm%20d%7DW_s.png" /&gt;&lt;/a&gt;&lt;br /&gt;
これで&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%90%E3%82%B7%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%BB%E3%83%A2%E3%83%87%E3%83%AB"&gt;wikipediaさんにあるのとおんなじ形&lt;/a&gt;になった。めでたしめでたし。&lt;br /&gt;
&lt;br /&gt;
なんかブログに書くと導出するのは楽ちんなように思えるけど、結構悩んだし大変だった。どんなもんでも答えを見るとすぐ分かるし思いつきそうなんだけど、実際になにもない地点から思いつくかどうかっていうのはまた別な話で、それを考えると新しい学問を生み出すっていうのは凄まじいほどの労力が必要だ。実際、未だにどういう発想で量子力学を思いついたのか本気で理解できない。あんなのヒントがいくらあっても無理だ。そういうことを考えた一日でありましたとさ。&lt;br /&gt;
&lt;br /&gt;
*1: もちろんこの説明は適当でないが、詳しく説明してもあんまり意味がないのでこう書くことにする&lt;br /&gt;
&lt;br /&gt;
追記(2010/10/04)&lt;br /&gt;
1/2の項が抜けていたので修正。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-7406054387089197894?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/_rQS2HQRZ9I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/7406054387089197894/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=7406054387089197894" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7406054387089197894?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7406054387089197894?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/_rQS2HQRZ9I/blog-post.html" title="確率微分方程式を解くー幾何ブラウン運動、バシチェックモデルの場合" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_8d0SChK7UaQ/TKhEp1fC13I/AAAAAAAAA7w/UKFyxZk-BXM/s72-c/New+York+Fashion+Week+Fall+2007.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/10/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMQH0-fCp7ImA9Wx5WFks.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-3831543263862392538</id><published>2010-09-28T18:31:00.002+09:00</published><updated>2010-09-28T18:33:01.354+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-28T18:33:01.354+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>マルコフ連鎖モンテカルロ法を実装してみよう</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OaH6STRyWkMbfS_njjd6Q8ZOTI8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OaH6STRyWkMbfS_njjd6Q8ZOTI8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OaH6STRyWkMbfS_njjd6Q8ZOTI8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OaH6STRyWkMbfS_njjd6Q8ZOTI8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TKC-_SyGgrI/AAAAAAAAA7o/IqSgFdwJX68/s1600/chain.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TKC-_SyGgrI/AAAAAAAAA7o/IqSgFdwJX68/s1600/chain.jpg" style="background:none; border:0" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/pedrosz/3642296149/"&gt;Chain Bridge, Budapest&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/pedrosz/"&gt;szeke&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
約2ヶ月ぶりということで、ご無沙汰しております。書きたいネタというのは結構あって書こう書こうとは思っているんですが、なにより書くとなるとあれもこれも伝えなきゃいけないみたいな思いになって、結局分量の多さから諦めてしまうというのが結構続いています。もう少し気を張らずに更新していきたいものです。&lt;br /&gt;
&lt;br /&gt;
さて、最近の自分はマルコフ連鎖モンテカルロ法(Markov Chain Monte Carlo, MCMC)についておりました。何にも知らない方ににとってはよく分からないかもしれませんが、この手法はマルコフ連鎖が持つ簡明さとモンテカルロ法が持つ実用性が合わさった凄まじい手法なんです。そしてなによりとてもエレガント。&lt;br /&gt;
&lt;br /&gt;
とりあえず知らない人のためにてきとーに解説しますと、与えられた適当な関数から確率変数をサンプリングするための公式です。べつにこれじゃなくても確率変数のサンプリングにはいろんなアルゴリズムがあるわけですが、これを使うと関数の計算コストがやけに高い場合だとか、ピーク部分を集中的にサンプリングしてくれたりとかで結構便利で、金融や工学、物理の分野でも非常に役立っております。計算物理をやる人にとっては必須に近い手法といっても過言ではありません。&lt;br /&gt;
&lt;br /&gt;
そんなMCMCですが、実際に提案されている手法には様々なものがあります。不変分布から遷移確率を逆算するため、自由度が増えるから遷移確率は一意じゃなくなってしまうんです。今回は最も有名なMetropolis-Hastingsアルゴリズム(*1)を用いて、任意の関数に従って乱数のサンプリングを行うコードを練習がてらpythonで書いてみました。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import math
import random

def main():
   f = lambda x: math.exp(-x*x / 10.0)
   for x, fx in metropolis(f):
       print x, fx

def metropolis(func, start=0.0, delta=2.0, burn_in=100, seed=1):
   metro_iter = _metropolis(func, start, delta, seed)
   for i, value in enumerate(metro_iter):
       if i &amp;gt; burn_in:
           yield value
           break
   for value in metro_iter:
       yield value

def _metropolis(func, start, delta, seed):
   random.seed(seed)
   initial_x = start
   initial_fx = func(initial_x)
   proposed_x, proposed_fx = 0.0, 0.0
   while True:
       proposed_x = initial_x + random.uniform(-delta, delta)
       proposed_fx = func(proposed_x)
       ratio = proposed_fx / initial_fx
       if ratio &amp;gt; 1.0 or ratio &amp;gt; random.random():
           initial_x, initial_fx = proposed_x, proposed_fx
           yield proposed_x, proposed_fx
       else:
           yield initial_x, initial_fx

if __name__ == '__main__':
   sys.exit(main())
&lt;/pre&gt;うーん・・・きれいだ(*2)・・・&lt;br /&gt;
&lt;br /&gt;
こいつのすごいところは、アルゴリズム自体は非常にシンプルで実装しやすいというところにあります。行数も上を見ると分かるのですがとっても少ないし、コア部分はたった25行くらいで構成されています。&lt;br /&gt;
&lt;br /&gt;
なのに使っている学問は結構複雑で、定常分布から遷移行列を導出するために詳細釣り合いの条件からMetropolis的制約を用いて導出、サンプリングを行っております。このアルゴリズム自体は結構知ってる人が多いかもしれませんが、実際に理論方面で理解している人はどうなんでしょう。&lt;br /&gt;
&lt;br /&gt;
んで、正規分布のガウス関数からサンプリングを行った結果がこれ。 &lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TKDD23Xa_OI/AAAAAAAAA7s/tf5xOJedbWo/s1600/test.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TKDD23Xa_OI/AAAAAAAAA7s/tf5xOJedbWo/s1600/test.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
赤線が元の確率分布。きちんとサンプリングが行われているようです。今回は正規分布で計算を行いましたが、非負の関数であればなんでも構いません。&lt;br /&gt;
&lt;br /&gt;
あとはこれを研究テーマへと落とし込むことができれば、とりあえず一区切りつけるかなって感じです。&lt;br /&gt;
&lt;br /&gt;
*1: 提案確率関数が対称であるという制約を持つのがMetropolis。それを非対称の場合にも拡張したのがHastings。個人的にはMetropolis-HastingよりMetropolisのほうが綺麗で好きです。というか提案確率密度関数が非対称じゃないといけないようなシチュエーションがよく分からない&lt;br /&gt;
*2: yieldとジェネレータって便利ですよね。計算速度も効率的だし、慣れてくるとすべて遅延評価で行わせたいくらい&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-3831543263862392538?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/0P0ZrdK7eK4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/3831543263862392538/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=3831543263862392538" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3831543263862392538?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/3831543263862392538?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/0P0ZrdK7eK4/blog-post_28.html" title="マルコフ連鎖モンテカルロ法を実装してみよう" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/TKC-_SyGgrI/AAAAAAAAA7o/IqSgFdwJX68/s72-c/chain.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/09/blog-post_28.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYNSXw-eSp7ImA9Wx5RFEQ.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-4125815332567138742</id><published>2010-07-23T01:49:00.009+09:00</published><updated>2010-08-23T01:23:18.251+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-23T01:23:18.251+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="金融工学" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>ドルコスト平均法は賢い投資方法と言えるのか？ 補足</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wzfbtkwTU0ItPWNWqIiTp-zGIT8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wzfbtkwTU0ItPWNWqIiTp-zGIT8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wzfbtkwTU0ItPWNWqIiTp-zGIT8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wzfbtkwTU0ItPWNWqIiTp-zGIT8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8d0SChK7UaQ/TEh17No3q-I/AAAAAAAAA6U/DMnCP7qYCJg/s1600/capitalism.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_8d0SChK7UaQ/TEh17No3q-I/AAAAAAAAA6U/DMnCP7qYCJg/s1600/capitalism.jpg" style="background: none repeat scroll 0% 0% transparent; border: 0pt none;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/wnorrix/262600004/"&gt;Pyramid of Capitalism&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/wnorrix/"&gt;Warren Noronha&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://mglab.blogspot.com/2010/05/part1.html"&gt;ドルコスト平均法は賢い投資方法と言えるのか？ part1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mglab.blogspot.com/2010/05/part2.html"&gt;ドルコスト平均法ははたして賢い投資方法と言えるのか？ part2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
以前ブログの記事を読んでいただいた友人から感想を伺うと、「&lt;i&gt;なんかよく分からない&lt;/i&gt;」といった感想が帰ってきました。基本的に説明が不足しているなぁと思った箇所は実際いくつもあって、金融の確率論を少しでもやると大体感覚的に理解できるのですが、普通の人はそんなのやらないのが当たり前ですので、基本的な概念について少し説明したいと思います。この分野に興味ない人でもちょこちょこと面白そうな話を挟んでいくので、暇つぶしに見てやってください。&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;1. 確率変数、期待値、分散&lt;/h4&gt;&lt;b&gt;確率変数というのは試行によって出てくる値が確率的に異なってくる変数のこと&lt;/b&gt;です。これは抽象的なので、もうすこし具体的にいきましょう。例えば、以下のコイントスゲームを考えます。最初あなたは1万円を所持していたとして、表であれば所持金が2倍となり、一方で裏であれば所持金が0.5倍、つまり半分になります。このような試行を3回行ったとして、最終的な資金額をXと表すと、このゲームは以下の式で表せます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?X%20%3D%2010000%20%5Ctimes%20X_1X_2X_3"&gt;&lt;img src="http://formula.s21g.com/?X%20%3D%2010000%20%5Ctimes%20X_1X_2X_3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ここでのX&lt;sub&gt;1&lt;/sub&gt;はそれぞれの試行の確率変数に相当し、50%の確率で0.5, 50%の確率で2.0の値をとります。&lt;br /&gt;
で、これだけではただ定式化しただけで、何にも面白いことは分かりません。ですが&lt;b&gt;こいつの期待値と分散を求めてやることで、このゲームは得なのか損なのか、またどれくらいのリスクがあるゲームなのか調べてやることができる&lt;/b&gt;のです。&lt;br /&gt;
&lt;br /&gt;
例えば、Xの期待値をE[X]としてやりましょう。ここで、期待値の性質として以下を確認しておきましょう。まず、XとYが確率変数とすると、その和の期待値は単純にそれぞれの期待値の和で表せます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D[X%20+%20Y]%20%3D%20%7B%5Crm%20E%7D[X]%20+%20%7B%5Crm%20E%7D[Y]"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D[X%20+%20Y]%20%3D%20%7B%5Crm%20E%7D[X]%20+%20%7B%5Crm%20E%7D[Y].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
また、XとYが独立(それぞれの試行がもう一方の試行に影響を及ぼさない)であるとすると、その積も同じような性質を持ちます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D[XY]%20%3D%20%7B%5Crm%20E%7D[X]%7B%5Crm%20E%7D[Y]"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D[XY]%20%3D%20%7B%5Crm%20E%7D[X]%7B%5Crm%20E%7D[Y].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
この性質を用いると、Xの期待値は以下のように表せます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D[X]%20%26%3D%26%2010000%20%5Ctimes%20%7B%5Crm%20E%7D[X_1]%7B%5Crm%20E%7D[X_2]%7B%5Crm%20E%7D[X_3]%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%26%3D%26%2010000%20%5Ctimes%201.25%5E3%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%26%3D%26%2019531.25"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D[X]%20%26%3D%26%2010000%20%5Ctimes%20%7B%5Crm%20E%7D[X_1]%7B%5Crm%20E%7D[X_2]%7B%5Crm%20E%7D[X_3]%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%26%3D%26%2010000%20%5Ctimes%201.25%5E3%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%26%3D%26%2019531.25.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
つまり、このゲームを行うことによってあなたは9500円くらいの利益を得ることが期待できます。もうこれはやるっきゃないと。&lt;br /&gt;
&lt;br /&gt;
このゲームが得であることは理解できましたが、ただこのゲームにどれくらいリスクがあるのかは不透明です。期待値が10000円プラスになるからといって、40%の確率で全財産を失ってしまうみたいなゲームですと、普通は行いたくないですよね。このリスクについて求めるためには分散を計算してやればいいのですが、これはそれなりに面倒です(*1)。前回ごっちゃごっちゃやってたのはこの面倒さによるものが大半ですので、今回は説明しません。とりあえず分散がリスクに対応しているということが大事です。&lt;br /&gt;
&lt;br /&gt;
世の中の投資行動には常にリスクとリターンが付きまといます。一般的にリスクとリターンは紙一重と言われており、リスクの高い行動はよりリターンも大きいというのが感覚的な理解です。ただ、このリスクとリターンを確率変数を用いて計算することによって、どの行動が一番リスクとリターンのバランスが取れている行動であるのか、判断することができます。&lt;br /&gt;
&lt;br /&gt;
で、どの戦略を用いれば合理的に資産を増やすことができるのかという問題ですが、実はこの戦略は既に知られており、&lt;b&gt;ある戦略を用いればリスクをリターンに変化させることで指数関数的に資産を増やすことができます。&lt;/b&gt;その戦略について興味がある方は適当に調べると出てくると思います。&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;2. なぜ乗法モデルを仮定しているのか？&lt;/h4&gt;まず、株価の変動は確率的であるから確率変数として表せるという話は納得できると思います。では、株価などの資産モデルには様々なものがあるのに、なぜそれぞれの確率変数が独立と仮定した乗法モデル&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0"&gt;&lt;img src="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
をわざわざ採用するのでしょうか？別に、例えば&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?S_N%20%3D%20S_0%20+%20R_1%20+%20R_2%20+%20%5Ccdots%20+%20R_N"&gt;&lt;img src="http://formula.s21g.com/?S_N%20%3D%20S_0%20+%20R_1%20+%20R_2%20+%20%5Ccdots%20+%20R_N.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
のような加法モデルでも構わないわけです。何故なんでしょう？&lt;br /&gt;
&lt;br /&gt;
まず独立と仮定した理由については、単に計算が楽だからです。正直独立と仮定しないと、ここまで綺麗な形がでるのか、そもそも解析的に解けるのかどうかすら分かりません。ただこれを仮定したことによって、ごちゃごちゃ計算できて結果的にそれなりに綺麗な数式へと展開することができたという次第です。&lt;br /&gt;
&lt;br /&gt;
乗法モデルを仮定した理由については、&lt;b&gt;金融業界の指数関数的な性格&lt;/b&gt;によるものです。例えば、ローンなんかは年利15%ーフリーローンですとこんくらいでしょうかーとありますが、これは1年間につきローンが15%増加していくので、ふるまいとしては指数的になります。同様に、国債についても年利で計算するので指数的な計算となります。金利が低いといってほいほい借金をすると危険だという理由もこれによるものです。逆に、金持ちがより金持ちになる理由の一つでもあります。&lt;br /&gt;
&lt;br /&gt;
これは個人的な意見ですが、&lt;b&gt;金融の世界で乗法モデルが成り立っている理由は、人間が金に対して貧欲であるからだ&lt;/b&gt;と思っています。はっきりと言いますが、世の中の結構な割合の人間は指数的なふるまいを理解できません。ですからマイホームを数十年ローンでぽんと買ってしまったり、リボ払いで決済をしたりしてしまいます。&lt;br /&gt;
&lt;br /&gt;
ちなみに、これらの金額はすべて年金公式と呼ばれる公式で算出できます。1期間後に支払いを始め、n期間にわたって金額Aを支払う場合、金利をrとおくと借入額Pは&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?P%20%3D%20%5Cfrac%7BA%7D%7Br%7D%20%5Cleft[%201%20-%20%5Cfrac%7B1%7D%7B%281+r%29%5En%7D%20%5Cright]"&gt;&lt;img src="http://formula.s21g.com/?P%20%3D%20%5Cfrac%7BA%7D%7Br%7D%20%5Cleft[%201%20-%20%5Cfrac%7B1%7D%7B%281+r%29%5En%7D%20%5Cright].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
もしくは&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?A%20%3D%20%5Cfrac%7Br%281+r%29%5EnP%7D%7B%281+r%29%5En%20-%201%7D"&gt;&lt;img src="http://formula.s21g.com/?A%20%3D%20%5Cfrac%7Br%281+r%29%5EnP%7D%7B%281+r%29%5En%20-%201%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
と表せます。これはすごく役立つ公式なので、店員の言葉に騙されないでおくこともできるかもしれません。ついでに、ローンを借りて全額返した場合に損をする差額はnA-Pで計算できて、&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?nA%20-%20P%20%3D%20%5Cfrac%7B%281+r%29%5En%28nr-1%29+1%7D%7B%281+r%29%5En-1%7DP"&gt;&lt;img src="http://formula.s21g.com/?nA%20-%20P%20%3D%20%5Cfrac%7B%281+r%29%5En%28nr-1%29+1%7D%7B%281+r%29%5En-1%7DP.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となります。こういう情報ってあんまり表沙汰にならないんですけれど。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;追記(10/08/23)&lt;/b&gt;&lt;br /&gt;
上の式は正直汚いからどんな振る舞いをするのか感覚的に理解し辛いですけど、利率が少ない、つまりrが微小のときは (1+r)^n ～ 1 + nr で近似できますから損失額は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?nA-P%20%5Csimeq%20nrP"&gt;&lt;img src="http://formula.s21g.com/?nA-P%20%5Csimeq%20nrP.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となります。ですから利率が低いときは、分割回数をちょっと多くしても線形的な負担にかならない。確かに損失額が増えることは確かですけど、一括払いで生活に支障がでるよりは、3, 4回くらいローンで払うっていう選択肢もありなのかもしれません(*2)。&lt;br /&gt;
&lt;br /&gt;
*1: 1次元のising模型の解析解を求めたり、極座標のラプラシアン導出するのよりは面倒じゃない&lt;br /&gt;
*2: ただそこまでして本当に欲しいものかそれっていう疑問はありますし、30年ローンとかで家を購入するような場合には全く通用しません。そもそもこのご時勢に長期のローンを組むなんて狂気の沙汰です。狂っている。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-4125815332567138742?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/dX21F-8QEQ4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/4125815332567138742/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=4125815332567138742" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/4125815332567138742?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/4125815332567138742?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/dX21F-8QEQ4/blog-post.html" title="ドルコスト平均法は賢い投資方法と言えるのか？ 補足" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_8d0SChK7UaQ/TEh17No3q-I/AAAAAAAAA6U/DMnCP7qYCJg/s72-c/capitalism.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/07/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUAQn0yeyp7ImA9WxFWF0Q.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8926266817276170982</id><published>2010-06-05T14:32:00.009+09:00</published><updated>2010-06-06T12:50:43.393+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-06T12:50:43.393+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Motion Graphics" /><title>BLESS by Overture</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EjdNTHyko5iS3F79fnHMRsU2iic/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EjdNTHyko5iS3F79fnHMRsU2iic/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EjdNTHyko5iS3F79fnHMRsU2iic/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EjdNTHyko5iS3F79fnHMRsU2iic/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/TAnkBGFtN7I/AAAAAAAAA5Y/bgasOAcVH_g/s1600/bress.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/TAnkBGFtN7I/AAAAAAAAA5Y/bgasOAcVH_g/s1600/bress.jpg"  style="border:0; background:none;"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin: 0pt auto;"&gt;&lt;object height="326" width="580"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=9898397&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=9898397&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="580" height="326"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href="http://vimeo.com/9898397"&gt;BLESS&lt;/a&gt; from &lt;a href="http://vimeo.com/opertura"&gt;Overture&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;
&lt;a href="http://www.myspace.com/trallaladykirakira"&gt;KiraKira&lt;/a&gt;というアイスランドのミュージシャンの音楽PV。作ったのは&lt;a href="http://overture-image.blogspot.com/"&gt;Overture&lt;/a&gt;というアメリカのユニット。&lt;br /&gt;
&lt;br /&gt;
これの何が凄いのかっていうと、たった2人の夫婦によって作られたっていうところです。やった人は分かると思うんですが、アニメーション制作というのは本当に大変です。それを夫婦の共同作業でやっちゃってるところが仲良さそうで素敵。しかもその作品もとても個性溢れていて、気持ちがいいなぁと思う作品でした。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://overture-image.blogspot.com/"&gt;ブログ&lt;/a&gt;も良かったらごらんになってください。奥さんが日本人なので片方は日本語で書かれています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8926266817276170982?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/kaW_R0Us3U4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8926266817276170982/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8926266817276170982" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8926266817276170982?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8926266817276170982?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/kaW_R0Us3U4/bless-by-overture.html" title="BLESS by Overture" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/TAnkBGFtN7I/AAAAAAAAA5Y/bgasOAcVH_g/s72-c/bress.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/06/bless-by-overture.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQBRXYycCp7ImA9WxFWF0w.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-7897514928617483974</id><published>2010-05-31T10:14:00.010+09:00</published><updated>2010-06-05T14:55:54.898+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-05T14:55:54.898+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="金融工学" /><title>ドルコスト平均法ははたして賢い投資方法と言えるのか？ part2</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WBk_fDxU5vn4oBW1q_5m2MPYD10/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WBk_fDxU5vn4oBW1q_5m2MPYD10/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WBk_fDxU5vn4oBW1q_5m2MPYD10/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WBk_fDxU5vn4oBW1q_5m2MPYD10/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8d0SChK7UaQ/TAMNM0hN51I/AAAAAAAAA4w/Yvx3oWw8vok/s1600/img2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_8d0SChK7UaQ/TAMNM0hN51I/AAAAAAAAA4w/Yvx3oWw8vok/s1600/img2.jpg" style="background: none repeat scroll 0% 0% transparent; border: 0pt none;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/nlscotland/2673092921/"&gt;Soviet poster of the transport sector during the Five Year Plan. 1930&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/nlscotland/"&gt;National Library of Scotland&lt;/a&gt;&lt;br /&gt;
&lt;h4&gt;3. 計算&lt;/h4&gt;&lt;a href="http://mglab.blogspot.com/2010/05/part1.html"&gt;前回の記事&lt;/a&gt;で株価が乗法モデル&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0"&gt;&lt;img src="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
に従った場合の一般投資戦略とドルコスト戦略の資産はそれぞれ&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?X_N%5E%7B%281%29%7D%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20R_1%20R_2%20%5Ccdots%20R_N%20X_0%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20X_0%20%5Cprod_%7Bi%3D1%7D%5EN%20R_i"&gt;&lt;img src="http://formula.s21g.com/?X_N%5E%7B%281%29%7D%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20R_1%20R_2%20%5Ccdots%20R_N%20X_0%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20X_0%20%5Cprod_%7Bi%3D1%7D%5EN%20R_i.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?X_N%5E%7B%282%29%7D%20%3D%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j%20%5Cequiv%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i"&gt;&lt;img src="http://formula.s21g.com/?X_N%5E%7B%282%29%7D%20%3D%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j%20%5Cequiv%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
で与えられることが分かりました。&lt;br /&gt;
&lt;br /&gt;
それではこれよりリスクの定量的評価を行います。私たちが知りたいのは、それぞれの資産のリスクとリターンの値です。この場合&lt;b&gt;リターンは確率変数の期待値、リスクは確率変数の分散(より正確に言うと標準偏差)にそれぞれ対応している&lt;/b&gt;ことが分かりますので、 X&lt;sub&gt;N&lt;/sub&gt; の期待値と分散をそれぞれ求めてやればよさそうです。&lt;br /&gt;
&lt;h5&gt;3.1 期待値の計算&lt;/h5&gt;まず簡単な期待値から調べていきましょう。 R&lt;sub&gt;i&lt;/sub&gt; と R&lt;sub&gt;j&lt;/sub&gt; は i≠j の場合独立であり、さらに R&lt;sub&gt;i&lt;/sub&gt; の期待値を μ 、分散を σ&lt;sup&gt;2&lt;/sup&gt; と仮定しているため、 X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(1)&lt;/sup&gt; の期待値は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D[X_n%5E%7B%281%29%7D]%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20%7B%5Crm%20E%7D[R_1]%20%5Ccdots%20%7B%5Crm%20E%7D[R_N]%20X_0%20%5C%5C%0A%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20%5Cmu%5EN%20X_0"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D[X_n%5E%7B%281%29%7D]%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20%7B%5Crm%20E%7D[R_1]%20%5Ccdots%20%7B%5Crm%20E%7D[R_N]%20X_0%20%5C%5C%0A%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20%5Cmu%5EN%20X_0.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(2)&lt;/sup&gt; の期待値は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%5Cleft%28%20%5Cmu%5EN%20+%20%5Cmu%5E%7BN-1%7D%20+%20%5Ccdots%20+%20%5Cmu%20%5Cright%29%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%5Cleft%28%20%5Cmu%5EN%20+%20%5Cmu%5E%7BN-1%7D%20+%20%5Ccdots%20+%20%5Cmu%20%5Cright%29%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となります。&lt;br /&gt;
&lt;h5&gt;3.2 分散の計算&lt;/h5&gt;次に一番知りたい分散についてですが、正直これは期待値に比べて少々面倒くさい。これは分散が期待値のような線形的な関係を持たない上に、ドルコスト平均法の R&lt;sub&gt;i&lt;/sub&gt; の項が折りたたまっているために生じているのですが、そんなことを憂いていても仕方がないのでさっさと計算していきます。&lt;br /&gt;
&lt;br /&gt;
まず比較的簡単な X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(1)&lt;/sup&gt; の分散ですが、&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_n%5E%7B%281%29%7D]%20%3D%20%5Clambda%5E2%20X_0%5E2%20%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N]"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_n%5E%7B%281%29%7D]%20%3D%20%5Clambda%5E2%20X_0%5E2%20%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ここで右式の V にのみ注目すると、分散の定義より&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N]%20%26%3D%26%20%7B%5Crm%20E%7D[R_1%5E2%20R_2%5E2%20%5Ccdots%20R_N%5E2]%20-%20%28%7B%5Crm%20E%7D[R_1%20R_2%20%5Ccdots%20R_N]%29%5E2%20%5C%5C%0A%20%26%3D%26%20%7B%5Crm%20E%7D[R_1%5E2]%20%5Ccdots%20%7B%5Crm%20E%7D[R_N%5E2]%20-%20%5Cmu%5E%7B2N%7D"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N]%20%26%3D%26%20%7B%5Crm%20E%7D[R_1%5E2%20R_2%5E2%20%5Ccdots%20R_N%5E2]%20-%20%28%7B%5Crm%20E%7D[R_1%20R_2%20%5Ccdots%20R_N]%29%5E2%20%5C%5C%0A%20%26%3D%26%20%7B%5Crm%20E%7D[R_1%5E2]%20%5Ccdots%20%7B%5Crm%20E%7D[R_N%5E2]%20-%20%5Cmu%5E%7B2N%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
関係式&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%5Csigma%5E2%20%26%3D%26%20%7B%5Crm%20E%7D[R_i%5E2]%20-%20%5Cmu%5E2%20%5C%5C%0A%7B%5Crm%20E%7D[R_i%5E2]%20%26%3D%26%20%5Csigma%5E2%20+%20%5Cmu%5E2"&gt;&lt;img src="http://formula.s21g.com/?%5Csigma%5E2%20%26%3D%26%20%7B%5Crm%20E%7D[R_i%5E2]%20-%20%5Cmu%5E2%20%5C%5C%0A%7B%5Crm%20E%7D[R_i%5E2]%20%26%3D%26%20%5Csigma%5E2%20+%20%5Cmu%5E2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
に注意すると、上式は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N]%20%26%3D%26%20%28%5Csigma%5E2%20+%20%5Cmu%5E2%29%5EN%20-%20%5Cmu%5E%7B2N%7D%20%5C%5C%0A%20%26%3D%26%20%5Csum_%7Bi%3D0%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D%20-%20%5Cmu%5E%7B2N%7D%20%5C%5C%0A%20%26%3D%26%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[R_1%20R_2%20%5Ccdots%20R_N]%20%26%3D%26%20%28%5Csigma%5E2%20+%20%5Cmu%5E2%29%5EN%20-%20%5Cmu%5E%7B2N%7D%20%5C%5C%0A%20%26%3D%26%20%5Csum_%7Bi%3D0%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D%20-%20%5Cmu%5E%7B2N%7D%20%5C%5C%0A%20%26%3D%26%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となりました。よって X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(1)&lt;/sup&gt; は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%281%29%7D]%20%26%3D%26%20%5Clambda%5E2%20X_0%5E2%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%281%29%7D]%20%26%3D%26%20%5Clambda%5E2%20X_0%5E2%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%7D_N%20C_i%20%5Csigma%5E%7B2i%7D%5Cmu%5E%7B2%28N-i%29%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
と表現できます。これは比較的何も悩まずに展開できました。&lt;br /&gt;
&lt;br /&gt;
次にドルコスト戦略 X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(2)&lt;/sup&gt; について同じように求めていきます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%7B%5Crm%20V%7D[%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i]%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%20%7B%5Crm%20E%7D%5Cleft[%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright%29%5E2%20%5Cright]%20-%20%5Cleft%28%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright]%20%5Cright%29%5E2%20%5Cright%5C%7D%0A"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%7B%5Crm%20V%7D[%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i]%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%20%7B%5Crm%20E%7D%5Cleft[%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright%29%5E2%20%5Cright]%20-%20%5Cleft%28%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright]%20%5Cright%29%5E2%20%5Cright%5C%7D%0A.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
2つの項が現れました。それぞれの項は結構面倒ですので、分けて考えることにします。まず第二項についてですが、&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%5Cleft%28%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright]%20%5Cright%29%5E2%20%26%3D%26%20%28%5Cmu%5EN%20+%20%5Cmu%5E%7BN-1%7D%20+%20%5Ccdots%20+%20%5Cmu%29%5E2%20%5C%5C%0A%20%26%3D%26%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2"&gt;&lt;img src="http://formula.s21g.com/?%5Cleft%28%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright]%20%5Cright%29%5E2%20%26%3D%26%20%28%5Cmu%5EN%20+%20%5Cmu%5E%7BN-1%7D%20+%20%5Ccdots%20+%20%5Cmu%29%5E2%20%5C%5C%0A%20%26%3D%26%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
次に第一項について計算します。まず&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright%29%5E2%20%5Cright]%20%3D%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi,j%7D%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%5Csum_%7Bi,j%7D%20%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i%20%5Cright%29%5E2%20%5Cright]%20%3D%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi,j%7D%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%5Csum_%7Bi,j%7D%20%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ここで&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%7B%5Crm%20E%7D%5Cleft[%20R_i%20%5Ccdots%20R_N%20%5Ctimes%20R_j%20%5Ccdots%20R_N%20%5Cright]"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%7B%5Crm%20E%7D%5Cleft[%20R_i%20%5Ccdots%20R_N%20%5Ctimes%20R_j%20%5Ccdots%20R_N%20%5Cright].png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
についてそれぞれの R&lt;sub&gt;k&lt;/sub&gt; で乗算し、独立性から期待値を分割して求めるわけですが、きちんと注目してやると&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;R&lt;sub&gt;k&lt;/sub&gt; となっている変数は全部で |i-j| 個&lt;/li&gt;
&lt;li&gt; R&lt;sub&gt;k&lt;/sub&gt;&lt;sup&gt;2&lt;/sup&gt; となっている変数は全部で min(N-i+1, N-j+1) 個&lt;/li&gt;
&lt;/ul&gt;となっているため、上式は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%5Cmu%5E%7B%7Ci-j%7C%7D%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5E%7B%5Cmin%28N-i+1,%20N-j+1%29%7D"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%3D%20%5Cmu%5E%7B%7Ci-j%7C%7D%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5E%7B%5Cmin%28N-i+1,%20N-j+1%29%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
と展開できます。&lt;br /&gt;
&lt;br /&gt;
ここで対称性について考えます。当たり前ですが i と j を反転させても上式の値は不変であるため、反転対称性から上式は以下のように展開できます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi,j%7D%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%26%3D%26%202%7B%5Crm%20E%7D%5Cleft[%5Csum_%7Bj%3Ei%7D%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20+%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%7B%5Ccal%20R%7D_i%5E2%20%5Cright]%20%5C%5C%0A%20%26%3D%26%202%20%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5Ei"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi,j%7D%20%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20%26%3D%26%202%7B%5Crm%20E%7D%5Cleft[%5Csum_%7Bj%3Ei%7D%7B%5Ccal%20R%7D_i%20%7B%5Ccal%20R%7D_j%20%5Cright]%20+%20%7B%5Crm%20E%7D%5Cleft[%20%5Csum_%7Bi%3D1%7D%5EN%7B%5Ccal%20R%7D_i%5E2%20%5Cright]%20%5C%5C%0A%20%26%3D%26%202%20%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%28%5Cmu%5E2%20+%20%5Csigma%5E2%29%5Ei.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
以上から、 X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(2)&lt;/sup&gt; の分散の値は&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%28%5Cmu%5E2%20+%5Csigma%5E2%29%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%28%5Cmu%5E2%20+%5Csigma%5E2%29%5Ei%20-%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5E%7BN%7D%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%5Cequiv%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%5Cnu%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cnu%5Ei%20-%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5E%7BN%7D%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%28%5Cmu%5E2%20+%5Csigma%5E2%29%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%28%5Cmu%5E2%20+%5Csigma%5E2%29%5Ei%20-%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5E%7BN%7D%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%5Cequiv%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%5Cmu%5E%7Bj-i%7D%5Cnu%5E%7BN-j+1%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cnu%5Ei%20-%20%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5E%7BN%7D%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となります。ここで、数式を見やすくするために&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%5Cnu%20%3D%20%5Cmu%5E2%20+%20%5Csigma%5E2"&gt;&lt;img src="http://formula.s21g.com/?%5Cnu%20%3D%20%5Cmu%5E2%20+%20%5Csigma%5E2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
と定義しておくことにし、便宜的にこの変数を『&lt;b&gt;修正バリアンス&lt;/b&gt;』とでも名づけておきます。この命名が正しいのかどうか、そもそも名前がつけられているのかについてはよく分かりません。&lt;br /&gt;
&lt;br /&gt;
この分散、和の項が3つ並んできたり少々面倒くさい形になっていますが、よくよく注目してみると σ に関して単調増加の形をしており、 σ=0 を代入すると結果に0が帰ってきたりとちゃんとしたリスク関数になっているのが確認できます。ただこの関数が一般投資戦略に比べてリスクを分散する形になっているかどうかはちょっと判別しにくいですね。&lt;br /&gt;
&lt;br /&gt;
まぁそんなこんなで X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(1)&lt;/sup&gt; と X&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(2)&lt;/sup&gt; それぞれにおける期待値と分散を求めることができました。次回はこの関数を利用して定量的な調査を行っていきます。&lt;br /&gt;
&lt;h5&gt;Note. σに関して単調増加であることと0であることの説明&lt;/h5&gt;まず、式の形よりV&lt;sub&gt;N&lt;/sub&gt;&lt;sup&gt;(2)&lt;/sup&gt;はσに関して単調増加関数であることは自明。&lt;br /&gt;
次にσ=0を代入すると修正バリアンスはμ&lt;sup&gt;2&lt;/sup&gt;になるので、次数を調整した後で合計のラベリングを変更してやると、&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%20%5Cmu%5E%7BN%20-%20j%20+%201%7D%5Cmu%5E%7BN%20-%20i%20+%201%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20-%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ci%7D%20%5Cmu%5E%7Bi%7D%5Cmu%5E%7Bj%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20-%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%3D%26%200"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Crm%20V%7D[X_N%5E%7B%282%29%7D]%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ei%7D%20%5Cmu%5E%7BN%20-%20j%20+%201%7D%5Cmu%5E%7BN%20-%20i%20+%201%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20-%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%3D%26%20%5Cfrac%7BX_0%5E2%7D%7BN%5E2%7D%20%5Cleft%5C%7B%202%5Csum_%7Bj%3Ci%7D%20%5Cmu%5E%7Bi%7D%5Cmu%5E%7Bj%7D%20+%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20-%5Cleft%28%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cmu%5Ei%20%5Cright%29%5E2%20%5Cright%5C%7D%20%5C%5C%0A%20%26%3D%26%200.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
となる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-7897514928617483974?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/jvFKS9BLuXQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/7897514928617483974/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=7897514928617483974" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7897514928617483974?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/7897514928617483974?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/jvFKS9BLuXQ/part2.html" title="ドルコスト平均法ははたして賢い投資方法と言えるのか？ part2" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_8d0SChK7UaQ/TAMNM0hN51I/AAAAAAAAA4w/Yvx3oWw8vok/s72-c/img2.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/05/part2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EARH06fyp7ImA9WxFWFEU.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8642308086924727911</id><published>2010-05-29T03:19:00.016+09:00</published><updated>2010-06-02T22:34:05.317+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-02T22:34:05.317+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="金融工学" /><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>ドルコスト平均法は賢い投資方法と言えるのか？ part1</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/r4HhbBwwG67pVBS8Syv3dQ34gZM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/r4HhbBwwG67pVBS8Syv3dQ34gZM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/r4HhbBwwG67pVBS8Syv3dQ34gZM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/r4HhbBwwG67pVBS8Syv3dQ34gZM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_8d0SChK7UaQ/TAAKNGgNj5I/AAAAAAAAA4o/vaB9ZjbFfOs/s1600/investment.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="232" src="http://4.bp.blogspot.com/_8d0SChK7UaQ/TAAKNGgNj5I/AAAAAAAAA4o/vaB9ZjbFfOs/s640/investment.jpg" style="background: none repeat scroll 0% 0% transparent; border: 0pt none;" width="550px" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/nlscotland/2673912878/"&gt;Soviet poster from the Five year plan showing economic investment. 1930&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/nlscotland/"&gt;National Library of Scotland&lt;/a&gt;&lt;br /&gt;
&lt;h4&gt;1. 概要&lt;/h4&gt;ドルコスト平均法という投資法があります。一応簡単に説明しておくと、&lt;b&gt;ある区切られた期間ごとに同じ金額だけ対象の商品を購入しておくことで、安定した収益が得られる&lt;/b&gt;という戦略です。信託投資やFXをやっている方にとっては馴染み深い戦略かもしれませんし、ファイナンシャルプランナーからお勧めされた方も多いかもしれません。&lt;br /&gt;
&lt;br /&gt;
一定期間同じ金額だけ同じ商品を買うだけというこの戦略、よく初心者にお勧めの投資法として雑誌などでは紹介されていますが、&lt;b&gt;はたして本当にお勧めできる投資法なのでしょうか？&lt;/b&gt;またリスクを軽減できるとありますが、&lt;b&gt;一体どれくらいのリスク軽減が望めるのでしょうか？それに対して、リターンはどれくらい減少するのでしょうか？&lt;/b&gt;以上を明らかにしていくのが今回の記事の目的です。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;定量的に評価するために少々数式が登場してきますが、一応大学の経済学を専攻していたり、統計学について初歩的な知識(期待値や分散など)を持っている方ならばすいすいと読み進めることができるくらいのレベルを目指しています。&lt;/li&gt;
&lt;li&gt;金融工学に関しての知識はまったく必要ありません。必要な箇所はすべて簡単に解説していきます。&lt;/li&gt;
&lt;li&gt;今回の記事は式の導出までを行います。結果だけ知りたい方は読み飛ばしてもらっても構いません。&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;2. 2つの戦略&lt;/h4&gt;ここではドルコスト戦略についてより詳しく説明した後に、数式を用いて定式化していきたいと思います。今回は比較のため、ドルコスト戦略の他にもう一つ『一般投資』を取り上げていきます。&lt;br /&gt;
&lt;br /&gt;
まず&lt;b&gt;一般投資戦略&lt;/b&gt;とは特になんにも考慮することなく、自分の手持ち資産のうち一部分を対象の金融商品に投資して、その後は満期まで放置しておくという戦略です。&lt;br /&gt;
&lt;br /&gt;
一方で、&lt;b&gt;ドルコスト戦略&lt;/b&gt;はまず自分の手持ち資産のすべてをN分割し、一定期間毎に対象の金融商品を購入するという行為をN回行って、満期まで保持しておくという戦略です。&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8d0SChK7UaQ/TAAI_WzjkGI/AAAAAAAAA4g/icC3ZEAtMrw/s1600/img1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8d0SChK7UaQ/TAAI_WzjkGI/AAAAAAAAA4g/icC3ZEAtMrw/s400/img1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;この2つの戦略を定式化する前に、まず以下の仮定を行っていきましょう。&lt;br /&gt;
&lt;ol&gt;&lt;li&gt; 時間を離散化してN期間として考え、現在いる時点を0時点、満期をN時点とします。&lt;/li&gt;
&lt;li&gt;株価をS&lt;sub&gt;n&lt;/sub&gt;で表し、S&lt;sub&gt;n&lt;/sub&gt;は以下の『&lt;b&gt;乗法モデル&lt;/b&gt;』に従うとします。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0"&gt;&lt;img src="http://formula.s21g.com/?S_N%20%3D%20R_1%20R_2%20%5Ccdots%20R_N%20S_0.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ここで、R&lt;sub&gt;i&lt;/sub&gt;は確率変数とします。つまり、S&lt;sub&gt;i&lt;/sub&gt;も確率変数となります。ただし、S&lt;sub&gt;0&lt;/sub&gt;だけは現時点で株価が判明しているのでただの実数となります。&lt;br /&gt;
R&lt;sub&gt;i&lt;/sub&gt;自体の確率分布は全く仮定していないことに注意してください。つまり、R&lt;sub&gt;i&lt;/sub&gt;は正規分布に従うとは限りません。                         &lt;/li&gt;
&lt;li&gt;計算を簡単にするため、&lt;b&gt;異なる確率変数R&lt;sub&gt;i&lt;/sub&gt;とR&lt;sub&gt;j&lt;/sub&gt;は完全に独立であり、また期待値と分散は同一の値μとσ&lt;sup&gt;2&lt;/sup&gt;を付与する&lt;/b&gt;ものと仮定します。&lt;br /&gt;
もちろん、これは理想化された仮定で、現実的ではありません。実際、R&lt;sub&gt;i&lt;/sub&gt;が過去の値に影響することは数々の測定から明らかになっています。が、そんなこといちいち考慮に入れるととっても大変ですし、そもそも今回の目的とは趣向が異なります。そこまで正確にやるんでしたら連続時間と仮定して確率微分方程式を解くべきですしね。こういうことするのは専門家だけで結構ですので今回はやりません。&lt;/li&gt;
&lt;/ol&gt;以上の仮定を用いて、実際に2つの戦略を定式化します。まず一般投資戦略の場合、X&lt;sub&gt;n&lt;/sub&gt;をn時点での手持ち資産と定義すると、以下のように表せます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?X_N%5E%7B%281%29%7D%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20R_1%20R_2%20%5Ccdots%20R_N%20X_0%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20X_0%20%5Cprod_%7Bi%3D1%7D%5EN%20R_i"&gt;&lt;img src="http://formula.s21g.com/?X_N%5E%7B%281%29%7D%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20R_1%20R_2%20%5Ccdots%20R_N%20X_0%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%281-%5Clambda%29X_0%20+%20%5Clambda%20X_0%20%5Cprod_%7Bi%3D1%7D%5EN%20R_i.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ここで、λは手持ち資産のうち投資にかけるウェイトとして定義され、0&amp;lt;λ&amp;lt;1の間をとります。&lt;br /&gt;
&lt;br /&gt;
次に、ドルコスト戦略の場合は、少々複雑ですが以下のように表せます。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?X_N%5E%7B%282%29%7D%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7DR_1%20R_2%20%5Ccdots%20R_N%20+%20%5Cfrac%7BX_0%7D%7BN%7D%20R_2%20R_3%20%5Ccdots%20R_N%20+%20%5Ccdots%20+%20%5Cfrac%7BX_0%7D%7BN%7DR_N%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%28R_1%20%5Ccdots%20R_N%20+%20R_2%20%5Ccdots%20R_N%20+%20%5Ccdots%20+%20R_N%29%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%5Cequiv%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i"&gt;&lt;img src="http://formula.s21g.com/?X_N%5E%7B%282%29%7D%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7DR_1%20R_2%20%5Ccdots%20R_N%20+%20%5Cfrac%7BX_0%7D%7BN%7D%20R_2%20R_3%20%5Ccdots%20R_N%20+%20%5Ccdots%20+%20%5Cfrac%7BX_0%7D%7BN%7DR_N%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%28R_1%20%5Ccdots%20R_N%20+%20R_2%20%5Ccdots%20R_N%20+%20%5Ccdots%20+%20R_N%29%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%3D%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%26%5Cequiv%26%20%5Cfrac%7BX_0%7D%7BN%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%7B%5Ccal%20R%7D_i.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
ただし、後の計算を楽にするため、&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://formula.s21g.com/?%7B%5Ccal%20R%7D_i%20%3D%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j"&gt;&lt;img src="http://formula.s21g.com/?%7B%5Ccal%20R%7D_i%20%3D%20%5Cprod_%7Bj%3Di%7D%5EN%20R_j.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
とおきました。&lt;br /&gt;
&lt;br /&gt;
ここで注目しておきたいのが、上式の形です。R&lt;sub&gt;N&lt;/sub&gt;の項が最も多く出現し、満期から現時点まで下がっていくにつれて出現回数が減少していくのが分かるでしょう。このことから何が言えるのかというと、『&lt;b&gt;ドルコスト平均戦略は満期近くの株価の変動に最も大きな影響を受ける&lt;/b&gt;』ということです。つまり、初期時点で株価が上昇しても、満期近くに株価が大きく下落した場合、ドルコスト戦略を用いると資産がマイナスになってしまうのです。&lt;br /&gt;
&lt;br /&gt;
もちろん、λ=1(全力投資)の場合の投資戦略よりはリスクは分散されていることは式の違いにより明らかです。それは確かなので、ドルコスト戦略はリスクを軽減する戦略であることは間違いありません。ですが、これはλの値を調整することで同じ効果を与えそうです。&lt;br /&gt;
&lt;br /&gt;
ここから分かる結論としては、『&lt;b&gt;ドルコスト戦略は満期近くに株価が大きく上昇すると予想した場合に効力を発揮する戦略である&lt;/b&gt;』ということです。ですが通常の場合ですと、満期近くの株価の変動なんて正直予想できるはずがありません(明日の株価ですら予想は難しいというのに)。ドルコスト戦略が初心者にお勧めできるという論調は少々疑問であります。&lt;br /&gt;
&lt;br /&gt;
そうなると結局のところ、フィナンシャルプランナーがドルコスト平均法を進める主な理由は『&lt;b&gt;商品を定期購入してくれる客を作り出す&lt;/b&gt;』ためである気がしてなりません。だって長期投資という名目の元で、給料の一定金額を毎月自分たちに差し出してくれて、しかもその回数分だけ手数料をいただける。これほど美味しい客はありません…&lt;br /&gt;
&lt;br /&gt;
…いやいや、そう考えるのはまだ早い。もしかしたらきちんとリスクを定量的に評価した上で勧めているのかもしれません。となると次に気になってくるのが『&lt;b&gt;一体どれくらいリスクが減少するのか、その上でリターンはどれくらい減少するのか&lt;/b&gt;』という点です。「&lt;b&gt;どうしてもドルコスト平均法じゃないといけないんですか？最初っから投資額を抑えることもできるんじゃないですか？&lt;/b&gt;」という声がどこからか聞こえてきそうです。&lt;br /&gt;
&lt;br /&gt;
疲れたので今日はここまで。次回から実際のリスクとリターンの評価を行っていきます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8642308086924727911?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/M0w4ebs-bOs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8642308086924727911/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8642308086924727911" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8642308086924727911?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8642308086924727911?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/M0w4ebs-bOs/part1.html" title="ドルコスト平均法は賢い投資方法と言えるのか？ part1" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_8d0SChK7UaQ/TAAKNGgNj5I/AAAAAAAAA4o/vaB9ZjbFfOs/s72-c/investment.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/05/part1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MGSXc9eCp7ImA9WxFQFUU.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8388917440258229949</id><published>2010-05-11T20:28:00.009+09:00</published><updated>2010-05-11T22:43:48.960+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-11T22:43:48.960+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="思うこと" /><title>2006年に発表されたイグノーベル賞の文学賞が面白い</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MzuOBLMIiF-ITSKFKuTsnPcuOBo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MzuOBLMIiF-ITSKFKuTsnPcuOBo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MzuOBLMIiF-ITSKFKuTsnPcuOBo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MzuOBLMIiF-ITSKFKuTsnPcuOBo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-kbazM-rsI/AAAAAAAAA3M/uyn5qvnEqZs/s1600/literature.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-kbazM-rsI/AAAAAAAAA3M/uyn5qvnEqZs/s320/literature.jpg" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: transparent none repeat scroll 0% 0%; border: 0pt none;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/helder/147682913/"&gt;860 Hispanic literature; 869 Portuguese&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/helder/"&gt;Helder da Rocha&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
2006年に発表された&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%A4%E3%82%B0%E3%83%8E%E3%83%BC%E3%83%99%E3%83%AB%E8%B3%9E"&gt;イグノーベル賞&lt;/a&gt;の文学賞が面白いです。どういう論文かっていうと『&lt;i&gt;無駄に難しい単語を多用したとき、そいつは知的に見えるかどうか&lt;/i&gt;』っていう論文で、まずタイトルからして "&lt;a href="http://web.princeton.edu/sites/opplab/papers/Opp%20Consequences%20of%20Erudite%20Vernacular.pdf"&gt;&lt;i&gt;Consequences of Erudite Vernacular Utilized Irrespective of Necessity:  Problems with Using Long Words Needlessly.&lt;/i&gt;&lt;/a&gt;" 。完全にふざけてます。Summaryも秀逸で、これ言いたいだけにこの論文書いただろって思うくらい。面白かったので思わずノリでSummary部分を翻訳してしまいました:&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;必要性と無関係に使用される博学な専門的用語が導く結末：不必要に長い単語を使うことにおける問題&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;DANIEL M. OPPENHEIMER&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
執筆者にとって最も奨励されている書き方は、過度に複雑な語彙の使用を避けることだ。しかしながら、大多数の学生は知的な印象を与えようとして、わざと複雑な語彙を使おうとする傾向にある。この論文ではその戦略が効果的であるかどうか、その程度について調査する。実験1-3では語彙の複雑性について扱い、語彙の複雑性と知的に見える効果の間柄には負の関係性があることを調べる。この関係性は元の小論文の質や、小論文の内容がどうであるかや、参加者が最初に期待していた度合いについては関わらない。複雑性の負の影響については、文章の読解速度(fluency)を処理することによって調べた。実験4では直接読解速度について扱い、読解が難しくなる文章はより著者が知的でないと判断されることが判明した。実験5では読解速度を遅くする要因について調査した。以上より、読解が難しくなる文章は明らかに正解であると即座に判断できなくなるため、人々は読解する手がかりの少なさから、文章をあまり信頼しなくなる。事実、文章の本質に関わらない語彙というのは過度に文章を修飾してしまい、結果としてかえって反対の方向へ影響してしまう。これらの影響や、実際の応用についても議論した。Copyright 2005 John Wiley &amp;amp; Sons, Ltd.&lt;/blockquote&gt;適当な翻訳で勘弁！この教授は学生の無駄に難しい言い回しを多用したレポートに飽き飽きして書いたんです。間違いない。&lt;br /&gt;
&lt;br /&gt;
でも、実際こういうのってよくあるよなぁとか思います。『&lt;b&gt;齟齬&lt;/b&gt;』『&lt;b&gt;蓋然性&lt;/b&gt;』『&lt;b&gt;慚愧&lt;/b&gt;』とか使われても、あんま頭良さそうに見えません。最近の例でいいますと&lt;a href="http://kazuyomugi.cocolog-nifty.com/private/2010/05/52-7a45.html"&gt;対談&lt;/a&gt;の際に用いられた『&lt;b&gt;写像&lt;/b&gt;』でしょうか。これも別にここで使わなくても、十分に説明できましたし…&lt;br /&gt;
&lt;br /&gt;
やっぱりイグノーベル賞は全体的に面白いです。こういうセンス日本にはないよなぁ。羨ましい限り。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8388917440258229949?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/g2abmG7iby4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8388917440258229949/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8388917440258229949" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8388917440258229949?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8388917440258229949?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/g2abmG7iby4/2006.html" title="2006年に発表されたイグノーベル賞の文学賞が面白い" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-kbazM-rsI/AAAAAAAAA3M/uyn5qvnEqZs/s72-c/literature.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/05/2006.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQNRH89eCp7ImA9WxFWGEQ.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-5732181168175690978</id><published>2010-05-06T20:32:00.014+09:00</published><updated>2010-06-07T16:39:55.160+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-07T16:39:55.160+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="Ubuntu" /><title>Geant4をCernのリポジトリ経由でインストールする</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Rm15sN7teegoCfzWgsSlZoZKczI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Rm15sN7teegoCfzWgsSlZoZKczI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Rm15sN7teegoCfzWgsSlZoZKczI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Rm15sN7teegoCfzWgsSlZoZKczI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-Kub38N2II/AAAAAAAAA3E/_XHZQwAzlzk/s1600/cern.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-Kub38N2II/AAAAAAAAA3E/_XHZQwAzlzk/s320/cern.jpg" style="-moz-background-inline-policy: continuous; background: none repeat scroll 0% 0% transparent; border: 0pt none;" /&gt;&lt;/a&gt;&lt;/div&gt;&amp;nbsp;"&lt;a href="http://www.flickr.com/photos/dominikf/2092966263/"&gt;ALICE - A Large Ion Collider Experiment at Cern&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/dominikf/"&gt;dominikf&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://geant4.cern.ch/"&gt;Geant4&lt;/a&gt;のインストールはソースコードをダウンロードし、ビルドを行うという手法が旧来の日本のページではよく書かれていますが、Debian系列(Ubuntu)のディストリビューションを使っているのであれば、いちいちそんな手間のかかることをしなくてもリポジトリ経由でインストールすることができます。こんな大容量のライブラリですと、ライブラリの依存関係を解決するだけでも大分かかっちゃいますしね。&lt;br /&gt;
&lt;br /&gt;
で、aptを利用してGeant4をインストールするためには、現時点では以下の手順を踏んで行うのが一番楽ちんです。&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://lcg-heppkg.web.cern.ch/lcg-heppkg/debian/index.html"&gt;Cernのリポジトリ&lt;/a&gt;を新規に追加します。&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;
&lt;i&gt;deb http://lcg-heppkg.web.cern.ch/lcg-heppkg/debian stable hep&lt;/i&gt;&lt;/span&gt;&lt;i&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;deb-src http://lcg-heppkg.web.cern.ch/lcg-heppkg/debian stable hep&lt;/span&gt;&lt;/i&gt; &lt;br /&gt;
&lt;br /&gt;
の2つを、Synapticかコマンドライン経由で追加してあげればいいでしょう。&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;apt-get update&lt;/span&gt;&lt;/i&gt;でデータベースを更新します。もちろんそのときこの2つのリポジトリが信用できるのかどうかわかりませんので、aptさんは&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;
&lt;i&gt;W: GPG error: http://lcg-heppkg.web.cern.ch stable Release: 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY F464E3D84061544D&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
のようなエラーを吐きます。そこで、これらの警告がでないようにしてやります。&lt;/li&gt;
&lt;li&gt;コマンドラインを立ち上げて、&lt;br /&gt;
&lt;code style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;i&gt;sudo apt-get install cern-archive-keyring&lt;/i&gt;&lt;br /&gt;
と入力。&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;
&lt;i&gt;警告: 以下のパッケージは認証されていません!&lt;/i&gt;&lt;/span&gt;&lt;i&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; cern-archive-keyring&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;検証なしにこれらのパッケージをインストールしますか [y/N]?&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;と当たり前ですが聞かれるので、yを入力します。信用されていないリポジトリから鍵をインストールして警告を出さないようにするってあたりが、俺を信頼しろ感が出ててとっても素敵。&lt;/span&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;i&gt;apt-get update&lt;/i&gt; &lt;span style="font-family: inherit;"&gt;でエラーが出ないことを確認してから、&lt;/span&gt;&lt;i&gt;sudo apt-get install geant4&lt;/i&gt;&lt;span style="font-family: inherit;"&gt;でGeant4をインストールして、終了です。&lt;/span&gt;&lt;/code&gt;&lt;code style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/code&gt;&lt;code style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;自分の環境(Ubuntu 10.04)ではこの手法で特に問題なくインストールできました。多分Debianでも普通にインストールできると思います。&lt;br /&gt;
&lt;br /&gt;
さて、次に環境変数の設定を行っていきます。ホームディレクトリの&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;".profile"&lt;/span&gt;ファイルの末尾に以下を記述します。&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;export G4WORKDIR=${HOME}/work/g4&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;これを行うことで、Geant4のワーキングディレクトリを&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;${HOME}/work/g4&lt;span style="font-family: inherit;"&gt;に設定します。&lt;/span&gt;${HOME}&lt;span style="font-family: inherit;"&gt;以下は各自適当なやつに変えてみてください。&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-family: inherit;"&gt;また、Geant4の動作に必要なシェルの変数を書き出すためには、対象のシェル内で&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;i&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;source /usr/share/geant4/env.sh&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: inherit;"&gt;と入力。きちんとG4WORKDIRが設定されていることを確認してください。&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-5732181168175690978?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/6lbyVE-mfOo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/5732181168175690978/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=5732181168175690978" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/5732181168175690978?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/5732181168175690978?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/6lbyVE-mfOo/geant4cern.html" title="Geant4をCernのリポジトリ経由でインストールする" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/S-Kub38N2II/AAAAAAAAA3E/_XHZQwAzlzk/s72-c/cern.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/05/geant4cern.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcFRXg7eyp7ImA9WxFTFEQ.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-2928879069301582444</id><published>2010-04-06T01:49:00.008+09:00</published><updated>2010-04-06T02:53:34.603+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-06T02:53:34.603+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="思うこと" /><title>マルコフ連鎖を使って簡単な問題を解いてみよう</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0ASONtHqn2Hy0vOVJX9mYxTMs2M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0ASONtHqn2Hy0vOVJX9mYxTMs2M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0ASONtHqn2Hy0vOVJX9mYxTMs2M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0ASONtHqn2Hy0vOVJX9mYxTMs2M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/S7oWq62ly6I/AAAAAAAAA2c/8JvEBs98UjE/s1600/pic.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/S7oWq62ly6I/AAAAAAAAA2c/8JvEBs98UjE/s320/pic.jpg" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: transparent none repeat scroll 0% 0%; border: 0pt none;" /&gt;&lt;/a&gt;&lt;/div&gt;"&lt;a href="http://www.flickr.com/photos/rainbowcatz/3487714868/"&gt;Cute Gyoza / Meat Dumpling Key Chain&lt;/a&gt;" by &lt;a href="http://www.flickr.com/photos/rainbowcatz/"&gt;♥ Rainbowcatz ♥&lt;/a&gt;&lt;br /&gt;
&lt;h4&gt;はじめに&lt;/h4&gt;&lt;a href="http://www.google.co.jp/search?hl=ja&amp;amp;client=firefox-a&amp;amp;hs=XT&amp;amp;rls=com.ubuntu%3Aja%3Aofficial&amp;amp;q=%E4%BA%BA%E5%B7%A5%E7%84%A1%E8%83%BD+%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95%E9%80%A3%E9%8E%96&amp;amp;aq=0r&amp;amp;aqi=g-r1&amp;amp;aql=&amp;amp;oq=%E4%BA%BA%E5%B7%A5%E7%84%A1%E8%83%BD%E3%80%80%E3%81%BE%E3%82%8B%E3%81%93&amp;amp;gs_rfai="&gt;人工無能&lt;/a&gt;、一時期流行りましたねー。&lt;br /&gt;
&lt;br /&gt;
難そうなわりに以外と簡単で、しかも結果が面白いということでRubyやなんかで実装している記事をよく見かけました。そういった中でマルコフ連鎖が注目されていた時期が一時期ありましたが、正直あれはマルコフ連鎖を利用しているというよりは、別のアルゴリズムにマルコフ連鎖という名前をつけたというか、あんまり関連性がないなーという印象でした。&lt;br /&gt;
&lt;br /&gt;
マルコフ連鎖の本質はそういうことではなく、状態の遷移確率を行列によって求めたり、定常分布を固有値問題で計算するところにある、と自分は考えています。マルコフ連鎖についてのより詳しい説明は他のブログにお任せするとして(自分がやるとすぐにボロが出てしまう)、今回はマルコフ連鎖を使って簡単な問題を解き、実際にマルコフ連鎖がどんな感じなのか確かめてみることにします。&lt;br /&gt;
&lt;h4&gt;もんだい&lt;/h4&gt;&lt;blockquote&gt;二つの箱A,Bが用意されている。2つの箱の内部は完全に遮蔽されており、外部からは確認することができない。また、Aの箱には赤玉がN個、Bの箱には白玉がN個入っている。&lt;br /&gt;
&lt;br /&gt;
ここで、両方の箱に腕を突っ込み、それぞれの箱から玉を一個づつ取り出し、交換し、反対側の箱のなかに入れることにしよう。今回の場合、Aの箱には赤玉がN-1、白玉が1個入ることになる。もちろん、Bの箱には赤玉が1個、白玉がN-1個入っている。&lt;br /&gt;
&lt;br /&gt;
この試行をひたすら続けて、そう、例えば無限回行ってみよう。この場合、Aの箱に入っている赤玉の数はどれくらいであろうか？個数に対応した確率分布を求めよ。&lt;/blockquote&gt;&lt;h4&gt;回答&lt;/h4&gt;&lt;b&gt;1回、2回ならまだしも、無限回なんて計算できるかクソが！&lt;/b&gt;そんなふうに考えていた時期が俺にもありました。&lt;br /&gt;
&lt;br /&gt;
まず、Aの箱における赤玉の個数をmとおきます。すると、これは状態mの遷移問題と考えることができ、マルコフ連鎖が使えます。&lt;br /&gt;
&lt;br /&gt;
また、1期間後にとりうることのできるmの遷移はm-1, m, m+1の3通りしか存在しません。以上を利用して、各mにおける状態の遷移確率を求めることができます。&lt;br /&gt;
&lt;br /&gt;
まず、mがm+1に遷移する確率(m-&amp;gt;m+1)を求めてみましょう。この場合、確率はAの箱の白玉が選ばれる確率とBの箱の赤玉が選ばれる確率の積に等しいので、&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%5Cbiggr%28%20%5Cfrac%7BN-m%7D%7BN%7D%20%5Cbiggl%29%20%5Ccdot%20%5Cbiggr%28%20%5Cfrac%7BN-m%7D%7BN%7D%20%5Cbiggl%29%20%3D%20%5Cfrac%7B%28N-m%29%5E2%7D%7BN%5E2%7D"&gt;&lt;img src="http://formula.s21g.com/?%5Cbiggr%28%20%5Cfrac%7BN-m%7D%7BN%7D%20%5Cbiggl%29%20%5Ccdot%20%5Cbiggr%28%20%5Cfrac%7BN-m%7D%7BN%7D%20%5Cbiggl%29%20%3D%20%5Cfrac%7B%28N-m%29%5E2%7D%7BN%5E2%7D.png" /&gt;&lt;/a&gt;&lt;br /&gt;
と表せます。&lt;br /&gt;
&lt;br /&gt;
同様にして、m-&amp;gt;m, m-&amp;gt;m-1 についても表していきます。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;mがmに遷移する確率は(i)Aの箱の赤玉が選ばれる確率とBの箱の赤玉が選ばれる確率の積と(ii)Aの箱の白玉が選ばれる確率とBの箱の白玉が選ばれる確率の積 の和((i)+(ii))に等しい。&lt;/li&gt;
&lt;li&gt;mがm-1に遷移する確率は確率はAの箱の赤玉が選ばれる確率とBの箱の白玉が選ばれる確率に等しい。&lt;/li&gt;
&lt;/ul&gt;以上の議論をまとめると、i-&amp;gt;jへの遷移行列p&lt;span style="font-size: xx-small;"&gt;ij&lt;/span&gt;は以下のように表せます。&lt;br /&gt;
&lt;a href="http://formula.s21g.com/?%5Cmathrm%7Bp%7D_%7Bij%7D%20%3D%20%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bll%7D%0Ai%5E2/N%5E2%20%26%20j%3Di-1%20%5C%5C%0A2i%28N-i%29/N%5E2%20%26%20j%3Di%20%5C%5C%0A%28N-i%29%5E2/N%5E2%20%26%20j%3Di+1%20%5C%5C%0A0%20%26%20%5Cmathrm%7Botherwise%7D%0A%5Cend%7Barray%7D%20%5Cright."&gt;&lt;img src="http://formula.s21g.com/?%5Cmathrm%7Bp%7D_%7Bij%7D%20%3D%20%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bll%7D%0Ai%5E2/N%5E2%20%26%20j%3Di-1%20%5C%5C%0A2i%28N-i%29/N%5E2%20%26%20j%3Di%20%5C%5C%0A%28N-i%29%5E2/N%5E2%20%26%20j%3Di+1%20%5C%5C%0A0%20%26%20%5Cmathrm%7Botherwise%7D%0A%5Cend%7Barray%7D%20%5Cright..png" /&gt;&lt;/a&gt;&lt;br /&gt;
ここで、遷移行列はN×Nの次元を持っているものとします。 &lt;br /&gt;
&lt;br /&gt;
以上を利用して遷移行列を求め、pythonを用いて定常分布を算出しました。プログラムのソースコードを以下に示します。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
eig.py [N]

定常確率分布を記述したファイルを新しく書き込むプログラムです。
引数には箱に入っている玉の数を指定します。引数が指定されなかった場合には、N=10が用いられます。
"""

import sys

def main():
    number = int(sys.argv[1]) if len(sys.argv) == 2 else 10
    P = getStateMatrix(number)
    result = getFiniteStateSpace(P)
    fp = file("%i.dat" % number, "w")
    fp.write("\n".join([str(abs(num)) for num in result]))
    fp.close()

def getStateMatrix(n):
    """n個における遷移確率行列を返します"""
    from scipy import matrix
    P = [[getState(i, j, n) for j in xrange(n+1)] for i in xrange(n+1)]
    return matrix(P)

def getState(i, j, N):
    if   j == i-1: return float(i*i)/(N*N)
    elif j == i:   return float(2*i*(N-i))/(N*N)
    elif j == i+1: return float((N-i)**2)/(N*N)
    else: return 0.0

def getFiniteStateSpace(mat):
    """
    i-&amp;gt;jに遷移する確率を行列(i,j)で表現した遷移確率行列から、定常分布を求めます。
    この関数は行列を転置する必要がない点に注意してください。
    
    mat : N×Nの遷移確率行列(numpyのmatrixでなければならない)
    戻り値 : N次元の定常分布ベクトル
    """
    from scipy import linalg
    la, v = linalg.eig(mat.T)
    result = zip(la, v.T)
    
    # 定常分布を求めるため、固有値が1に近い順で固有ベクトルをソートする
    result_sorted = sorted(result,
                           cmp=lambda x, y: cmp(abs(1.0-x), abs(1.0-y)),
                           key=lambda x: x[0])
    
    eig_value   = result_sorted[0][0]
    # 固有値が1近傍でなかったら例外を送出
    assert abs(eig_value - 1.0) &amp;lt; 1.0e-6, "the eigen value of FSS is apart from 1.0"
    
    fss = result_sorted[0][1]    
    return fss/sum(fss) # 正規化

if __name__ == "__main__":
 sys.exit(main())
&lt;/pre&gt;&lt;br /&gt;
実行は対象のソースコードを"eig.py"として保存してから、カレントディレクトリを適切なディレクトリに移動した後で、コマンドライン上から"python eig.py 10"のように指定してあげます。この場合、N=10(赤玉10個, 白玉10個)の際に遷移するであろう定常分布のデータが"10.dat"として書き出されます。&lt;br /&gt;
&lt;br /&gt;
ここで、試しにN=6, 10, 50, 100における確率分布を載せておきます。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8d0SChK7UaQ/S7mG18dUnzI/AAAAAAAAA18/-QZ6fehLitU/s1600/6.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8d0SChK7UaQ/S7mG18dUnzI/AAAAAAAAA18/-QZ6fehLitU/s320/6.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;N = 6 のとき。離散的でよく分からないが、N=3付近の確率が一番高くなっている。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8d0SChK7UaQ/S7mG4knFZcI/AAAAAAAAA2E/kq3I07k0WDM/s1600/10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8d0SChK7UaQ/S7mG4knFZcI/AAAAAAAAA2E/kq3I07k0WDM/s320/10.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_8d0SChK7UaQ/S7mG7Q5v0UI/AAAAAAAAA2M/JgU5YdKIlOA/s1600/50.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_8d0SChK7UaQ/S7mG7Q5v0UI/AAAAAAAAA2M/JgU5YdKIlOA/s320/50.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;N = 10, 50 のとき。だんだん滑らかになっていく。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_8d0SChK7UaQ/S7mG-bYsTtI/AAAAAAAAA2U/7d8GVC15QlE/s1600/100.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8d0SChK7UaQ/S7mG-bYsTtI/AAAAAAAAA2U/7d8GVC15QlE/s320/100.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;N = 100 のとき。N=50付近のピークが非常に鋭くなっている。&lt;/div&gt;&lt;br /&gt;
以上より、Nを増やせば増やすほど、N/2近傍により鋭いピークが表れるようになることが確認できます。&lt;br /&gt;
&lt;h4&gt;どーいうことが言いたいのか&lt;/h4&gt;結局のところ、お手玉の数を増やせば増やすほどmは中央付近で安定するわけです。「&lt;i&gt;いや、最初に赤玉と白玉分けられているじゃん&lt;/i&gt;」それはそうなんですけど、今回の場合は無限回試行しているので、最初どのように分布してようが全く関係ないわけで。&lt;br /&gt;
&lt;br /&gt;
最初は偏っていた分布がごちゃごちゃやっている内に中央付近に移動し、そこから多少のゆらぎはあるかもしれないが、結果的に中央へと帰ってしまうような、そういうイメージです。&lt;br /&gt;
&lt;h4&gt;まとめ&lt;/h4&gt;確率を無限回にすっ飛ばしたり、ある時点での確率分布を求めたり、&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95%E9%80%A3%E9%8E%96%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3%83%AD%E6%B3%95"&gt;モンテカルロ法にも使われている&lt;/a&gt;マルコフ連鎖はとっても賢くてすごいやつという記事なのでした&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-2928879069301582444?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/6JvHxsqnoK4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/2928879069301582444/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=2928879069301582444" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2928879069301582444?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2928879069301582444?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/6JvHxsqnoK4/blog-post_9805.html" title="マルコフ連鎖を使って簡単な問題を解いてみよう" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_8d0SChK7UaQ/S7oWq62ly6I/AAAAAAAAA2c/8JvEBs98UjE/s72-c/pic.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/04/blog-post_9805.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08CSXg9eip7ImA9WxFTFEU.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-8546374013118531797</id><published>2010-04-06T01:27:00.002+09:00</published><updated>2010-04-06T01:44:28.662+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-06T01:44:28.662+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="思うこと" /><title>前のセメスターのレポートを微妙に公開してみるという話</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/e-7oJMTlgcZ18IF642goSjOBnt8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e-7oJMTlgcZ18IF642goSjOBnt8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/e-7oJMTlgcZ18IF642goSjOBnt8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e-7oJMTlgcZ18IF642goSjOBnt8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;前のセメスターで、『固有値問題』『フーリエ変換』『モンテカルロ法』を利用した問題を作成し、レポートを提出するよう求められた授業がありました。&lt;br /&gt;
&lt;br /&gt;
物理学科で『固有値問題』といいますと、普通は『時間に依存しないSchrodinger e.q.を解いて粒子の波動関数を求める』といった問題が一般的なんですが、そんな問題を解いてもみんな同じことやってるので正直つまらない。別に物理と絡めて解けと指示されたわけではありませんので、そんなら違う問題でもいーかということで自分はマルコフ連鎖を使用して、簡単な問題を解いてみるといったレポートを提出しました。&lt;br /&gt;
&lt;br /&gt;
この問題は自分で設定したんですが、正直簡単なわりになかなかきれいにできてる(うわー自画自賛)ということで、このまま埋もれたままにするのはもったいないなーと思いまして、微妙に一部分を変更して公開してみることにしました。この記事利用してレポート書いたら多分すぐにバレるし、別に問題ないかなぁと。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-8546374013118531797?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/flC3hqjVL4w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/8546374013118531797/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=8546374013118531797" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8546374013118531797?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/8546374013118531797?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/flC3hqjVL4w/blog-post_06.html" title="前のセメスターのレポートを微妙に公開してみるという話" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/04/blog-post_06.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YFSHg7cSp7ImA9WxFTFEU.&quot;"><id>tag:blogger.com,1999:blog-1062283300115822026.post-2680733069202000985</id><published>2010-04-04T23:31:00.004+09:00</published><updated>2010-04-06T02:38:39.609+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-06T02:38:39.609+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="技術情報" /><title>Bloggerにはてなスターを設置するためには(まとめ)</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fcjYEeCKmEYgsPSeXbUTM79So0A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fcjYEeCKmEYgsPSeXbUTM79So0A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fcjYEeCKmEYgsPSeXbUTM79So0A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fcjYEeCKmEYgsPSeXbUTM79So0A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;a href="http://www.hatena.ne.jp/"&gt;はてな&lt;/a&gt;のサービス『&lt;a href="http://s.hatena.ne.jp/"&gt;はてなスター&lt;/a&gt;』は、はてなダイアリーだけしか設置できない…というわけではなく、livedoor, blogger, seeseaなど、外部のブログでも導入することができます。&lt;br /&gt;
&lt;br /&gt;
Bloggerにはてなスターを導入するための具体的な方法は『&lt;a href="http://d.hatena.ne.jp/hatenastar/20070707"&gt;はてなスターをブログに設置するには&lt;/a&gt;』を参照すればすべて書いてありますが、この内容はテンプレートがクラシックなど、標準のものしか対応していません。なのでこのブログのようにいろいろとカスタマイズしているブログに設置するためには、いささか面倒な手順を踏まなければいけません。ここではBloggerでの変更手順を、上記の記事を補足する形で説明します。&lt;br /&gt;
&lt;br /&gt;
まず、はてなスターのJavaScriptは、h3タグに囲まれている内容を記事のタイトル、h3タグ内のaタグのリンク先を記事のpermalinkと推測して処理を行っています。&lt;b&gt;よって、ブログのHTML構造がその方式に従っている場合は特に変更する必要はなく&lt;/b&gt;、ただheadタグ内直下に&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;script type="text/javascript" src="http://s.hatena.com/js/HatenaStar.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript"&amp;gt;
Hatena.Star.Token = 'your-original-token';
&amp;lt;/script&amp;gt;
&lt;/pre&gt;を挿入するだけで良いです。&lt;br /&gt;
&lt;br /&gt;
しかし、h3タグの中にaタグが複数個入っている場合や、ブログタイトルにh2タグなど別のタグを使っている場合には、正解のURLを教えてあげる必要があるため、h3タグの直下に&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;h3 class='post-title'&amp;gt;
&amp;lt;a expr:href='data:post.url' style='display:none;' title='permanent link'&amp;gt;&amp;lt;/a&amp;gt;&lt;/pre&gt;とダミーのaタグを挿入し、Hatena.Star.SiteConfigにカスタマイズした辞書を入れてやります。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;また、複数のJSを使っている場合、時々JS同士が競合して正常な動作が行われない場合があります&lt;/b&gt;。筆者の場合ははてなスターのJSとGoogle AnalyticsのJSが競合してしまったために、Add Starボタンを押してもログインのダイアログが表示され、正常にスターが追加されないというエラーが生じていました(*1)。こういった場合、JavaScriptのロード順を変えることによって解決する場合があります。具体的には、このブログですとbodyタグ終了の直前に以下のようにコードを挿入することによって解決しました。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;script type='text/javascript'&amp;gt;
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
  document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
  &amp;lt;/script&amp;gt;
&amp;lt;script type='text/javascript'&amp;gt;
  try {
  var pageTracker = _gat._getTracker("your-UA-code");
  pageTracker._trackPageview();
  } catch(err) {}&amp;lt;/script&amp;gt;
&amp;lt;script src='http://s.hatena.ne.jp/js/HatenaStar.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type='text/javascript'&amp;gt;
Hatena.Star.Token = 'your-original-token';
Hatena.Star.SiteConfig = {
entryNodes: {
'div.post': {
uri: 'h3 a',
title: 'h3',
container: 'h3'
}
}
};
&amp;lt;/script&amp;gt;
&lt;/pre&gt;要はGoogle Analyticsの次にはてなスターのJSが読み込まれるように修正したわけです。以上の手順によって、はてなスターの正常な動作を確認しました。この記事が皆様のお役に立てば幸いです。&lt;br /&gt;
&lt;br /&gt;
(*1) おそらく競合の原因はクリックイベントのフックによるものと考えられます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1062283300115822026-2680733069202000985?l=mglab.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/lFRu/~4/Alx4x9qGlc8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mglab.blogspot.com/feeds/2680733069202000985/comments/default" title="コメントの投稿" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1062283300115822026&amp;postID=2680733069202000985" title="0 件のコメント" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2680733069202000985?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1062283300115822026/posts/default/2680733069202000985?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/lFRu/~3/Alx4x9qGlc8/blogger.html" title="Bloggerにはてなスターを設置するためには(まとめ)" /><author><name>rezoo</name><uri>http://www.blogger.com/profile/09706721371333005060</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://bp2.blogger.com/_8d0SChK7UaQ/SCRphOFABvI/AAAAAAAAAQc/cQg8HR1aEkc/S220/top.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://mglab.blogspot.com/2010/04/blogger.html</feedburner:origLink></entry></feed>

