NAG LibraryルーチンのJavaからの呼び出し

テクニカルレポート

Javaから数値計算トップ | Example1 | Example2 | Example3 | Example4 | Example5 | Example6

NAG Technical Report TR 2/09

Mick Pont, Anna Kwiczala
Numerical Algorithms Group, April 2009

(このレポートはNAG Technical Report TR1/04 (NP3658)に代わるものである)

概要

このレポートはJavaプログラミング言語からNAG C, Fortran Library中のルーチンをどのようにコールするかについて詳細を記述するものである。UNIX及びWindowsプラットフォーム上で動作するJavaを用いた用例を示す。

目次

  1. 動機
  2. Java Native Interface
  3. インタフェースライブラリの使用
  4. 用例
  5. インタフェースの構築
  6. 参照文献

1. 動機

NAG C Library [1]NAG Fortran Library [2] にはパッケージの開発者にとって有用な数多くの数学、統計関連ルーチンが含まれている。カバーされている領域には線形代数、最適化、積分、微分方程式、回帰分析、時系列分析などがある。これらはCあるいはFortranで記述されているが、ライブラリの機能はC++を含む他の言語からアクセスでき、またPC上においてはDLL版のライブラリがさまざまな形で利用できる [3]。となればJavaプログラミング言語 [4] から NAG Libraries がコールできないかという疑問が湧いても不思議はない。

数値計算を実行する必要性のある人にとって一つのアプローチは、必要とされる機能を実装したJavaクラスを作成する方法である。新たにコードを書いたり、他言語で書かれた既存のコードをJavaに変換したりして、この方向で進展を図っているグループの一つに Java Grande ForumNumerics Working Group がある。JavaNumerics のwebページ [5] には、現状のJavaから課される制約により数値計算にJavaを使用することの難点等、多くの有用な情報が記載されている。

本レポートにおいてはJavaから直接 NAG Libraries をコールするというもう一つのアプローチを取ることにする。これによってコードを新たに書いたり書き換えたりといった作業や、それに伴うテスト作業を回避することができる。もちろん NAG Libraries のコールを提案するわけであるため、Java単独で書かれたときのようなポータビリティ(移植性)はアプリケーションから期待できなくなる。NAG Library のマシン依存の実装が実行時に存在していることが前提となるからである。しかしほとんどの商用機において NAG Libraries が利用できるという意味においては、依然ポータビリティは維持されているとも言える。

Java版の数値計算ルーチンを書かなくても良いという点の他に、NAG Libraries を利用するというアプローチには別の利点もある。そもそもJavaはポータブルであるように設計されている。すなわちコンパイルされたプログラムは Java Virtual Machine(VM: 仮想計算機)の実装を持つ任意の計算機上で動作する。これを実現するために、JavaコンパイラはCやC++といった伝統的な言語のようにマシン依存のアセンブラコードを生成するわけではなく、マシン非依存のバイトコードを生成する。このバイトコードはVMによって解釈され実行される。このJavaインタプリータは効率的に作られてはいるが、アセンブラコードに展開された場合に比べると実行性能の劣化は避けられない。多くのプログラムにとってこれは問題にはならないが、大量のデータに対し多くの演算操作を必要とするアプリケーションにとっては深刻な問題となることがある。これらの演算操作をJavaからはずし NAG Libraries 側に移すことによって、実行時間の短縮が期待できるようになる。

Javaプログラムから NAG Libraries にアクセスするためには Java Native Interface を利用する。

2. Java Native Interface

Javaのソフトウェア開発者用キット(Java Software Development Kit (SDK))の一部として提供される Java Native Interface (JNI) には、Javaプログラムからネイティブコードをコールしたい人向けのコンパイル時、及び実行時支援機能が含まれている。ここで言うネイティブコードとはCやC++等で書かれたJava以外のコードのことを意味するが、本レポートではCを仮定する。

コンパイル時、JNI はJavaのデータタイプをCのデータタイプに対応させる際の様式を規定する。Cプログラムはこの情報をJNIヘッダファイル(Java SDKに含まれる)から取得する。SDKによって提供されるツール javah は、JavaとCルーチン間での交信時のトラブル回避を企図したアプリケーション固有のヘッダファイルの作成を支援する。

実行時、JNI はJavaオブジェクトをCコードに引渡したり、CコードからJava属性(properties)やメソッド(methods)へのアクセスすることを可能にする。これによって例えば、Cコード側からJavaクラスの属性をセットしたり、CからJavaメソッドをコールしたりといった操作が可能となる。

本レポートの作成に当り、コードのテストは次の2機種上で行われた。

  • 64-bit Fedora 8 (Werewolf) を搭載したLinuxマシン。Java SE Development Kit v1.6.0u11, gcc (GCC) 4.2.3, GNU Fortran (GCC) 4.2.3, NAG C Library の Mark 9 プレリリース版、NAG Fortran Library Mark 22 を含む。
  • Windows XP を搭載したPC。Java SE Development Kit v1.6.0u11, Microsoft Visual C++ v9.0, NAG C Library の Mark 9 プレリリース版、NAG Fortran Library Mark 22 を含む。

他のUNIX系プラットフォームについてはLinux x86と同様のはずである。Javaインクルードファイルの位置と共用オブジェクト(動的ライブラリ)の作成方法において違いが見られる可能性がある。

Java Native Interface に関する技術紹介については Sun Microsystems のwebサイト [6] を参照されたい。

