外部プログラムをWolfram言語から呼び出す

外部プログラム中に定義してある関数をWolfram言語から呼び出すためには,関数に引数を渡したり,関数の結果を戻すためのWolfram Symbolic Transfer Protocol (WSTP)コードを外部プログラムに追加する必要がある.
簡単なものなら,呼び出したい外部関数ごとに適切なWSTPテンプレートを用意するだけで必要なコードを生成することができる.
:Begin:
:Function: f
:Pattern: f[x_Integer, y_Integer]
:Arguments: {x, y}
:ArgumentTypes: {Integer, Integer}
:ReturnType: Integer
:End:
外部関数fに対応するWSTPテンプレートを含むf.tmファイル
:Begin:
特定の関数に関するテンプレートを開始する
:Function:
外部プログラム中の関数名
:Pattern:
関数を呼び出すように定義されたパターン
:Arguments:
関数に渡す引数
:ArgumentTypes:
関数に渡す引数の型
:ReturnType:
関数の戻り値の型
:End:
ひとつの関数に関するテンプレートを終了する
:Evaluate:
関数をインストールする際に評価されるWolfram言語入力
WSTPテンプレートの要素
外部関数に対応するWSTPテンプレートは関数のソースコードと結合させる必要がある.ソースコードがC言語で書かれていると仮定すると,それは単にWSTPのヘッダファイルを含むコード1行と小さいmainプログラムをソースコードに追加するだけで済む.
標準WSTPヘッダファイルを含む:
#include "wstp.h"
関数fのコード:
int f(int x, int y) {
return x+y;
}
外部関数をWolfram言語からの呼出しに答えるように設定する:
int main(int argc, char *argv[]) {
return WSMain(argc, argv);
}
C言語のソースを含んでいるf.cファイル
システムによっては,main関数の形式が若干異なることもある.詳しくはWSTPデベロッパキット中のリリースノートを参照すること.
wscc
WSTPソースファイルを前処理し,コンパイルする
wsprep
WSTPソースファイルを前処理する
WSTPソースファイルを処理する外部プログラム
WSTPテンプレートは通常 file.tmという名前のファイルにする.そのファイルにはさまざまな関数のテンプレートに混ざって,Cのソースコードも挿入することができる.
適当なファイルを準備したら,WSTPテンプレートに書き込まれた情報とともに,ソースコードをコンパイルする.コンパイルは外部プログラムで行うが,細かい部分はコンピュータシステムによって違っている.
Unixを例に取ると,WSTPデベロッパキットにはwsccと呼ばれるプログラムがあり,このプログラムは名前が.tmで終るWSTPテンプレートファイルを前処理してCのソースコードを生成し,そのソースコードをccでコンパイルする.wsccはコマンドラインオプションや他のファイルは直接ccに渡す.
f.tmを前処理して得られるCのソースファイルをf.cファイルとともにコンパイルする:
wscc -o f.exe f.tm f.c
Wolfram言語にバイナリをインストールする:
は整数の和を求める外部関数f(int x, int y)を呼び出す:
外部プログラムはマシンサイズの整数しか扱えないため,妙なことが起っている:
Windowsでは,WSTPデベロッパーキットには,mprepプログラムが入っていて,これを直接呼び出して,前処理したい.tmファイルを処理する.mprepはCのソースコードを出力するので,それをCコンパイラにかける.
Install["prog"]
外部プログラムをインストールする
Uninstall[link]
外部プログラムをアンインストールする
Links["prog"]
"prog"に関連するアクティブなリンクを表示する
Links[]
アクティブなリンクをすべて表示する
LinkPatterns[link]
あるリンク上で評価されるパターンを表示する
外部プログラムへのリンクの取扱い
これでf.exeプログラムへのリンクを求める:
これはリンクを使って評価できるWolfram言語のパターンを示している:
Installは適切な関数ExternalCallを実行する実際の関数fを設定する:
WSTPテンプレートが処理されるとき,基本的に2つのことが行われる.まず,:Pattern:の仕様に従い,WSTP経由で外部プログラムを呼び出すWolfram言語の定義を生成する.次に,:Function:の仕様に従って外部プログラム中の関数を呼び出すCのソースコードが生成される.
:Begin:
呼び出すべき外部プログラム中の関数名:
:Function:      prog_add
定義が設定されるべきWolfram言語のパターン:
: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:
WSTPテンプレート中の:Pattern:には,どんなWSTPの式を与えても構わない.に与えたものはすべて,その外部関数の呼出しごとに毎回評価される.評価の結果は引数のリストとして関数に渡される.
外部関数の呼出し時ではなく,インストール時にだけ,評価させたいWolfram言語式もあるだろう.
その場合,WSTPテンプレート中の:Evaluate:を利用する.:Evaluate:の後ろに与える式は何行になっても構わない.空行,あるいはスペース文字やタブ文字で始まらない行がきたら,式が終ったとみなされる.
SkewAddの使用法は外部関数がインストールされるときに設定される:
:Evaluate:    SkewAdd::usage = "SkewAdd[x, y] performs
a skew addition in an external program."
外部プログラムがインストールされるときは,WSTPテンプレートファイルに記述された順に仕様が読み込まれる.:Begin:より前の:Evaluate:に与えられた式は外部関数の定義が読み込まれる前に評価される.
外部関数の定義が読み込まれる以前に評価されるWolfram言語の式:
:Evaluate:  BeginPackage["XPack`"]
:Evaluate: XF1::usage = "XF1[x, y]は1つの外部関数です."
:Evaluate: XF2::usage = "XF2[x]は他の外部関数です."
:Evaluate: Begin["`Private`"]
Wolfram言語の関数XF1が外部Cプログラム中の関数fを呼び出すように設定される:
:Begin:
:Function: f
:Pattern: XF1[x_Integer, y_Integer]
:Arguments: {x, y}
:ArgumentTypes: {Integer, Integer}
:ReturnType: Integer
:End:
Wolfram言語の関数XF2gを呼び出す.その引数と戻り値は近似された実数である:
:Begin:
:Function: g
:Pattern: XF2[x_?NumberQ]
:Arguments: {x}
:ArgumentTypes: {Real}
:ReturnType: Real
:End:
外部関数の定義の後に評価されるWolfram言語式.これらは関数定義に用いた特別なコンテキストを終了する:
:Evaluate: End[ ]
:Evaluate: EndPackage[ ]
関数fのソースコード.引数の名前は対応するWolfram言語のものと一致する必要はない:
int f(int i, int j) {
return i + j;
}
関数gのソースコード.Wolfram言語中で与えた数は,gに渡される前にCのdoubleに変換される:
double g(double x) {
return x*x;
}
:Evaluate:を利用して,外部プログラムが最初にインストールされるときに評価されるWolfram言語の式を指定することができる.また,外部プログラムのmain()中のWSMain()呼出しの前に挿入したコードも,外部プログラムのインストール前に実行される.外部関数が実行される前に,外部プログラムを初期化する場合等に使うとよいだろう.
WSEvaluateString(stdlink,"string")
文字列をWolfram言語の入力として評価する
外部プログラムからWolfram言語のコマンドを実行する
int diff(int i, int j) {
もしi < jであればWolfram言語のPrintを評価する:
    if (i < j) WSEvaluateString(stdlink, "Print[\"negative\"]");
return i - j;
}
上で定義したdiff関数を含むプログラムをインストールする:
diffを呼ぶと,Printが実行される:
WSEvaluateString()の評価結果は,どんなものであろうと単に無視されることに注意すること.戻り値の利用にはWolfram言語と外部プログラムとの間で完全な双方向の通信が必要になる.これに関しては「外部プログラムとの双方向通信」で述べる.