%#!platex %% $OpenXM: OpenXM/src/ox_math/documents/ox_math.tex,v 1.8 2005/07/19 15:58:37 ohara Exp $ \documentclass{jarticle} \title{Mathematica の Open XM 化について % \\ {\small --- Open Mathematica サーバの内部構成 ---} } %\date{January 19, 1999} %\date{July 12, 1999} \date{November 25, 1999\\ (Revised July 20, 2005) } \author{小原功任} \def\oxmath{{\tt ox\_math}} \begin{document} \maketitle \noindent {\bf 注意 (2002.04.17): この文書は, 古いインタフェースをもとに記述してあるので, 例はこのままでは動作しないので注意. math2ox.texi が最新のインタフェースのマニュアルである. 一番の変更点は, {\tt OxStart} が pid (ox process id) を戻すようになり, {\tt OxParse} など多くの関数が, pid を引数として求めるようになったことで ある. たとえば, この文書の {\tt OxParse} を用いる例は, 次のように変更しないと いけない.} \begin{verbatim} Install["math2ox"] pid = OxStart["ox_sm1"] OxParse[pid,"(CMO_ZERO)"] OxPopCMO[pid] \end{verbatim} \section{我々が提供するもの} 我々が提供するのは二つのプログラムとそのソースである。一つ目は \oxmath プログラムであり、これは OpenXM サーバの一種である。二つ 目は {\tt math2ox} であり、OpenXM クライアントである。 動作環境は Solaris, Linux および Windows、対象としている Mathematica の バージョンは、3.0 〜 4.2 までである。バージョン 5.x については、我々が所 有していないため調査していない。 Windows 上では \oxmath は、cygwin のもとで動作する。\oxmath の Windows 対応は藤本さんによる(2002年4月)。ありがとう。 \section{Open Mathematica サーバの構成} Open Mathmatica サーバ(\oxmath)はOpen XM クライアントおよび Mathematica Kernel と通信する。\oxmath は起動直後に Mathematica Kernel を起動し、 Mathematica Kernel と協調して動作する。Mathematica Kernel とは MathLink ライブラリを利用して通信する。つまり \oxmath は MathLink のラッパだと思ってよい。Open XM クライアントとの間はソケットを利用して通 信する。\oxmath はファイルディスクリプタ 3,4 が既にオープ ンされていると思って, 3 から読み込み、4 に書き出す。 さらに \oxmath には計算中断機能が必要であるが、この機能は 2003年のはじめに実装された。 \section{OX スタックマシン} スタックのオブジェクトは cmo 型の変数、あるいはその派生クラスである. つまり、Open XM 規約で定められたデータ形式を流用している. % cmo 構造体およびその派生クラスは/home/ohara/openxxx/lib/oxlib.h で定義さ % れている. この方法の利点は Open XM プロトコルを通して通信するにあたって 特にデータの変換を必要としないことである. すなわちCMO の各データタイプ は Open Mathematicaサーバ(スタックマシン)の内部でも, CMO として保持する わけである. サーバの各関数は cmo* を受け取り、タグをみて実際のクラスが何であるかを 知り、動作を決定する. \section{MathLink プログラミングの基礎知識} ここでは、MathLink についての基礎的事項を説明する。概ね、Mathematica Book~\cite{Wolfram-1996} や宮地~\cite{miyachi-1998} などを参照すればよい が、必ずしもこれらの書籍に明確に書かれているわけではない(探せば見つかる が)。 まず MathLink とは、Wolfram が提供するライブラリであり、Mathematica のネッ トワーク対応部分に相当する。Mathematica Kernel と通信するプログラムを書 こうとするならば、MathLink を利用する必要がある。MathLink の内部構成は明 らかにされていないが、{\bf 大部分はネットワーク透過的}である(例外はある)。 まず、MathLink の通信路で交換されるデータが何なのか、ということを理解す る必要がある。答は{\bf Mathematicaの式}である。これは自明ではない。 次のような式がその例である。 \begin{verbatim} EvaluatePacket[Sin[\$VersionNumber]] ReturnPacket[Sin[x]] InputNamePacket["In[1]:= "] MenuPacket[1,"Interrupt> "] \end{verbatim} このような *Packet[] を \cite{Wolfram-1996}ではパケットと呼んでいる. MathLink を用いて、確実なプログラミングをするためには、これらのパケット を正しく扱う必要がある。 さて、Mathematica Kernel の起動および通信路の確立については省略する。 いったん、通信路が確立されたら、 \begin{enumerate} \item Mathematica Kernel に式を送る。 \item Mathematica Kernel から式を受け取る。 \end{enumerate} を繰り返すのが MathLink でのプログラミングである。 \oxmath は Mathematica と以下のような意味で{\bf 文字列ベース}で通信して いる。まず Mathematica Kernel に評価させたい式が、C 言語の文字列で与えら れているとして、link で指し示すMathematica Kernel に \begin{verbatim} int ml_evaluateStringByLocalParser(char *str) { MLPutFunction(link, "EvaluatePacket", 1); MLPutFunction(link, "ToExpression", 1); MLPutString(link, str); MLEndPacket(link); } \end{verbatim} として送信する。パケットは、 EvaluatePacket[ToExpression[{\it str}]] である。 評価された結果を配列 str に格納するには、単純には次のようになる。 \begin{verbatim} int receive_sample(char str[]) { while (MLNextPacket(link) != RETURNPKT) MLNewPacket(link); switch(MLGetNext(link)) { MLTKSTR: MLGetString(link, &str); ... MLTKINT: ... } MLNewPacket(link); } \end{verbatim} この例では ReturnPacket[] 以外を無視しているが、実際にはこんなに単純には 書けない。\oxmath の実装では、mlo.c の ml\_next\_packet(), ml\_new\_packet(), ml\_read\_packet(), ml\_read\_returnpacket(), ml\_read\_menupacket(), ml\_read\_textpacket() などを見てほしい。 \section{Mathematica との通信(MathLink) について} CMO は 次のように変換されてから, MathLink を通して送られる. \begin{enumerate} \item CMO\_INT32 は MLTKINT (多倍長整数型). \item CMO\_STRING は MLTKSTR (文字列型). \item CMO\_LIST は MLTKFUNC (関数型). \item その他のタイプの CMO は ToExpression[文字列] として送る. \end{enumerate} 上で述べられている ToExpression は Mathematica の組み込み関数であり, 文字列を引数として Mathematica の式を返す. (\cite[pp.407]{Wolfram-1996}) ここで一つ注意をしておく. MathLink では, int 型以外のデータを MLTKINT として送ることは残念ながらで きない. したがって CMO\_ZZ を直接, 整数型であると Mathematica に思わせ ることはできないのである. そこで, 次のような方法をとることになる. \begin{verbatim} char *CONVERT_ZZ_TO_CSTRING(cmo_t zz); int main() { char *s; cmo_t zz; /* zz.tag == CMO_ZZ */ MLINK lp; /* MathLink Socket */ ... s = CONVERT_ZZ_TO_CSTRING(zz); MLPutFunction(lp, "ToExpression", 1); MLPutString(lp, s); ... } \end{verbatim} このようにすると, Mathematica 側では, 例えば \[ \mbox{\tt ToExpression["1234567890"]} \] という評価が行われ, 文字列データから整数が復元される. 逆に, Mathematica から送られた整数データは, マシン整数の範囲内であれば, int として取得可能(MLGetInteger を使う)であるが, 受け取る前に int に収ま るか否かを知ることはできない. int に収まらない場合、データが切り捨てられ てしまうので注意が必要である. また, 直接 CMO\_ZZ として取得することも不 可能である. (MathLink 上でどのような形式でデータ交換されているのかの情 報は手元にある資料からは得られなかった) しかしながら, たとえ Mathematica 側から整数データが送られていたとしても, そのデータを文字列に変換して受け取ることは MathLink の機構上可能である. これを利用して, 我々は次のようにして整数を受け取る. \begin{verbatim} cmo_t CONVERT_CSTRING_TO_ZZ(char *s); int main() { MLINK lp; char *s; cmo_t zz; ... if(MLGetNext(lp) == MLTHINT) { MLGetString(lp, &s); zz = CONVERT_CSTRING_TO_ZZ(s); /* zz.tag == CMO_ZZ */ } ... } \end{verbatim} つまり、Mathematica から整数データを文字列として受け取り、その文字列を OX サーバ側で CMO\_ZZ に直している。 基本的に MathLink では全てのデータを文字列で受け取るしか方法はない。どの ような種類のデータであるかは受け取る前に知ることはできる。データの型は、 MLTKERR(エラー), MLTKINT(整数), MLTKSTR(文字列), MLREAL(実数), MLTKSYM (シンボル), MLTKFUNC(関数) のいずれかである。このような事情で Mathematica から受け取ったデータは基本的に CMO\_STRINGとしてスタックに積 まれるので、クライアント側でその文字列の解釈をする必要がでてくる。 しかしながら、全ての MathLink オブジェクトが文字列に変換できるわけではな いので、その取り扱いには注意を要する。 まだ、実装していないが、多項式(CMO\_???\_PORINOMIAL)の扱いが難しい。 \section{個々のスタックマシン命令の実装} 現在、実装されているのは SM\_popCMO, SM\_popString, SM\_pops, SM\_executeFunction, SM\_executeStringByLocalParser, SM\_mathcap, SM\_setMathcap(受け取るだけ で何もしない)である。 \section{\oxmath への計算中断機能の実装} \noindent {\bf 注意: {\tt ox\_math\_interruption.tex} に Risa/Asir Conference (2003) での講演原稿がある.} OpenXM プロトコルは、エンジンに対して、計算中断機能を要求する。\oxmath のような wrapper プログラムでは、そのような機能を実装するのは一般には難 しいが、MathLink には Mathematica Book~\cite{Wolfram-1996} に書かれてい ない機能があり(\cite{MathSource-Google1}, \cite{MathSource-Google2}, \cite{Math-Output1})、そのひとつを用いて、\oxmath に計算中断機能を実装し た。この節では、その実装について説明する。 Mathematica Kernel に対する割り込みは、 \begin{enumerate} \item MLPutMessage で Mathematica Kernel に MLInterruptMessage を送る。 \item 通信路の後始末を行い、最終的に ReturnPacket[\$Aborted] を受け取る。 \end{enumerate} ことでなされる。 MLPutMessage は MathLink の非公開関数でネットワーク透過性はない。 Unix と Windows では異なるが、Unix の場合、MLInterruptMessage の実体は SIGINT である。 通信路の後始末には、{\bf Mathematica Kernel のバージョン依存性がある}ので、 それを回避すると、結局、次の手順になる。 \begin{enumerate} \item MLPutMessage(link, MLInterruptMessage) \item MenuPacket[1,"Interrupt> "] を受け取れば計算が中断されている \item MLPutString(link, "$\backslash$n") \item MenuPacket[0,"Interrupt> "] を受け取る \item MLPutString(link, "a") \item TextPacket["..."] を受け取る \item EvaluatePacket[0] を送って、ReturnPacket[...] をふたつ受け取る。 最初のものが ReturnPacket[\$Aborted] である。 \end{enumerate} 最後の手順を説明する。 ここで、ReturnPacket[\$Aborted] が素直に返ってくればいいのであるが、 バージョン 3.x では返ってくるのに、バージョン4.xでは、何故か、 返ってこず、次の計算を行うとき、ふたつまとめて返ってくる。 よって、ダミーにEvaluatePacket[0] を送るのである。 \section{Mathematica を OX のクライアントに} OpenXM クライアントは Mathematica の外部プログラム({\tt math2ox}) の形で 実現されている。すなわち、Mathematica と math2ox の間は MathLink プロト コルで、math2ox と OpenXM サーバの間は OpenXM プロトコルで通信し、 math2ox が適切に情報を変換しながらやりとりする。その意味で wrapper の一 種であるとも言える。 利用するには、最初に \begin{verbatim} In[1]:= Install["math2ox"] \end{verbatim} として、math2ox をロードしなければならない。 Mathematica に新たに定義されるコマンドは、 {\tt OxStart[s\_String], OxStartInsecure[s\_String, p\_Integer, q\_Integer], OxExecuteString[s\_String], OxParse[s\_String], OxGet[], OxPopCMO[], OxPopString[], OxClose[], OxReset[]} の9つである。 math2ox をロードしたら、 \begin{verbatim} In[2] := OxStart["ox_sm1"] \end{verbatim} によって OpenXM サーバに接続する。この場合の接続先は ox\_sm1 である。 もちろん \begin{verbatim} In[2] := OxStartInsecure["water.s.kanazawa-u.ac.jp", 1300, 1400] \end{verbatim} のようにして、insecure モードで接続してもよい。ただしこの場合は、 あらかじめ {\tt Run[]} 等で、OpenXM サーバを起動しておかなければならない。 接続が成功したらデータを送ってみよう。 \begin{verbatim} In[3] := OxParse["(CMO_LIST, (CMO_STRING, "hello world"), (CMO_ZERO))"] \end{verbatim} のように CMO expression を指定することによって、 任意の CMO を送信できる。 正しくない CMO の場合には、何も送信されない。 また、CMO ではなく、 \begin{verbatim} In[4] := OxParse["(OX_COMMAND, (SM_popCMO))"] \end{verbatim} などとして、OX メッセージの形で記述することもできる。 注意しなければならないのは、SM コマンドの場合、OX スタックマシンから OX メッセージが送られてくる場合があるが、OxParse[] を用いた場合、 このメッセージは自動的には受信しない(現在の仕様では)。したがって明示的に 受信する必要がある。そのためには \begin{verbatim} In[5] := OxGet[] \end{verbatim} とするだけでよい。返ってくるオブジェクトは CMO に対応するものである。 \begin{verbatim} In[6] := OxPopCMO[] \end{verbatim} を用いる場合にはもちろん {\tt OxGet[]} を呼び出す必要はない。 計算を実行するには {\tt OxExecute[]} (SM\_executeStringByLocalParser) か、適切な OX メッセージを送信すること。 計算が終わったら、 \begin{verbatim} In[7] := OxClose[] \end{verbatim} とすると、接続が終了する。 \appendix \section{付録} GMP における ``整数型'' {\tt mpz\_t} はつぎのような 内部表現を持つ: \\ まず {\tt mpz\_t} 型は \begin{verbatim} typedef struct __mpz_struct mpz_t[1]; \end{verbatim} と typedef されており, {\tt mpz\_t} 型の変数は(関数の仮引数でない限り)配列の 扱いである. また, \begin{verbatim} typedef unsigned long int mp_limb_t; \end{verbatim} と宣言されている場合には, 変数 {\tt mpz\_t x} の {\tt x->\_mp\_d} が unsigned long int の 配列であり, データの実体である. これは整数の最下位4バイトが配列の先頭にくる. つまり全体としては``リトルエンディアンっぽい''が, 各 unsigned long int はマシンのネイティブな integer である. つまり, GMP の内部表現はマシン依存となっている. \begin{thebibliography}{99} \bibitem{Openxxx-1998} 野呂正行, 高山信毅. {Open XM の設計と実装 --- Open message eXchange protocol for Mathematics}, November 22, 1999, Revised March 4, 2005. \bibitem{Ohara-Takayama-Noro-1999} 小原功任, 高山信毅, 野呂正行. {Open asir 入門}, 1999, 数式処理, Vol 7, No 2, 2--17. (ISBN4-87243-086-7, SEG 出版, Tokyo). \bibitem{Wolfram-1992} ウルフラム. {Mathematica (日本語版)}, アジソンウエスレイ, 1992. \bibitem{Wolfram-1996} Stephen Wolfram. {The Mathematica Book}, Third edition, Wolfram Media/Cambridge University Press, 1996. \bibitem{miyachi-1998} 宮地力. {Mathematica によるネットワークプログラミング}, 岩波コンピュータサイエンス, 岩波書店, 1998. \bibitem{MathSource-Google1} Todd Gayley. [mg17015] in MathArchive, 1999 April. \bibitem{MathSource-Google2} 昔の MathLink にあった MLSignal の解説. (以前、Google のキャッシュにあったが、もうない) \bibitem{Math-Output1} mathlink.h, libMLa のシンボル表, mprep の生成するソース. \end{thebibliography} \end{document}