3. インタフェースライブラリの使用

JNI を使用すると媒介的な共用ライブラリ(UNIX系)、またはDLL(Windows系)が生成される。このライブラリはJavaコードと NAG C Library コード間のインタフェースとして機能する。

Javaからネイティブなメソッド(関数、またはサブルーチン)がコールされた場合、ネイティブルーチンの引数リストの前に追加の引数を付加するために、このインタフェースライブラリが必要になる。これらの追加の引数によって ネイティブコードからのJavaメソッドや属性へのアクセスが可能になる。しかし当然のことながら NAG Libraries はこれらの引数を扱えるようには設計されていない。またJavaから引渡される引数のタイプは標準のCやFortranのタイプに対応しているとは限らないため、NAG Libraries がそれらを直接使用できるわけではない。インタフェースライブラリはこれらの問題に対処するためのもので、独自に NAG Library をコールした上で結果をJavaに送り返す。

JNI
JavaとNAG Library間を仲介するJava Native Interface

Javaから NAG Library へのコールは3段階のプロセスによって実装される。

  1. Java中でネイティブメソッドに対する宣言を記述する。その宣言中には、それがJava外で実装されていることをコンパイラに指示するためのキーワード native を含める。
  2. ネイティブ(C)コードで使用するヘッダファイルを作成する。このヘッダファイルにはネイティブメソッドに対するCコンパイラから見たときの宣言を含める。その中にはCの関数がJavaメソッドや属性をアクセスする際に必要となる追加引数や、標準的なCのタイプによって定義された引数タイプの規定が含まれる。
  3. ネイティブメソッドをCで実装する。この関数は上で作成されたヘッダファイルを用い NAG C または Fortran Library へのコール、あるいはJavaメソッドへのコールバックを行い、結果をJavaに返す。このCコードがコンパイルされインタフェースライブラリを構成することになる。ただしこのコードは NAG Fortran Library を使う場合であってもCで実装されている点に注意。上記の追加引数の構造から、この“グルー(glue)”コードをFortranで記述することができないからである。

インタフェースライブラリができた段階では、インタフェースライブラリ自体はマシン依存であっても、それを利用するJavaコードは依然マシン独立である。インタフェースライブラリは種々のプラットフォームごとに開発されなくてはならないが、それを利用するJavaコードの編集や再構築は必要ない。

4. 用例

インタフェースライブラリを作成するプロセスは具体例を見ることによって簡便に学習できる。ここでは JNI の使用に関する種々の側面を持った6種類の用例を示す。

4.1 Example 1  ベッセル関数 Y(x)

Example1 Bessel 最も単純な例である。ただ一つの戻り値を持つ関数をコールする。使用するのは NAG C Library からの Y(x) ベッセル関数ルーチン s17acc である。戻り値が一つだけの場合には特別なコードは必要ない。

4.2 Example 2  連立1次方程式 A x = b の解法

lineq 配列を応答として返す関数、具体的には連立1次方程式ソルバ f04arc をコールする。JavaからCにデータを渡し、結果をCからJavaに返すために追加のコードが必要になる。

4.3 Example 3  ユーザ提供関数 f(x) の定積分値の計算

Example3_Quad 引数の一つとして関数を取る関数をコールする。使用するのは NAG C Library 中の積分ルーチン d01ajc である。この場合には被積分関数の値を計算するためにCコードからJavaメソッドをコールバックする必要が生じる。また結果をJavaに返す際にJavaのクラス属性をどのように修正するかについても示す。

4.4 Example 4  非線形の最小化問題の解法

Example4_Minimization この用例では NAG Fortran Library 中の非線形最小化ルーチン e04ucf をコールする方法を示す。この場合、Cで書かれたインタフェースコードはFortranをコールし、さらにはFortranからCを経由してJavaに至るコールバックを扱う必要が生じる。またFortranが2次元配列をどのように格納しているかについても考慮する必要がある。

4.5 Example 5  Black-Scholes-Merton公式による欧州オプション価格の計算

Example5_Price 応答として配列を返す関数であるオプション価格公式 s30aac を用いた例を示す。

4.6 Example 6  大域的最適化問題の解法

Example6_Optimization 大域的最適化のための NAG Fortran Library ルーチン e05jbf をコールする方法を示す用例である。

5. インタフェースの構築

上記の用例をすべて学べば、Javaと NAG C, Fortran Libraries 間での情報受渡しに関する基本技術については習得できたことになる。これらの技術を使い、そして恐らくはここで紹介したソースコードの一部を再利用することによって、NAG Library 中に含まれるその他数多くのルーチンに対するインタフェースの作成が可能なはずである。単に整数コードの応答を返すに留まらず、NAGルーチンの実行が正常に行われなかったときにJavaに対しエラーメッセージを返すといったインタフェースの拡張も比較的容易に対応できるものと思われる。

Cで書かれたインタフェースライブラリから NAG Fortran 77 Library ルーチンをコールしやすくするためのヘッダファイル [7] がNAGより提供されている。

また、上記の用例、及びその他のNAGオプション価格ルーチンに伴うソースコード一式をダウンロードすることもできる(zipファイル形式)。
NAG Fortran ルーチンのコール: fortran_examples.zip
NAG C ルーチンのコール: c_examples.zip

参照文献


Copyright 2009 Numerical Algorithms Group
[NP3671]


関連情報
MENU
Privacy Policy  /  Trademarks