|
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
|
Javaで作成する多次元配列操作ライブラリはじめにパーソナルコンピューティングの世界に出現した最初のキラーアプリケーションは表計算ソフトでした。これは当然のことです。数値が詰まった表は、データを表示・分析するための最も簡単かつ有用な手法です。 数値の配列は、数値プログラミングの基礎です。多次元配列を専門的に扱う言語(たとえば、APLや、その後継言語であるJおよびK)がいくつも作り出されたのは、驚くにあたりません。これらの言語の推進者は、配列言語を使うことで、すっきりと理解しやすいコードが書ける、と言っています。 金融プログラミングを少しでも手がけた方なら、必ず数値の多次元配列を扱っているはずです。高次元の配列はデータ構造を図式化するのも難しく、一筋縄では扱えません。コード自体も読みにくいものになりがちです。三重のネストになった、優に3画面分にも及ぶ しかし、多次元配列のメリットは否定できません。数値データ構造がたとえ扱いにくいほどの高次元配列だったとしても、すべての軸が均質であるというメリットは何物にも代えられません。つまり、配列を高次元空間で自在に回転させ、低次元のデータスライスを切り取って、それを操作し、表示できるのです。軸と軸の間に大きな違いはありませんから、どの軸の取り扱いにも同じルーチン群を使用できます。 本稿では、多次元配列用ライブラリを設計して実装し、それを使用してプログラミングを単純化する方法について考えていきます。 Genericsについてのメモ 本稿で説明するライブラリは、JDK 1.5のJava Generics機能を使用しています。むしろ、このライブラリの 私がJavaのこの機能を使ったのは、今回が初めてです。コードのあちこちで型パラメータ Cubeクラス 今回のコードの中心は、 それでは、まず Cubeの作成まずは簡単なデータで考えてみましょう。次に示すのは典型的な配列です。
Integer data[] = { 10, 20, 30 };
これを1次元の
Cube cube = new Cube( data );
図1は、この 図1 1次元Cube(1次元Cube内のデータはこのように表現できる) ![]() 私がスロット0に10、スロット1に20、スロット2に30を入れたのは偶然です。データを一様にして、それに何が起こるかを見やすくしたかっただけですが、現実にはさまざまなデータが入るはずです。 データの変更 Cube r = cube.reverse(); これにより、図2のような新しい 図2 反転したCube(図1のデータを反転させると、このCubeが得られる) ![]() ここで「新しい マップ操作 マップとは、ある関数をリスト中のすべての要素に適用する操作を言います。マップの結果として得られるものは、毎回の関数コールから得られた出力のリストです。たとえば、 Cube d = cube.map( doubler ); 図3 2倍化したCube(図1のCubeの値を2倍化した結果を示している) ![]() ところで、この Fun doubler = new Fun<Integer>() { public Integer apply( Integer n ) { return n * 2; } }; フォールド操作 フォールド(折り畳み)も、多次元配列に対して行える便利な操作です。マップがN次元配列を受け取ってN次元配列を返したのに対し、フォールドはN次元配列を受け取って(N−1)次元配列を返します。つまり、ある次元に沿って 例を示しましょう。最初の
Integer data[] = { 10, 20, 30 }
Cube cube = new Cube( data );
int sum = cube.fold( plus, 0 );
フォールドの結果(10+20+30=60)が、整数型の変数 先ほどの例では int sum = 0; // 0 sum = plus( sum, 30 ); // 30 = 0+30 sum = plus( sum, 20 ); // 50 = 20+30 sum = plus( sum, 10 ); // 60 = 10+50 つまり、このコードは
int sum = plus( 10, plus( 20, plus( 30, 0 ) ) );
あるいは、+演算子を使えば、次のようになります。
int sum = 10 + (20 + (30 + 0));
フォールドの長所は、いろいろな関数を使い分け、いろいろな結果を得られることです。たとえば、和でなく積が欲しいときは、
Integer data[] = { 10, 20, 30 }
Cube cube = new Cube( data );
Integer product = cube.fold( times, 1 );
このコードからは、 Fun2 plus = new Fun2<Integer>() { public Integer apply( Integer a, Integer b ) { return a + b; } }; Fun2 times = new Fun2<Integer>() { public Integer apply( Integer a, Integer b ) { return a * b; } }; 少々長ったらしい定義であることは否定できませんが、再使用可能であるのが最大のメリットです。こうしたマップやフォールドを行うプロセスをいくつも定義し、ライブラリを作っておけば、コード中で必要なものを名前で参照できます。 左フォールドと右フォールドフォールドには、上記の方法しかないわけではありません。実は、左フォールドと右フォールドという2通りの方法があります。 先ほど説明したのは右フォールドでした(
Integer data[] = { 10, 20, 30 }
Cube cube = new Cube( data );
int sum = cube.foldr( plus, 0 );
次の操作と同じです。 int sum = 10 + (20 + (30 + 0)); // 60 一方、左フォールド(
Integer data[] = { 10, 20, 30 }
Cube cube = new Cube( data );
int sum = cube.foldl( plus, 0 );
これは、次のようにするのと同じことです。 int sum = ((0 + 10) + 20) + 30; // 60 もちろん、加算なら、左フォールドでも右フォールドでも結果は同じになります。加算は結合的演算であり、
Float data[] = { 10F, 20F, 30F, 40F };
Cube cube = new Cube( data );
float sum_right = (Float)cube.foldr( dividedby, 1F );
float sum_left = (Float)cube.foldl( dividedby, 1F );
このコードでは、 次元の追加 これまで扱ってきたのは1次元配列でした。簡単ですが、あまりおもしろくありません。そこで、もっとデータを追加してみることにします。2次元
Integer data[][] = { { 1010, 1020, 1030 },
{ 2010, 2020, 2030 },
{ 3010, 3020, 3030 } };
Cube cube = new Cube( data );
この2次元 図4 2次元Cube(この図は、2次元Cube内のデータを表現している) ![]() マップ操作は、2次元配列でも1次元配列と同じように実行できます。図4の2次元 図5 2倍化した2次元Cube(1次元Cubeの場合と同じ要領で、2次元Cubeにも2倍化が適用される) ![]() フォールド操作も、2次元配列に対して支障なく実行できます。フォールドでは次元数が1つ減ることを思い出してください。1次元配列
Cube f = cube.fold( ’plus’, 0 );
このフォールドでは、図6に示すとおり1列の値が得られます。 図6 折り畳まれた2次元Cube(フォールドは多次元Cubeにも適用できる) ![]() 軸の操作高次元の配列では、軸を動かすと便利なことがあります。たとえば、上の2次元配列の軸を交換したくなったとします。つまり、図4の配列を図7の配列のようにしたいとします。できるでしょうか。 図7 軸の交換(図4の2次元Cubeの軸を交換するとこうなる) ![]() 答えは簡単です。次のようにして、2つの軸を入れ替えるだけです。
int permutation[] = { 1, 0 };
Cube pcube = cube.permuteAxes( permutation );
マップとフォールドは強力な操作です。その力の源泉は、計算の実行方法を記述せず、データをたどっていく順序だけを記述するという点にあります。計算方法自体は、 データをたどる順序と計算方法とを分離することが、関数的プログラミングの基本です。これは、アスペクト指向プログラミングで言う「関心事の分離」という考え方にも通じます。本稿で述べたマップとフォールドは初歩中の初歩です。あとはご自分で新しい関数を作成し、データ構造を縦横にマップし、フォールドしてください。 著者紹介Greg Travis(Greg Travis)
ニューヨーク在住のJavaプログラマ兼テクノロジーライター。ハイエンドPCゲーム業界で3年間を過ごした後に、EarthWebに参加し、当時最新鋭のJavaプログラミング言語を用いた新規テクノロジーを各種開発。1997年以降は、さまざまなWebテクノロジーについてのコンサルタントを務める。
関連記事 関連テーマ 最新トップニュース
|
japan.internet.com 10周年記念
インターネットコムマーケティングセミナー ROI を最適化するパフォーマンスマーケティングの最前線 【12/16(水)13時〜 東京・赤坂】 申込はコチラ>>
|