Mathematica の Open XM 化について

小原功任

November 25, 1999 (Revised July 20, 2005)

1 我々が提供するもの

我々が提供するのは二つのプログラムとそのソースである。一つ目は ox math プログラムであり、これは OpenXM サーバの一種である。二つ目は math2ox であり、 OpenXM クライアントである。

動作環境は Solaris, Linux および Windows、対象としている Mathematica のバージョンは、 3.0 〜 4.2 までである。バージョン 5.x については、我々が所有していないため調査していない。

Windows 上では ox math は、 cygwin のもとで動作する。 ox math の Windows 対応は藤本さんによる (2002 年 4 月)。ありがとう。

2 Open Mathematica サーバの構成

Open Mathmatica サーバ (ox math) は Open XM クライアントおよび Mathematica Kernel と通信する。 ox math は起動直後に Mathematica Kernel を起動し、 Mathematica Kernel と協調して動作する。 Mathematica Kernel とは MathLink ライブラリを利用して通信する。つまり ox math は MathLink のラッパだと思ってよい。 Open XM クライアントとの間はソケットを利用して通信する。 ox math はファイルディスクリプタ 3,4 が既にオープンされていると思って, 3 から読み込み、 4 に書き出す。

さらに ox math には計算中断機能が必要であるが、この機能は 2003 年のはじめに実装された。

次に、 Open XM 規約より ox math はスタックマシンでなければならない。スタックのオブジェクトは cmo 型の変数、あるいはその派生クラスである. つまり、 Open XM 規約で定められたデータ形式を流用している. この方法の利点は Open XM プロトコルを通して通信するにあたって特にデータの変換を必要としないことである. すなわち CMO の各データタイプは ox math の内部でも, CMO として保持するわけである.

サーバの各関数は cmo* を受け取り、タグをみて実際のクラスが何であるかを知り、動作を決定する.

現在、実装されているスタックマシン命令は SM popCMO, SM popString, SM pops, SM executeFunction, SM executeStringByLocalParser, SM mathcap, SM setMathcap(受け取るだけで何もしない) である。

3 MathLink プログラミングと ox math

最初に、 MathLink プログラミングについての基礎的事項を説明し、次に ox math の Mathematica Kernel との通信部分について述べる。

MathLink プログラミングについては、概ね、 Mathematica Book [4] や宮地 [5] などを参照すればよいが、必ずしもこれらの書籍に明確に書かれているわけではない (探せば見つかるが)。

まず MathLink とは、 Wolfram が提供するライブラリであり、 Mathematica のネットワーク対応部分に相当する。 Mathematica Kernel と通信するプログラムを書こうとするならば、 MathLink を利用する必要がある。 MathLink の内部構成は明らかにされていないが、大部分はネットワーク透過的である (例外はある)。

まず、 MathLink の通信路で交換されるデータが何なのか、ということを理解する必要がある。答は Mathematica の式である。これは自明ではない。次のような式がその例である。

    EvaluatePacket[Sin[\$VersionNumber]]
    ReturnPacket[Sin[x]]
    InputNamePacket["In[1]:= "]
    MenuPacket[1,"Interrupt> "]

このような *Packet[] を [4] ではパケットと呼んでいる. MathLink を用いて、確実なプログラミングをするためには、これらのパケットを正しく扱う必要がある。

さて、 Mathematica Kernel の起動および通信路の確立については省略する。いったん、通信路が確立されたら、

1. Mathematica Kernel に式を送る。

2. Mathematica Kernel から式を受け取る。

を繰り返すのが MathLink でのプログラミングである。

ox math は Mathematica と以下のような意味で文字列ベースで通信している。まず Mathematica Kernel に評価させたい式が、 C 言語の文字列で与えられているとして、 link で指し示す Mathematica Kernel に

int ml_evaluateStringByLocalParser(char *string)
{

    MLPutFunction(link, "EvaluatePacket", 1);
    MLPutFunction(link, "ToExpression", 1);
    MLPutString(link, string);
    MLEndPacket(link);
}

として送信する。パケットは、 EvaluatePacket[ToExpression[string]] である。ここで ToExpression は Mathematica の組み込み関数であり, 文字列 string を引数として Mathematica の式を返す. ([4, pp.407])

評価された結果を配列 str に格納するには、単純には次のようになる。

int receive_sample(char str[])
{
    while (MLNextPacket(link) != RETURNPKT)
        MLNewPacket(link);
    switch(MLGetNext(link)) {
    MLTKSTR:
        MLGetString(link, &str);
        ...
    MLTKINT:
        ...
    }
    MLNewPacket(link);
}

