=================================================================== RCS file: /home/cvs/OpenXM/src/ox_math/documents/ox_math.tex,v retrieving revision 1.2 retrieving revision 1.9 diff -u -p -r1.2 -r1.9 --- OpenXM/src/ox_math/documents/ox_math.tex 1999/11/02 06:12:00 1.2 +++ OpenXM/src/ox_math/documents/ox_math.tex 2005/07/20 16:24:56 1.9 @@ -1,154 +1,343 @@ %#!platex -%% $OpenXM$ +%% $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{ +%January 19, 1999 +%July 12, 1999 +November 25, 1999 +(Revised July 20, 2005) +} \author{小原功任} +\def\oxmath{{\tt ox\_math}} + \begin{document} \maketitle -\section{Open Mathematicaの構成} +\section{我々が提供するもの} -Open Mathmatica サーバはOpen XM クライアントおよびmathematica カーネルと -通信する。Open Mathmatica サーバは起動直後にmathematica カーネルを起動し、 -mathematica カーネルと協調して動作する。mathematica カーネルとは -MathLink ライブラリを利用して通信する。Open Mathmatica サーバはMathLink +我々が提供するのは二つのプログラムとそのソースである。一つ目は +\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 クライアントとの間はソケットを利用して通 -信する。Open Mathmatica サーバはファイルディスクリプタ 3,4 が既にオープ +信する。\oxmath はファイルディスクリプタ 3,4 が既にオープ ンされていると思って, 3 から読み込み、4 に書き出す。 -さらに、Open Mathmatica サーバはコントロールプロセスからシグナルを受け取 -る場合がある。シグナルを受け取った場合には,相応の動作が必要であるが、現 -在は実装していない. SIGUSR1 (SM\_control\_reset\_connection) は計算が全 -て終わってからOX\_SYNC\_BALL を投げるので、実際には意味がない。 +さらに \oxmath には計算中断機能が必要であるが、この機能は 2003年のはじめに実装された。 -\section{OX スタックマシン} +次に、Open XM 規約より \oxmath はスタックマシンでなければならない。 スタックのオブジェクトは cmo 型の変数、あるいはその派生クラスである. つまり、Open XM 規約で定められたデータ形式を流用している. -% cmo 構造体およびその派生クラスは/home/ohara/openxxx/lib/oxlib.h で定義さ -% れている. この方法の利点は Open XM プロトコルを通して通信するにあたって 特にデータの変換を必要としないことである. すなわちCMO の各データタイプ -は Open Mathematicaサーバ(スタックマシン)の内部でも, CMO として保持する +は \oxmath の内部でも, CMO として保持する わけである. サーバの各関数は cmo* を受け取り、タグをみて実際のクラスが何であるかを 知り、動作を決定する. -\section{Mathematica との通信(MathLink) について} +現在、実装されているスタックマシン命令は +SM\_popCMO, SM\_popString, SM\_pops, SM\_executeFunction, +SM\_executeStringByLocalParser, SM\_mathcap, SM\_setMathcap(受け取るだけ +で何もしない)である。 -CMO は 次のように変換されてから, MathLink を通して送られる. +\section{MathLink プログラミングと \oxmath} +最初に、MathLink プログラミングについての基礎的事項を説明し、 +次に \oxmath の Mathematica Kernel との通信部分について述べる。 + +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 CMO\_INT32 は MLTKINT (多倍長整数型). -\item CMO\_STRING は MLTKSTR (文字列型). -\item その他のタイプの CMO は ToExpression[文字列] として送る. +\item Mathematica Kernel に式を送る。 +\item Mathematica Kernel から式を受け取る。 \end{enumerate} +を繰り返すのが MathLink でのプログラミングである。 -上で述べられている ToExpression は Mathematica の組み込み関数であり, -文字列を引数として Mathematica の式を返す. +\oxmath は Mathematica と以下のような意味で{\bf 文字列ベース}で通信して +いる。まず Mathematica Kernel に評価させたい式が、C 言語の文字列で与えら +れているとして、link で指し示すMathematica Kernel に +\begin{verbatim} +int ml_evaluateStringByLocalParser(char *string) +{ + MLPutFunction(link, "EvaluatePacket", 1); + MLPutFunction(link, "ToExpression", 1); + MLPutString(link, string); + MLEndPacket(link); +} +\end{verbatim} +として送信する。パケットは、 +EvaluatePacket[ToExpression[{\it string}]] である。 +ここで ToExpression は Mathematica の組み込み関数であり, +文字列 {\it string} を引数として Mathematica の式を返す. (\cite[pp.407]{Wolfram-1996}) -ここで一つ注意をしておく. -MathLink では, int 型以外のデータを MLTKINT として送ることは残念ながらで -きない. したがって CMO\_ZZ を直接, 整数型であると Mathematica に思わせ -ることはできないのである. そこで, 次のような方法をとることになる. - +評価された結果を配列 str に格納するには、単純には次のようになる。 \begin{verbatim} -char *CONVERT_ZZ_TO_CSTRING(cmo_t zz); - -int main() +int receive_sample(char str[]) { - 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); - ... + 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() +などを見てほしい。 -このようにすると, Mathematica 側では, 例えば +\bigskip + +文字列によらず、CMO を送ることもできる. + +\oxmath は, CMO を次の規則で MathLink のオブジェクトに変換する. \[ -\mbox{\tt ToExpression["1234567890"]} +\begin{array}{lcl} +\mbox {CMO\_INT32} & \to & \mbox{MLTKINT}, \\ +\mbox {CMO\_STRING} & \to & \mbox{MLTKSTR}, \\ +\mbox {CMO\_LIST} & \to & \mbox{MLTKFUNC}, \\ +\mbox {その他の CMO} & \to & \mbox{ToExpression[文字列]} +\end{array} \] -という評価が行われ, 文字列データから整数が復元される. +逆に MathLink のオブジェクトは次の規則で CMO に変換される. +\[ +\begin{array}{lcl} +\mbox {MLTKERR} & \to & \mbox{CMO\_ERROR2}, \\ +\mbox {MLTKINT} & \to & \mbox{CMO\_ZZ}, \\ +\mbox {MLTKSTR} & \to & \mbox{CMO\_STRING},\\ +\mbox {MLTKREAL} & \to & \mbox{CMO\_IEEE\_DOUBLE\_FLOAT}, \\ +\mbox {MLTKSYM} & \to & \mbox{CMO\_STRING}, \\ +\mbox {MLTKFUNC} & \to & \mbox{CMO\_LIST} +\end{array} +\] +この変換規則は明らかに可逆でないので注意. -逆に, Mathematica から送られた整数データは, -マシン整数の範囲内であれば, int として -取得可能(MLGetInteger を使う)であるが, -受け取る前に int に収まるか否かを知ることはできない. -また, 直接 CMO\_ZZ として取得することも不可能である. -(MathLink 上でどのような形式でデータ交換されているのかの -情報は手元にある資料からは得られなかった) +\bigskip +CMO\_ZZ をもとに実装を説明しよう. +まず, MLTKINT は多倍長整数型であるが, MathLink の内部データ構造が +公開されていないため, +CMO\_ZZ (あるいは GNU GMP library の整数)を直接 MLTKINT に +変換することはできない. つまり CMO\_ZZ が整数型であると MathLink に知ら +せることはできない. そこで, 次のような方法をとることになる. + +\begin{verbatim} +export MLINK link; +int ml_send_cmo_zz(cmo *m) +{ + MLPutFunction(link, "ToExpression", 1); + MLPutString(link, new_string_set_cmo(m)); +} +\end{verbatim} + +このようにすると, Mathematica 側では, 例えば ToExpression["1234567890"] +の評価が行われ, 文字列データから整数 1234567890 が復元される. + +逆に, Mathematica から送られた多倍長整数は, マシン整数の範囲内であれば, +int として取得可能(MLGetInteger を使う)であるが, 受け取る前に int に収ま +るか否かを知ることはできない. int に収まらない場合、データが切り捨てられ +てしまうので注意が必要である. また, 直接 CMO\_ZZ として取得することも不 +可能である. (MathLink 上でどのような形式でデータ交換されているのかの情 +報は手元にある資料からは得られなかった) + しかしながら, たとえ Mathematica 側から整数データが送られていたとしても, そのデータを文字列に変換して受け取ることは MathLink の機構上可能である. これを利用して, 我々は次のようにして整数を受け取る. \begin{verbatim} -cmo_t CONVERT_CSTRING_TO_ZZ(char *s); - -int main() +export MLINK link; +cmo_zz* ml_receive_cmo_zz() { - MLINK lp; - char *s; - cmo_t zz; - ... - if(MLGetNext(lp) == MLTHINT) { - MLGetString(lp, &s); - zz = CONVERT_CSTRING_TO_ZZ(s); /* zz.tag == 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; +} \end{verbatim} -つまり、Mathematica から整数データを文字列として受け取り、 -その文字列を OX サーバ側で CMO\_ZZ に直している。 +つまり、Mathematica から整数を文字列として受け取り、その文字列を +\oxmath が CMO\_ZZ に直している。 -基本的に MathLink では全てのデータを文字列で受け取るしか方法はない。どの -ような種類のデータであるかは受け取る前に知ることはできる。データの型は、 -MLTKERR(エラー), MLTKINT(整数), MLTKSTR(文字列), MLREAL(実数), MLTKSYM -(シンボル), MLTKFUNC(関数) のいずれかである。このような事情で -Mathematica から受け取ったデータは基本的に CMO\_STRINGとしてスタックに積 -まれるので、クライアント側でその文字列の解釈をする必要がでてくる。 +% このように基本的に MathLink では全てのデータを文字列で受け取るしか方法は +% ない。どのような種類のデータであるかは受け取る前に知ることはできる。デー +% タの型は、MLTKERR(エラー), MLTKINT(整数), MLTKSTR(文字列), MLTKREAL(実数), +% MLTKSYM (シンボル), MLTKFUNC(関数) のいずれかである。このような事情で +% Mathematica から受け取ったデータは基本的に CMO\_STRINGとしてスタックに積 +% まれるので、クライアント側でその文字列の解釈をする必要がでてくる。しかし +% ながら、全ての MathLink オブジェクトが文字列に変換できるわけではないので、 +% その取り扱いには注意を要する。 -しかしながら、全ての MathLink オブジェクトが文字列に変換できるわけではな -いので、その取り扱いには注意を要する。 -まだ、実装していないが、多項式(CMO\_???\_PORINOMIAL)の扱いが難しい。 +\section{\oxmath への計算中断機能の実装} -\section{個々のスタックマシン命令の実装} -現在、実装しているのは -SM\_popCMO, SM\_popString, SM\_pops, SM\_executeFunction, -SM\_executeStringByLocalParser, SM\_mathcap, SM\_setMathcap(受け取るだけ -で何もしない)である。 +\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], +\\ +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 をロードしたら、 \begin{verbatim} -In[2] := OxStart["ox_sm1"] +In[2] := pid = OxStart["ox_sm1"] \end{verbatim} -によって OpenXM サーバに接続する。接続先は ox\_sm1 である。 +によって OpenXM サーバに接続する。この場合の接続先は ox\_sm1 である。 +返り値 pid は、セッション番号である。 +もちろん +\begin{verbatim} +In[2] := pid = OxStartInsecure["water.s.kanazawa-u.ac.jp", 1300, 1400] +\end{verbatim} +のようにして、insecure モードで接続してもよい。ただしこの場合は、 +あらかじめ {\tt Run[]} 等で、OpenXM サーバを起動しておかなければならない。 -接続が成功したら適当にデータを送ってみよう。 -利用できるコマンドは -{\tt OxStart[s\_String], OxExecute[s\_String], OxPopString[], OxClose[], OxReset[]} -の五つである。計算が終わったら、 +接続が成功したらデータを送ってみよう。 \begin{verbatim} -In[3] := OxClose[] +In[3] := OxParse[pid, "(CMO_LIST, (CMO_STRING, "hello world"), (CMO_ZERO))"] \end{verbatim} +のように CMO expression を指定することによって、 +任意の CMO を送信できる。 +正しくない CMO の場合には、何も送信されない。 +また、CMO ではなく、 +\begin{verbatim} +In[4] := OxParse[pid, "(OX_COMMAND, (SM_popCMO))"] +\end{verbatim} +などとして、OX メッセージの形で記述することもできる。 +注意しなければならないのは、SM コマンドの場合、OX スタックマシンから +OX メッセージが送られてくる場合があるが、OxParse[] を用いた場合、 +このメッセージは自動的には受信しない(現在の仕様では)。したがって明示的に +受信する必要がある。そのためには +\begin{verbatim} +In[5] := OxGet[pid] +\end{verbatim} +とするだけでよい。返ってくるオブジェクトは CMO に対応するものである。 +\begin{verbatim} +In[6] := OxPopCMO[pid] +\end{verbatim} +を用いる場合にはもちろん {\tt OxGet[pid]} を呼び出す必要はない。 + +計算を実行するには {\tt OxExecute[pid, ...]} +(SM\_executeStringByLocalParser) か、適切な OX メッセージを送信すること。 + +計算が終わったら、 +\begin{verbatim} +In[7] := OxClose[pid] +\end{verbatim} とすると、接続が終了する。 \appendix @@ -177,10 +366,11 @@ typedef unsigned long int mp_limb_t; \begin{thebibliography}{99} \bibitem{Openxxx-1998} 野呂正行, 高山信毅. -{Open xxx の設計と実装, xxx = asir,kan}, 1998/10/11 +{Open XM の設計と実装 --- Open message eXchange protocol for Mathematics}, +November 22, 1999, Revised March 4, 2005. \bibitem{Ohara-Takayama-Noro-1999} 小原功任, 高山信毅, 野呂正行. -{Open asir 入門}. +{Open asir 入門}, 1999, 数式処理, Vol 7, No 2, 2--17. (ISBN4-87243-086-7, SEG 出版, Tokyo). \bibitem{Wolfram-1992} ウルフラム. {Mathematica (日本語版)}, @@ -189,12 +379,20 @@ typedef unsigned long int mp_limb_t; 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}