设置从 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 头文件的行,再插入一个小主程序即可.
包含标准 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 Developer Kit 版本说明中将会给出合适的形式.
wscc
预处理和编译 WSTP 源文件
wsprep
预处理 WSTP 源文件
处理 WSTP 源文件的典型外部程序.
约定将 WSTP 模板放在形如 file.tm 的文件中. 这类文件也可以含有散步在不同函数模板中的 C 语言代码.
在建立了适当的文件后,就要处理 WSTP 模板信息,编译所有的源代码. 这一般需要运行各种外部程序,其细节依赖于所使用的计算机系统.
例如,在 Unix 中,WSTP Developer Kit 有一个名为 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),并将两个整数相加:
外部程序处理机器整数,所有这里给了一个奇怪的结果:
在 Wolfram 语言中,WSTP Developer Kit 一般包含一个名为 mprep 的程序,必须将要处理的 .tm 文件作为输入直接调用它. mprep 输出产生 C 源代码,它可以送往 C 编译器.
Install["prog"]
安装外部程序
Uninstall[link]
卸载外部程序
Links["prog"]
显示与 "prog" 有关的激活链接
Links[]
显示所有激活链接
LinkPatterns[link]
显示在一个链接中可以被计算的模式
处理外部程序的链接.
找出程序 f.exe 的链接:
这里显示可以用该链接计算的 Wolfram 语言模式:
Install 安装了一个用来执行一个适当的 ExternalCall 函数的实际函数 f
处理 WSTP 模板文件时做两件基本事情:第一,用 :Pattern: 的给定值产生一个 Wolfram 语言定义,它通过 WSTP 调用外部函数. 第二,用 :Function: 的给定值产生 C 源代码,它在外部程序中调用函数.
:Begin:
给出在外部程序中实际调用的 C 函数名:
:Function:      prog_add
给出建立定义的 Wolfram 语言模式:
:Pattern:       SkewAdd[x_Integer, y_Integer:1]
这两个列表元素的值就是要传递给外部的实际变量:
:Arguments:     {x, If[x > 1, y, y + x - 2]}
这里指定变量应该按整数传给 C 函数:
:ArgumentTypes: {Integer, Integer}
这里规定从 C 函数返回的值必须是整数:
:ReturnType:    Integer
:End:
在 WSTP 模板中,:Pattern: 的指定值都可以是任何 Wolfram 语言表达式. 对 的指定值在每次调用外部函数时计算. 计算的结果将作为变量列表传递给函数.
有时需要建立调用外部函数时不计算,而是只在第一次安装这个外部函数时计算的 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] is one external function."
:Evaluate: XF2::usage = "XF2[x] is another external function."
: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 语言中的函数 XF2 调用函数 g. 它的变量和返回值都是近似实数:
: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 语言表达式. 此时也可以通过在调用 WSMain()之前将代码插入 main() 中执行外部程序中的代码. 这在使用外部程序中的函数之前对它进行初始化时是有用的.
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 语言与外部程序通讯的两种方式.