この例では ReturnPacket[] 以外を無視しているが、実際にはこんなに単純には書けない。 ox math の実装では、 mlo.c の ml next packet(), ml new packet(), ml read packet(), ml read returnpacket(), ml read menupacket(), ml read textpacket() などを見てほしい。

文字列によらず、 CMO を送ることもできる.

ox math は, CMO を次の規則で MathLink のオブジェクトに変換する.

CMO INT32  → MLTKINT,
CMO STRING → MLTKSTR,
CMO LIST  → MLTKFUNC,
その他の CMO → ToExpression[文字列]

逆に MathLink のオブジェクトは次の規則で CMO に変換される.

MLTKERR → CMO ERROR2,
MLTKINT  → CMO ZZ,
MLTKSTR → CMO STRING,
MLTKREAL → CMO IEEE DOUBLE FLOAT,
MLTKSYM → CMO STRING,
MLTKFUNC → CMO LIST

この変換規則は明らかに可逆でないので注意.

CMO ZZ をもとに実装を説明しよう. まず, MLTKINT は多倍長整数型であるが, MathLink の内部データ構造が公開されていないため, CMO ZZ (あるいは GNU GMP library の整数) を直接 MLTKINT に変換することはできない. つまり CMO ZZ が整数型であると MathLink に知らせることはできない. そこで, 次のような方法をとることになる.

export MLINK link;
int ml_send_cmo_zz(cmo *m)
{
    MLPutFunction(link, "ToExpression", 1);
    MLPutString(link, new_string_set_cmo(m));
}

このようにすると, Mathematica 側では, 例えば ToExpression[”1234567890”] の評価が行われ, 文字列データから整数 1234567890 が復元される.

逆に, Mathematica から送られた多倍長整数は, マシン整数の範囲内であれば, int として取得可能 (MLGetInteger を使う) であるが, 受け取る前に int に収まるか否かを知ることはできない. int に収まらない場合、データが切り捨てられてしまうので注意が必要である. また, 直接 CMO ZZ として取得することも不可能である. (MathLink 上でどのような形式でデータ交換されているのかの情報は手元にある資料からは得られなかった)

しかしながら, たとえ Mathematica 側から整数データが送られていたとしても, そのデータを文字列に変換して受け取ることは MathLink の機構上可能である.

これを利用して, 我々は次のようにして整数を受け取る.

export MLINK link;
cmo_zz* ml_receive_cmo_zz()
{
    cmo_zz *zz = NULL;
    if(MLGetNext(link) == MLTKINT) {

        char *s;
        MLGetString(link, &s);
        zz = new_cmo_zz_set_string(s);
        MLDisownString(link, s);
    }
    return zz;
}

つまり、 Mathematica から整数を文字列として受け取り、その文字列を ox math が CMO ZZ に直している。

4 ox math への計算中断機能の実装

注意: ox math interruption.tex に Risa/Asir Conference (2003) での講演原稿がある.

OpenXM プロトコルは、エンジンに対して、計算中断機能を要求する。 ox math のような wrapper プログラムでは、そのような機能を実装するのは一般には難しいが、 MathLink には Mathematica Book [4] に書かれていない機能があり ([6], [7], [8])、そのひとつを用いて、 ox math に計算中断機能を実装した。この節では、その実装について説明する。

Mathematica Kernel に対する割り込みは、

1. MLPutMessage で Mathematica Kernel に MLInterruptMessage を送る。

2. 通信路の後始末を行い、最終的に ReturnPacket[$Aborted] を受け取る。

ことでなされる。 MLPutMessage は MathLink の非公開関数でネットワーク透過性はない。 Unix と Windows では異なるが、 Unix の場合、 MLInterruptMessage の実体は SIGINT である。通信路の後始末には、 Mathematica Kernel のバージョン依存性があるので、それを回避すると、結局、次の手順になる。

1. MLPutMessage(link, MLInterruptMessage)

2. MenuPacket[1,”Interrupt¿ ”] を受け取れば計算が中断されている

3. MLPutString(link, ”\n”)

4. MenuPacket[0,”Interrupt¿ ”] を受け取る

5. MLPutString(link, ”a”)

6. TextPacket[”...”] を受け取る 7. EvaluatePacket[0] を送って、 ReturnPacket[...] をふたつ受け取る。最

初のものが ReturnPacket[$Aborted] である。

