%%$OpenXM: OpenXM/src/kan96xx/Doc/oxshell.oxw,v 1.2 2003/12/08 05:35:32 takayama Exp $ %% "make oxshell-ja.tex" to get the platex source. //&ja \documentclass{jarticle} //&en \documentclass{article} //&ja \title{Oxshell の設計と実装} //&en \title{The design and implementation of oxshell} //&C \author{Nobuki Takayama} //&C \date{December 8, 2003} //&C \newtheorem{example}{Example} \usepackage{html} \begin{document} \maketitle /*&ja OpenXM プロジェクトでは OX RFC 100 を用いて種々の数学ソフトウエアシステムの統合化を試みている. 新しい OX RFC 100 準拠のサーバを作る場合には ターゲットとする数学ソフトウエアシステムのソースコードに OX RFC 100 対応部分 を加える作業をしないといけない. この作業はソースコードの理解とかなりの手間を要する. 一方, 多くの数学ソフトウエアシステムはあらかじめファイルにコマンドやデータを書き出しておくことにより unix の shell や Windows のコマンドプロンプトから利用可能なように作られている. このような数学ソフトウエアをバッチ処理対応アプリケーションとこの文書ではよぶ. Oxshell は上記のようなバッチ処理対応アプリケーションをソースコードの改変なく OX RFC 100 準拠にするためのいわゆるラッパー型の OX サーバを書くための補助機能を 提供する sm1 への組み込み関数である. */ //&ja Oxshell を用いて OX サーバを実現するのが適切な数学ソフトウエアは以下のような特徴をもつものであろう. /*&ja \begin{enumerate} \item バッチ処理対応アプリケーションである. \item ソースコードの変更ができないか困難. \item サーバとの通信が頻繁におきない. \item サーバの計算を中断して, 再度開始するなどの必要がない. \item Windows でも unix でも動かしたい. \end{enumerate} */ //&ja このような特徴を幾つかもつソフトウエアシステムとしてたとえば, {\tt polymake} がある //&C (\htmladdnormallink{{\tt http://www.math.tu-berlin.de/polymake}}{http://www.math.tu-berlin.de/polymake}). /*&ja Polymake は多面体の facet の数え挙げなど多面体の種々の構成と計算をおこなうためのソフトウエアである. Polymake はバッチ処理対応アプリケーションであり, また C++ で書かれたソースは先端的な C++ の機能を 利用しておりコンパイルが容易でない. サーバとの通信の頻度は問題によるがある程度大きい計算の場合は通信時間は無視できる. Polymake は対話的利用は想定しておらずサーバの計算を中断して, 再度開始するなどの必要がない. この文章ではこの {\tt polymake} を例にとって, oxshell の設計と実装を述べる. */ //&ja \section{ox polymake サーバ入門} //&en \section{Introduction to ox polymake server} /*&ja oxshell の設計と実装を述べるまえに, {\tt polymake} がどのようなソフトウエアか, ox polymake がどのように動作するか実例をあげて説明しよう. */ //&C \begin{example} \rm /*&ja 点 $(1,0,0)$, $(1,1,0)$, $(1,0,1)$, $(1,1,1)$ 上の cone の facet を求めよ. \\ {\tt polymake} ではつぎような入力ファイル {\tt square.poly} をまず作成する. */ /*&C {\footnotesize \begin{verbatim} POINTS 1 0 0 1 1 0 1 0 1 1 1 1 \end{verbatim} } */ //&ja \noindent そして次のコマンドを shell から実行する. //&C \ \\ \verb@ polymake square.poly FACETS @ \\ //&ja {\tt Polymake} は次のように結果を戻す. /*&C {\footnotesize \begin{verbatim} FACETS 0 0 1 0 1 0 1 0 -1 1 -1 0 \end{verbatim} } */ //&C \end{example} //&C \begin{example} \rm /*&ja 同じ例を {\tt sm1/oxshell} を用いて解くと次のようになる. */ //&ja 次のコマンドを {\tt ox\_sm1} に実行させる. こたえはスタックマシンの変数 {\tt rr} に入る. /*&C {\footnotesize \begin{verbatim} [(FACETS) (polymake.data(polymake.POINTS([[1,0,0],[1,1,0],[1,0,1],[1,1,1]])))] doPolymake /rr set ; \end{verbatim} } */ //&ja {\tt rr} にはつぎような値がはいっている. /*&C {\footnotesize \begin{verbatim} [ $polymake.data(polymake.POINTS([[1,0,0],[1,1,0],[1,0,1],[1,1,1]]), polymake.FACETS([[0,0,1],[0,1,0],[1,0,-1],[1,-1,0]]), polymake.AFFINE_HULL())$ CMO tree expression of the data above Outputs to stdout and stderr ] \end{verbatim} } */ //&C \end{example} //&ja \section{doPolymake の処理の流れ} /*&ja \begin{enumerate} \item (CMO tree を tfb/2 形式へ.) \item tfb/2 表現のデータを polymake の入力形式へ. ({\tt OpenXM/src/k097/k0} の {\tt QuoteMode} を利用して CMO tree 形式へ. それから sm1 の treeToPolymake extension を用いる. ソースは, {\tt OpenXM/src/kan96xx/trans/tree2polymake.c}) \item polymake を {\tt oxshell} で呼び出す. ({\tt OpenXM/src/kan96xx/trans/polymake.sm1}). \item うけとった polymake 形式のデータを tfb/2 形式へ ({\tt OpenXM/src/kan96xx/trans} の {\tt yy\_polymake.y} でパース. polymake2tfb が変換用のバイナリ.) \item (tfb/2 形式を CMO tree へ.) \end{enumerate} {\tt doPolymake} のソースは \\ {\tt kan96xx/trans/polymake.sm1} にある. */ //&ja \section{{\tt Oxshell} の特徴} /*&ja \noindent OX RFC 100 にはファイルの概念がない. したがって, \\ \verb@ polymake ファイル名 動作 @ \\ みたいなプログラムは OX スタックマシンの上のデータをファイルに書き出してから 実行して, それからまたスタックマシンの上のデータに変換しないといけない. この変換は単純仕事であるが, 実際のプログラムは unix と windows のパス名の違いとか, /bin/sh の存在を仮定できる unix と /bin/sh の存在を仮定できない windows とかいろんな要素があり, プログラムが大変読みにくく保守もしにくい ( phc での経験). ZPG の極致である. {\tt oxshell} ではこの仕事は次の 1 行で書く. \\ \verb@[(polymake) (stringInOut://スタックマシン変数名.poly) 動作] oxshell@\\ スタックマシンの変数をファイルをみなしている. このような考え方は, なにも新しいものではない. 文字列変数をファイルのように input output stream とみなすというのは Java の io.StringReader ( io.InputStreamReader の代わり) 等で使われている. またコマンドの実行結果を文字列として変数に代入する動作は, たとえばスクリプト言語である Python では \verb@ x=os.popen("abc","r").read(); @ として簡単に実行できる. しかしながらこれらの考えを数学ソフトウエアの統合化のために使うための実装は存在していなかった. これが oxshell コマンドの導入によって解決される点の一つである. これらはよく知られている工夫だがこれを数学ソフトウエア統合作業に採り入れることにより, 考え方が整理されプログラムの保守性が大変よくなり, また新しいバッチ型アプリケーションの OX サーバ化が楽になった. {\tt oxshell} のその他のコマンドについては, sm1 で {\tt (oxshell) usage} の解説を見よ. {\tt oxshell} のソースコードは {\tt OpenXM/src/kan96xx/Kan/shell.c}. 将来的には /bin/sh の拡張言語とする予定. OX RFC 100 にファイルの概念を加える作業は OX RFC 103 (100, 101 の補い) でやる予定. */ //&ja \section{Asir より使う oxshell } //&en \section{Oxshell on asir} /*&ja Asir から sm1/oxshell を利用するための関数は \\ {\tt OpenXM/src/asir-contrib/packages/src/oxshell.rr} にまとめられている. 次のコマンドでロードする. */ /*&C \begin{verbatim} [1163]:= load("oxshell.rr"); \end{verbatim} */ //&ja 幾つか例をみてみよう. //&en Let us see some examples. /*&ja unix 上で次のコマンドの実行により {\tt ls} の stdout への出力が文字列として {\tt S} の 第一要素として, stderr への出力が文字列として {\tt S} の第2要素として格納される. */ /*&C \begin{verbatim} [1164]:= S = oxshell.oxshell(["ls"]); \end{verbatim} */ /*&ja 文字列 {\tt S} に格納された単語 dog, cat, lion を unix のツール sort で 並べ変えるには次のように書く. 入力は oxshell を実行しているスタックマシンの変数 {\tt S} に格納されている. */ /*&C \begin{verbatim} [1163]:= S="dog\ncat\nlion\n"; [1164]:= oxshell.set_value("S",S); [1165]:= T=oxshell.oxshell(["sort","stringIn://S"]); [cat dog lion ,] \end{verbatim} */ /*&ja {\tt OpenXM/src/asir-contrib/packages/src/taka\_ahg.rr} の 関数 {\tt taka\_ahg.b(A,Idx)} は oxshell による polymake 呼び出し機能を 用いた数学関数の実装例である. この関数は 行列 {\tt A} に付随した 方向 {\tt Idx} のある $b$ 関数を計算する. これは {\tt A} の定義する cone のファセットをあらわす一次式の積で表現されることが, 知られている (Saito, Mutsumi; Sturmfels, Bernd; Takayama, Nobuki; Hypergeometric polynomials and integer programming. Compositio Math. 115 (1999), no. 2, 185--204 および Saito, Mutsumi; Parameter shift in normal generalized hypergeometric systems. Tohoku Math. J. (2) 44 (1992), no. 4, 523--534 をみよ.) */ /*&C \begin{verbatim} [1163]:= load("oxshell.rr"); [1164]:= load("taka_ahg.rr"); [1165]:= A=[[1,0,0],[1,1,0],[1,0,1],[1,1,1],[1,2,0]]; [1166]:= fctr(taka_ahg.b(A,4,[s1,s2,s3])); [[1,1],[s1+2*s2,2],[s1+2*s2-1,1]] \end{verbatim} */ /*&C \begin{verbatim} def b(A,Idx,V) { F = oxshell.facets(A); /* Computing all the facets by polymake server.*/ F = F[1]; /* F is the set of the facets */ P = A[Idx]; Nfacets = length(F); F = toPrimitive(A,F); /* Translate into primitive supporting function */ Bf = 1; for (I=0; I