通过生成 MEX 函数加快 MATLAB 算法的执行速度
您可以使用 MATLAB® Coder™ 从 MATLAB 代码生成 MEX 函数。MEX 函数是一个 MATLAB 可执行文件。它是可以从 MATLAB 内部调用的生成代码。在 MATLAB 环境内工作时,使用 MEX 函数可加快 MATLAB 代码的计算密集型部分的执行速度。通过使用 MATLAB Coder 或在 MATLAB 命令行中使用 codegen
,从您的 MATLAB 代码生成一个 MEX 函数。
在本教程中,您将使用 MATLAB Codercodegen
命令为 MATLAB 函数生成 MEX 函数。首先,您需要生成一个 MEX 函数,该函数只能接受具有预分配的固定大小的输入。然后生成另一个 MEX 函数,该函数可以接受具有许多不同大小的输入。
教程文件:欧几里德距离
打开此示例以获取本教程的文件。
教程文件的描述
本教程使用 euclidean_data.mat
、euclidean.m
、test.m
、test_2d.m
、build_mex_fixed.m
和 build_mex_variable.m
文件。
MATLAB 数据文件
euclidean_data.mat
包含两段数据:三维欧几里德空间中的一个点以及三维欧几里德空间中的一组其他点。更具体地说:x
是一个3
×1
列向量,表示三维欧几里德空间中的一个点。cb
是一个3
×216
数组。cb
中的每列都表示三维欧几里德空间中的一个点。
MATLAB 文件
euclidean.m
包含euclidean
函数,该函数在本示例中实现核心算法。该函数接受x
和cb
作为输入。它计算x
和cb
中每个点之间的欧几里德距离,并返回以下量:列向量
y_min
,它等于cb
中表示与x
距离最近的点的列。列向量
y_max
,它等于cb
中表示与x
距离最远的点的列。二维向量
idx
,它包含cb
中向量y_min
和y_max
的列索引。二维向量
distance
,它包含计算出的到x
的最小和最大距离。
function [y_min,y_max,idx,distance] = euclidean(x,cb) % Initialize minimum distance as distance to first element of cb % Initialize maximum distance as distance to first element of cb idx(1)=1; idx(2)=1; distance(1)=norm(x-cb(:,1)); distance(2)=norm(x-cb(:,1)); % Find the vector in cb with minimum distance to x % Find the vector in cb with maximum distance to x for index=2:size(cb,2) d=norm(x-cb(:,index)); if d < distance(1) distance(1)=d; idx(1)=index; end if d > distance(2) distance(2)=d; idx(2)=index; end end % Output the minimum and maximum distance vectors y_min=cb(:,idx(1)); y_max=cb(:,idx(2)); end
MATLAB 脚本
test.m
将数据文件euclidean_data.mat
加载到工作区中。它调用函数euclidean
计算y_min
、y_max
、idx
和distance
。然后,脚本在命令行中显示计算出的量。加载
euclidean_data.mat
是在调用核心算法之前执行的预处理步骤。显示结果是后处理步骤。% Load test data load euclidean_data.mat % Determine closest and farthest points and corresponding distances [y_min,y_max,idx,distance] = euclidean(x,cb); % Display output for the closest point disp('Coordinates of the closest point are: '); disp(num2str(y_min')); disp(['Index of the closest point is ', num2str(idx(1))]); disp(['Distance to the closest point is ', num2str(distance(1))]); disp(newline); % Display output for the farthest point disp('Coordinates of the farthest point are: '); disp(num2str(y_max')); disp(['Index of the farthest point is ', num2str(idx(2))]); disp(['Distance to the farthest point is ', num2str(distance(2))]);
MATLAB 脚本
test_2d.m
是表示二维欧几里德空间中点的test.m
的修改版。test_2d.m
的内容将在本教程后面显示,您可以使用它来针对可变大小输入测试 MEX 函数。编译脚本
build_mex_fixed.m
和build_mex_variable.m
包含的命令可从您的 MATLAB 代码生成 MEX 函数,这两个库分别接受固定大小和可变大小输入。这些脚本的内容显示在本教程后面有关生成 C 代码的部分中。
提示
您可以使用 MATLAB Coder 从 MATLAB 函数生成代码。不支持从 MATLAB 脚本生成代码。
请使用测试脚本将预处理和后处理步骤与实现核心算法的函数分隔开。这种做法使您能够轻松地重用您的算法。您需要为实现核心算法的 MATLAB 函数生成代码。不需要为测试脚本生成代码。
为 MATLAB 函数生成 MEX 函数
运行原始 MATLAB 代码
在 MATLAB 中运行测试脚本 test.m
。输出显示 y
、idx
和 distance
。
Coordinates of the closest point are: 0.8 0.8 0.4 Index of the closest point is 171 Distance to the closest point is 0.080374 Coordinates of the farthest point are: 0 0 1 Index of the farthest point is 6 Distance to the farthest point is 1.2923
使 MATLAB 代码适用于代码生成
为了使您的 MATLAB 代码适用于代码生成,您可以使用代码分析器和代码生成就绪工具。MATLAB 编辑器中的代码分析器会在您输入代码时持续检查代码。它会报告问题,并提出修改建议,以最大程度地提高性能和可维护性。代码生成就绪工具会筛查 MATLAB 代码中是否存在代码生成不支持的功能和函数。
C/C++ 代码生成支持的某些 MATLAB 内置函数和工具箱函数、类以及 System object 有特定的代码生成限制。这些限制和相关使用说明列在其对应参考页的扩展功能部分。有关详细信息,请参阅 C/C++ 代码生成支持的函数和对象。
在 MATLAB 编辑器中打开
euclidean.m
。MATLAB 编辑器右上角的代码分析器消息指示标记为绿色。分析器未在代码中检测到错误、警告或改进机会。在函数声明后面添加
%#codegen
指令:function [y,idx,distance] = euclidean(x,cb) %#codegen
%#codegen
指令提示代码分析器识别特定于代码生成的警告和错误。代码分析器消息指示标记变为红色,表示它检测到代码生成问题。
要查看警告消息,请将光标移到带下划线的代码片段上。警告指示,代码生成要求先对变量
idx
和distance
进行完全定义,然后才可以对它们进行下标索引。出现此警告是因为代码生成器必须在这些变量在代码中首次出现时确定其大小。要解决此问题,请使用ones
函数同时分配和初始化这些数组。% Initialize minimum distance as distance to first element of cb % Initialize maximum distance as distance to first element of cb idx = ones(1,2); distance = ones(1,2)*norm(x-cb(:,1));
代码分析器消息指示标记再次变为绿色,表示它没有再检测到任何代码生成问题。
有关使用代码分析器的详细信息,请参阅使用代码分析器检查代码中的错误和警告。
保存文件。
要运行代码生成就绪工具,请从 MATLAB 命令行调用
coder.screener
函数:coder.screener('euclidean')
该工具不会检测
euclidean
的任何代码生成问题。有关详细信息,请参阅代码生成就绪工具。MATLAB Online™ 不支持代码生成就绪工具。
注意
代码分析器和代码生成就绪工具可能无法检测到所有代码生成问题。消除这两个工具检测到的错误或警告后,使用 MATLAB Coder 生成代码以确定您的 MATLAB 代码是否还存在其他合规性问题。
现在您即可使用 codegen
命令编译您的代码。此处,编译指从您的 MATLAB 代码生成 C/C++ 代码。
注意
编译 MATLAB 代码指从 MATLAB 代码生成 C/C++ 代码。在其他情况下,“编译”可能指 C/C++ 编译器的操作。
定义输入类型
由于 C 使用静态类型,因此在代码生成时(也称为编译时),代码生成器必须确定 MATLAB 文件中所有变量的类、大小和复/实性。因此,在为文件生成代码时,必须指定入口函数的所有输入参数的属性。入口函数是顶层 MATLAB 函数,您可以从中生成代码。
当您使用 codegen
命令生成代码时,请使用 -args
选项指定入口函数的示例输入参数。代码生成器使用这些信息来确定输入参数的属性。
在下一步中,您将使用 codegen
命令从入口函数 euclidean
生成 MEX 文件。
生成并验证 MEX 函数
编译脚本 build_mex_fixed.m
包含用于为 euclidean.m
生成和验证 MEX 函数的命令。要验证 MEX 函数,请运行测试脚本 test
,并将调用 MATLAB 函数 euclidean
替换为调用生成的 MEX 函数。
% Load the test data load euclidean_data.mat % Generate code for euclidean.m with codegen. Use the test data as example input. Validate MEX by using test.m. codegen -report euclidean.m -args {x, cb} -test test
默认情况下,
codegen
在当前文件夹中生成名为euclidean_mex
的 MEX 函数。-report
选项指示codegen
生成代码生成报告,您可使用该报告调试代码生成问题,并验证您的 MATLAB 代码是否适用于代码生成。-args
选项指定入口函数euclidean
的示例输入参数。代码生成器使用这些信息来确定输入参数的类、大小和复/实性。您使用
-test
选项运行测试文件test.m
。此选项将测试文件中对euclidean
的调用替换为对euclidean_mex
的调用。
有关代码生成选项的详细信息,请参阅 codegen
。
运行编译脚本
build_mex_fixed.m
。代码生成器在当前工作文件夹中生成 MEX 函数
euclidean_mex
。输出为:
此输出与原始 MATLAB 函数生成的输出相匹配,并验证 MEX 函数。Code generation successful: View report. Running test file: 'test' with MEX function 'euclidean_mex'. Coordinates of the closest point are: 0.8 0.8 0.4 Index of the closest point is 171 Distance to the closest point is 0.080374 Coordinates of the farthest point are: 0 0 1 Index of the farthest point is 6 Distance to the farthest point is 1.2923
要在报告查看器中查看代码生成报告,请点击查看报告。
如果代码生成器在代码生成过程中检测到错误或警告,报告将说明问题并提供有问题的 MATLAB 代码的链接。请参阅Code Generation Reports。
提示
在命令行使用编译脚本生成代码。编译脚本自动执行您在命令行重复执行的一系列 MATLAB 命令,可帮助您节省时间和消除输入错误。
为可变大小输入生成 MEX 函数
您为 euclidean.m
生成的 MEX 函数只能接受与您在代码生成期间指定的样本输入具有相同大小的输入。但是,对应的 MATLAB 函数的输入数组可以具有任意大小。在本教程的此部分,您将从 euclidean.m
中生成接受可变大小输入的 MEX 函数。
假设您希望生成的 MEX 函数中的 x
和 cb
的维度具有以下属性:
x
和cb
的第一个维度的大小为可变大小,但不超过3
。x
的第二个维度具有固定大小,其值为1
。cb
的第二个维度的大小为可变大小,但不超过216
。
要指定这些输入属性,请使用 coder.typeof
函数。coder.typeof(A,B,1)
指定一个可变大小的输入,其类和复/实性与 A
相同,其上限由大小向量 B
的对应元素给出。使用编译脚本 build_mex_variable.m
,该脚本使用 coder.typeof
在生成的 MEX 函数中指定可变大小输入的属性。
% Load the test data load euclidean_data.mat % Use coder.typeof to specify variable-size inputs eg_x=coder.typeof(x,[3 1],1); eg_cb=coder.typeof(cb,[3 216],1); % Generate code for euclidean.m using coder.typeof to specify % upper bounds for the example inputs codegen -report euclidean.m -args {eg_x,eg_cb}
您可以验证新 MEX 函数 euclidean_mex
是否接受不同于 x
和 cb
的维度输入。测试脚本 test_2d.m
创建输入数组 x2d
和 cb2d
,它们分别是 x
和 cb
的二维版本。然后,它使用这些输入参数调用 MATLAB 函数 euclidean
。
% Load the test data load euclidean_data.mat % Create 2-D versions of x and cb x2d=x(1:2,:); cb2d=cb(1:2,1:6:216); % Determine closest and farthest points and corresponding distances [y_min,y_max,idx,distance] = euclidean(x2d,cb2d); % Display output for the closest point disp('Coordinates of the closest point are: '); disp(num2str(y_min')); disp(['Index of the closest point is ', num2str(idx(1))]); disp(['Distance to the closest point is ', num2str(distance(1))]); disp(newline); % Display output for the farthest point disp('Coordinates of the farthest point are: '); disp(num2str(y_max')); disp(['Index of the farthest point is ', num2str(idx(2))]); disp(['Distance to the farthest point is ', num2str(distance(2))]);
运行 test_2d.m
会生成以下输出:
Coordinates of the closest point are: 0.8 0.8 Index of the closest point is 29 Distance to the closest point is 0.078672 Coordinates of the farthest point are: 0 0 Index of the farthest point is 1 Distance to the farthest point is 1.1357
要运行测试脚本 test_2d.m
并将对 euclidean
的调用替换为对 euclidean_mex
的调用,请使用 coder.runTest
。
coder.runTest('test_2d','euclidean')
x
和 cb
的维度输入。接下来的步骤
目的 | 更多信息 |
---|---|
了解对 MATLAB 内置函数和工具箱函数、类和 System object 的代码生成支持 | |
生成 C++ MEX 代码 | |
以交互方式创建和编辑输入类型 | |
优化所生成的代码的执行速度或内存使用量。 | |
了解代码生成报告 | |
在 MATLAB 探查器中查看生成的 MEX 函数的执行时间和代码覆盖率 |