此为 Mathematica 4 文档,内容基于更早版本的 Wolfram 语言
查看最新文档(版本11.1)

2.12.3 设置从 Mathematica 中调用的外部函数

Mathematica 中调用在外部程序中定义的函数时,需要增添适当的 MathLink 代码以传递函数的变量和得到函数所产生的结果.
在简单情况下,对每一个外部函数给出一个适当的 MathLink 模板就可以 生成所需的代码.

:Begin:
:Function: f
:Pattern: f[x_Integer, y_Integer]
:Arguments: {x, y}
:ArgumentTypes: {Integer, Integer}
:ReturnType: Integer
:End:

MathLink 模板的元素

对一个外部函数建立了 MathLink 模板后,必须将这个模板和实际的函数源代码 结合起来. 当源代码是用 C 语言编写的时,只需要简单地增加一个包含标准 MathLink 头文件的行,再插入一个小主程序即可.

#include "mathlink.h"

#include "mathlink.h"

int f(int x, int y)
return x+y;

int f(int x, int y) {
return x+y;
}

int main(int argc, char *argv[])
return MLMain(argc, argv);

注意,不同系统调用的主形式会有小的差异. 在所使用计算机系统的 MathLink Developer Kit 版本说明中将会给出合适的形式.

处理 MathLink 源文件的典型外部程序

约定将 MathLink 模板放在形如 file.tm 的文件中.这类文件也可以含有散布在不同函数 模板中的 C 语言代码.
在建立了适当的文件后,就要处理 MathLink 模板信息,编绎所有的源代码. 这一般需要运行各种外部程序,其细节依赖于所使用的计算机系统.
例如,在 Unix 中,MathLink Developer Kit 有一个名为 mcc 的程序,它对任何文件中以 .tm 结尾的 MathLink 模板进行预处理,然后对结果中的 C 源代码调用 cc. mcc 将命令行选项和其它文件直接传递给 cc.

预处理 f.tm 然后将所得 C 源文件和文件 f.c 一起进行编绎

mcc -o f.exe f.tm f.c

在当前 Mathematica 进程中安装二进制文件

现在 f[x, y] 调用外部函数 f(int x, int y),并将两个整数相加

外部程序处理机器整数,所以这里给了一个奇怪的结果

在除过 Unix 以外的系统中,MathLink Developer Kit 一般包含一个名为 mpreg 的程序,必须将要处理的 .tm 文件作为输入直接调用它. mpreg 输出产生 C 源代码,它可以送往 C 编绎器.

处理外部程序的链接

找出程序 f.exe 的链接

这里显示可以用该链接计算的 Mathematica 模式

Install 安装了一个用来执行一个适当的 ExternalCall 函数的实际函数 f

处理 Mathematica 模板文件时做两件基本事情:第一,用 :Pattern::Arguments: 的给定值产生一个Mathematica 定义,它通过 MathLink 调用外部函数;第二,用 :Function:, :ArgumentTypes::ReturnType: 的给定值产生 C 源代码,它在外部程序中调用函数.

:Begin:

给出在外部程序中实际调用的 C 函数名

:Function: prog_add

给出建立定义的 Mathematica 模式

:Pattern: SkewAdd[x_Integer, y_Integer:1]

这两个列表元素的值就是要传递给外部的实际变量

: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] is one external function."
:Evaluate: XF2::usage = "XF2[x] is another external function."
: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 g(double x)
return x*x;

:Evaluate: 设定值可以在第一次安装一个外部程序时计算 Mathematica 表达式. 此时也可以通过在调用 MLMain() 之前将代码插入 main() 中执行外部 程序中的代码. 这在使用外部程序中的函数之前对它进行初始化时 是有用的.

从外部程序中执行 Mathematica 命令

int diff(int i, int j) {

i < j 时计算 Mathematica 函数 Print

if (i < j) MLEvaluateString(stdlink, "Print[\"negative\"]");

return i - j;
}

安装一个含有前面定义的 diff 函数的外部程序

调用 diff 去执行 Print

注意由 MLEvaluateString() 要求的计算所产生的结果将被忽略, 要使用这些结果时需要 2.12.9 节中讨论的 Mathematica 与外部程序通讯的 两种方式.