|
2.13.3 外部プログラムをMathematicaから呼び出す
外部プログラム中に定義してある関数をMathematicaから呼び出すためには,関数に引数を渡したり,関数の結果を Mathematicaに戻すためのコードを外部プログラムに追加する必要がある.
簡単なものなら,呼び出したい外部関数ごとに適切な MathLinkテンプレートを用意するだけで必要なコードを生成することができる.
:Begin:
:Function: f
:Pattern: f[x_Integer, y_Integer]
:Arguments: {x, y}
:ArgumentTypes: {Integer, Integer}
:ReturnType: Integer
:End:
外部関数 fに対応する MathLinkテンプレートを含むf.tmファイル

MathLinkテンプレートの要素
外部関数に対応する MathLinkテンプレートは関数のソースコードと結合させる必要がある.ソースコードがC言語で書かれていると仮定すると,それは単に MathLinkのヘッダファイルを含むコード1行と小さいmainプログラムをソースコードに追加するだけですむ.
標準 MathLinkヘッダファイルを含む.
#include "mathlink.h"
関数 fのコード.
int f(int x, int y) 
return x+y;

外部関数を Mathematicaからの呼出しに答えるように設定する.
int main(int argc, char *argv[]) 
return MLMain(argc, argv);

C言語のソースを含んでいるf.cファイル
システムによっては,main関数の形式が若干異なることもある.詳しくは MathLinkデベロッパーキット中のリリースノートを参照すること.

MathLinkソースファイルを処理する外部プログラム
MathLinkテンプレートは通常file.tmという名前のファイルにする.そのファイルにはさまざまな関数のテンプレートに混ざって,Cのソースコードも挿入することができる.
適当なファイルを準備したら, MathLinkテンプレートに書き込まれた情報とともに,ソースコードをコンパイルする.コンパイルは外部プログラムで行うが,細かい部分はコンピュータシステムによって違っている.
Unixを例に取ると, MathLinkデベロッパーキットには mccと呼ばれるプログラムがあり,このプログラムは名前が .tmで終るMathLinkテンプレートファイルを前処理してCのソースコードを生成し,そのソースコードを ccでコンパイルする. mccはコマンドラインオプションや.tm以外のファイルは直接 ccに渡す.
f.tmを前処理して得られるCのソースファイルをf.cファイルと共にコンパイルする.
mcc -o f.exe f.tm f.c
Mathematicaにバイナリをインストールする.
In[1]:= Install["f.exe"]
Out[1]= 
f[x, y]は整数の和を求める外部関数f(int x, int y)を呼び出す.
In[2]:= f[6, 9]
Out[2]= 
外部プログラムはマシンサイズの整数しか扱えないため,妙なことが起っている.
In[3]:= f[2^31-1, 5]
Out[3]= 
Unix以外のシステムでは, MathLinkデベロッパーキットには,普通, mprepプログラムが入っていて,この mprepを直接呼び出して,前処理したい.tmファイルを処理する.mprepはCのソースコードを出力するので,それをCコンパイラにかける.

外部プログラムへのリンクの取扱い
これでf.exeプログラムへのリンクを求める.
In[4]:= Links["f.exe"]
Out[4]= 
これはリンクを使って評価できるMathematicaのパターンを示している.
In[5]:= LinkPatterns[%[[1]]]
Out[5]= 
Installは適切な関数ExternalCallを実行する実際の関数fを設定する.
In[6]:= ?f


MathLinkテンプレートが処理されるとき,基本的に2つのことが行われる.まず, :Pattern:と:Arguments:の仕様に従い, MathLink経由で外部プログラムを呼び出す Mathematicaの定義を生成する.次に, :Function:,:ArgumentTypes:と:ReturnType:の仕様に従って外部プログラム中の関数を呼び出すCのソースコードが生成される.
:Begin:
呼び出すべき外部プログラム中の関数名.
:Function: prog_add
定義が設定されるべき Mathematicaのパター ン.
:Pattern: SkewAdd[x_Integer, y_Integer:1]
リスト中の2つの要素の値が外部関数の実引数となる.
:Arguments: x, If[x > 1, y, y + x - 2]
引数は整数としてCの関数に渡される.
:ArgumentTypes: Integer, Integer
Cの関数の戻り値は整数である.
:ReturnType: Integer
:End:
MathLinkテンプレート中の:Pattern:と :Arguments:には,どんな Mathematicaの式を与えても構わない. :Arguments:に与えたものはすべて,その外部関数の呼出しごとに毎回評価される.評価の結果は引数のリストとして関数に渡される.
外部関数の呼出し時ではなく,インストール時にだけ,評価させたい Mathematica式もあるだろう.
その場合,MathLinkテンプレート中の :Evaluate:を利用する. :Evaluate:の後ろに与える式は何行になっても構わない.空行,あるいはスペース文字やタブ文字で始まらない行がきたら,式が終ったとみなされる.
SkewAddの使用法は外部関数がインス トールされるときに設定される.
:Evaluate: SkewAdd::usage = "SkewAdd[x, y] performs
a skew addition in an external program."
外部プログラムがインストールされるときは, MathLinkテンプレートファイルに記述された順に仕様が読み込まれる.:Begin:より前の:Evaluate:に与えられた式は外部関数の定義が読み込まれる前に評価される.
外部関数の定義が読み込まれる以前に評価されるMathematicaの式.
:Evaluate: BeginPackage["XPack`"]
:Evaluate: XF1::usage = "XF1[x, y]は1つの外部関数です."
:Evaluate: XF2::usage = "XF2[x]は他の外部関数です."
:Evaluate: Begin["`Private`"]
Mathematicaの関数 XF1が外部Cプログラム中の関数 fを呼び出すように設定される.
:Begin:
:Function: f
:Pattern: XF1[x_Integer, y_Integer]
:Arguments: x, y
:ArgumentTypes: Integer, Integer
:ReturnType: Integer
:End:
Mathematicaの関数 XF2はgを呼び出す.その引数と戻り値は近似された実数である.
:Begin:
:Function: g
:Pattern: XF2[x_?NumberQ]
:Arguments: x
:ArgumentTypes: Real
:ReturnType: Real
:End:
外部関数の定義のあとに評価されるMathematica式.これらは関数定義に用いた特別なコンテキストを終了する.
:Evaluate: End[ ]
:Evaluate: EndPackage[ ]
関数 fのソースコード.引数の名前は対応する Mathematicaのものと一致する必要はない.
int f(int i, int j) 
return i + j;
関数 gのソースコード.Mathematica中で与えた数は, gに渡される前にCのdoubleに変換される.
double g(double x) 
return x*x;

:Evaluate:を利用して,外部プログラムが最初にインストールされるときに評価されるMathematicaの式を指定することができる.また,外部プログラムの main()中の MLMain()呼出しの前に挿入したコードも,外部プログラムのインストール前に実行される.外部関数が実行される前に,外部プログラムを初期化する場合等に使うとよいだろう.

外部プログラムから Mathematicaのコマンドを実行する
int diff(int i, int j) {
もし i < jであれば Mathematicaの Printを評価する.
if (i < j) MLEvaluateString(stdlink, "Print[\"negative\"]");
return i - j;
}
上で定義した diff関数を含むプログラムをインストールする.
In[7]:= Install["diffprog"]
Out[7]= 
diffを呼ぶと, Printが実行される.
In[8]:= diff[4, 7]

Out[8]= 
MLEvaluateString()の評価結果は,どんなものであろうと単に無視されることに注意すること.戻り値の利用には Mathematicaと外部プログラムとの間で完全な双方向の通信が必要になる.これに関しては 2.13.9で述べる.
|