最後の手順を説明する。ここで、 ReturnPacket[$Aborted] が素直に返ってくればいいのであるが、バージョン 3.x では返ってくるのに、バージョン 4.x では、何故か、返ってこず、次の計算を行うとき、ふたつまとめて返ってくる。よって、ダミーに EvaluatePacket[0] を送るのである。

5 Mathematica を OX のクライアントに

OpenXM クライアントは Mathematica の外部プログラム (math2ox) の形で実現されている。すなわち、 Mathematica と math2ox の間は MathLink プロトコルで、 math2ox と OpenXM サーバの間は OpenXM プロトコルで通信し、 math2ox が適切に情報を変換しながらやりとりする。その意味で wrapper の一種であるとも言える。

利用するには、最初に

In[1]:= Install["math2ox"]

として、 math2ox をロードしなければならない。 Mathematica に新たに定義されるコマンドは、

OxStart[s String], OxStartInsecure[s String, p Integer, q Integer],
OxStartRemoteSSH[s String, host String],
OxExecuteString[id Integer, s String], OxParse[id Integer, s String],
OxSendMessage[id Integer, s String], OxGet[id Integer],
OxPopCMO[id Integer], OxPopString[id Integer],
OxClose[id Integer], OxReset[id Integer]

の 11 個である。 math2ox をロードしたら、

In[2] := pid = OxStart["ox_sm1"]

によって OpenXM サーバに接続する。この場合の接続先は ox sm1 である。返り値 pid は、セッション番号である。もちろん

In[2] := pid = OxStartInsecure["water.s.kanazawa-u.ac.jp", 1300, 1400]

のようにして、 insecure モードで接続してもよい。ただしこの場合は、あらかじめ Run[] 等で、 OpenXM サーバを起動しておかなければならない。

接続が成功したらデータを送ってみよう。

In[3] := OxParse[pid, "(CMO_LIST, (CMO_STRING, "hello world"), (CMO_ZERO))"]

のように CMO expression を指定することによって、任意の CMO を送信できる。正しくない CMO の場合には、何も送信されない。また、 CMO ではなく、

In[4] := OxParse[pid, "(OX_COMMAND, (SM_popCMO))"]

などとして、 OX メッセージの形で記述することもできる。注意しなければならないのは、 SM コマンドの場合、 OX スタックマシンから OX メッセージが送られてくる場合があるが、 OxParse[] を用いた場合、このメッセージは自動的には受信しない (現在の仕様では)。したがって明示的に受信する必要がある。そのためには

In[5] := OxGet[pid]

とするだけでよい。返ってくるオブジェクトは CMO に対応するものである。

In[6] := OxPopCMO[pid]

を用いる場合にはもちろん OxGet[pid] を呼び出す必要はない。

計算を実行するには OxExecute[pid, ...] (SM executeStringByLocalParser) か、適切な OX メッセージを送信すること。

計算が終わったら、

In[7] := OxClose[pid]

とすると、接続が終了する。

A 付録

GMP における “整数型” mpz t はつぎのような内部表現を持つ:

まず mpz t 型は
typedef struct __mpz_struct mpz_t[1];

と typedef されており, mpz t 型の変数は (関数の仮引数でない限り) 配列の扱いである. また,

typedef unsigned long int mp_limb_t;

と宣言されている場合には, 変数 mpz t x の x-> mp d が unsigned long int の配列であり, データの実体である. これは整数の最下位 4 バイトが配列の先頭にくる. つまり全体としては “リトルエンディアンっぽい” が, 各 unsigned long int はマシンのネイティブな integer である. つまり, GMP の内部表現はマシン依存となっている.

参考文献

[1] 野呂正行, 高山信毅. Open XM の設計と実装 — Open message eXchange protocol for Mathematics, November 22, 1999, Revised March 4, 2005.

[2] 小原功任, 高山信毅, 野呂正行. Open asir 入門, 1999, 数式処理, Vol 7, No 2, 2–17. (ISBN4-87243-086-7, SEG 出版, Tokyo).

[3] ウルフラム. Mathematica (日本語版), アジソンウエスレイ, 1992.

[4] Stephen Wolfram. The Mathematica Book, Third edition, Wolfram Media/Cambridge University Press, 1996.

[5] 宮地力. Mathematica によるネットワークプログラミング, 岩波コンピュータサイエンス, 岩波書店, 1998.

[6] Todd Gayley. [mg17015] in MathArchive, 1999 April.

[7] 昔の MathLink にあった MLSignal の解説. (以前、 Google のキャッシュにあったが、もうない)

[8] mathlink.h, libMLa のシンボル表, mprep の生成するソース.