Matlab 連結 C/C++ 動態函式庫
| 元月 05, 2006 | 7個迴響| 沒有引用| 6762 reads | Size: L, M, S | Edit: P, C, R || Category: Programming. |
剛剛在網路上看到的,還滿特別的使用方法。
通常,要利用 MATLAB 矩陣運算的方便,和 C/C++ 的高效能,都會使用 MATLAB 的 C Libary。不過剛剛看到這的這篇,原來還可以這樣玩,大開眼界了。
怕文章不見,轉錄在內文。
UPDATE 2006-12-27: 看來作者也受 天空事件 影響,所以自架主機。修正一下連結,感謝告知!
「程式開始跑了,我們去喝個下午茶再回來吧…」
「記憶體又不夠了,老闆,我想買RAM…」
只要你是 Matlab 重度使用者,相信你都遇過前面兩個問題。即使 7.0 版已經大幅改善速度,但執行時間永遠都嫌慢。「向量化」這個老問題,總是使得需要的執行記憶體大幅膨脹。偏偏 Matlab 內建的眾多運算函式,再再讓你無法脫離它的魔掌。
受不了了嗎?解決之道之一就是「連結 C/C++ 動態函式庫」!
在決定使用 C/C++ 函式庫之前,你應該先用 profile reporter 確定你程式的效能瓶頸,這通常是一個被呼叫非常多次,或需要非常大記憶體的函式。確認效能瓶頸後,才針對函式製作 C/C++ 版本。
【撰寫C/C++函式】
製作 C/C++ 版本函數並不困難。絕大多數情況下,需要撰寫的,僅是一個「在 Matlab 與 C/C++ 之間轉換變數」的中界函數。
1. 引入標頭檔 "mex.h"
在 C/C++ 函式的前端,加入
#include "mex.h" 這是包含有 Matlab 矩陣型態定義及協助函式 prototype 的標頭檔。
2. 撰寫 mexFunction 函數
mexFunction 函數為程式的進入點,它有規定好之 prototype ,不可隨意更動:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
這個函數包含四個引數,分別代表呼叫該函式時,輸出與輸入之矩陣。我們知道 Matlab 函式允許多個參數輸入與多個參數輸出,例如:
[M, I] = larger(A, B);
但 C/C++ 語言僅允許單一參數輸出,因此 mexFunction 必須將函式等號左邊之輸出參數移到右邊,方可順利輸出參數。mexFunction中四個參數分別代表:
nlhs:呼叫函式時,等號左邊的變數數目,即 plhs 之個數。
plhs:呼叫函式時,等號左邊之變數本體。
nrhs:呼叫函式時,等號右邊的變數數目,即 prhs 之個數。
prhs:呼叫函式時,等號右邊之變數本體。在上例中,nlhs=nrhs=2。若呼叫
M = larger(A, B);
則 nlhs=1,nrhs=2。
Matlab 中所有的矩陣型態,在 C/C++ 中都以 mxArray 型態表示。 plhs 及 prhs 之變數型態均為 mxArray **,即為「指向 Matlab 矩陣之指標陣列」,在兩個輸出參數的例子中,plhs[0] 指向 M ,而 plhs[1] 指向 I ,prhs[0] 指向 A ,prhs[1]則指向 B。
3. 將 Matlab 矩陣轉換為 C/C++ 陣列
Matlab 提供一系列函式,協助你將 Matlab 矩陣轉換為 C/C++ 之陣列。此處僅介紹必須用到的幾個函式,其他的請參考 Matlab 手冊中 MX-Functions 的部分。
˙mxGetPr:取得矩陣之實數部分。
利用該函數可將矩陣之實數部分取出,函式將回傳一個 double * 指向資料的開頭。無論原始矩陣的維度(dimension)是多少,在 C/C++ 中均以一維陣列表示,故使用時必須自行計算正確之index。函數的 prototype 為
double *mxGetPr(const mxArray *array_ptr);
另有類似函數 mxGetPi ,可取得矩陣之虛數部分。
˙mxGetM:取得矩陣之第一維大小
該函數將傳回一整數(int型態),為矩陣之第一維大小。其 prototype 為
int mxGetM(const mxArray *array_ptr);
第二維大小則可由 mxGetN 取得。若為多維矩陣,請參考 mxGetNumberOfDimensions 及 mxGetDimensions 函數。
搭配組合上述函式,我們可以把
[M, I] = larger(A, B);
之 A 引入 C/C++ 內:
double *A;
int mA, nA;
A = mxGetPr(prhs[0]);
mA = mxGetM(prhs[0]);
nA = mxGetN(prhs[0]);如此便可使用 A[i] 來存取輸入矩陣了。
4. 配置輸出矩陣之記憶體空間
函數之輸出矩陣,亦必須是 Matlab 矩陣,其大小及內容是由 C/C++ 函式決定,故記憶體空間亦須函式配置。
˙mxCreateDoubleMatrix:創造一個二維 Matlab 矩陣
利用本函數,可以創造一個任意大小、實數或複數型態的二維 Matlab 矩陣。其 prototype 為
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag);
我們需給定矩陣的大小(m-by-n),以及矩陣的型態(mxREAL或mxCOMPLEX擇一),函式會創造一個 Matlab 矩陣,配置足夠的空間,並回傳一個 mxArray 指標指向新矩陣。
若要創造多維矩陣或非實數或虛數型態之矩陣,參考 mxCreateNumericArray 以及 mxCreateNumericMatrix 。
現在我們可以配置 M 與 I 的空間了:
double *M, *I;
plhs[0] = mxCreateDoubleMatrix(mA, nA, mxREAL);
M = mxGetPr(plhs[0]);
plhs[1] = mxCreateDoubleMatrix(mA, nA, mxREAL);
I = mxGetPr(plhs[1]);我們將 M 與 I 設定為與 A 相同大小之實數矩陣,並取出其資料指標備用。
現在我們已經將參數引入 C/C++ 中,亦配置好輸出參數的空間,接下來可依正常 C/C++ 語法撰寫函式的功能部分。
下一篇文章我們將討論如何編譯撰寫好的 C/C++ 函式庫。
最後列出完整的 mexFunction 供參考,該函數接受兩個輸入 A 及 B ,輸出 M 的每一個元素,取自 A 與 B 相對位置中較大的數值,以及一個索引 I 表示 M 的元素取自 A 或 B:
#include "mex.h" |
我們已經寫好了 C/C++ 函式庫,接下來要把它編譯成 DLL 檔。
我們仍然以前文的程式為例子,我們將 C/C++ 函式庫存檔為 larger.c ,開啟 Matlab 並將工作目錄切換至 larger.c 存檔的目錄。
在 Matlab 下編譯 C/C++ 函式庫的指令為 mex ,但在使用 mex 之前,必須先設定編譯器的種類和參數。若你是第一次使用 mex ,系統會自動提示你選擇一個編譯器:
>> mex Select a compiler: [1] Lcc C version 2.4 in C:PROGRAM FILESMATLAB704syslcc [0] None Compiler: |
mex 會自動偵測並列出你的電腦中已安裝的合適編譯器, 由於我的電腦並沒有安裝 C/C++ 編譯器,因此 mex 僅列出 Matlab 內建之 Lcc 編譯器。若你有安裝其他編譯器,請選擇你偏愛的編譯器。這個步驟僅需設定一次, Matlab 會記下你選擇的編譯器,以後都會自動使用,若需選擇不同的編譯器,你必須執行:
| >> mex -setup |
指令,重新選擇一個編譯器。
選擇好編譯器之後,便可以編譯我們的程式,只需要輸入
| >> mex larger.c |
若程式順利結束,現在你應該可以在同一目錄下看見 larger.dll ,這便是編譯好的函式庫。
接下來我們來測試編譯好的函式:
>> A=[1 2 3; 4 5 6; 7 8 9]; M = 9 8 7 >> I I = 1 1 1 >> |
你也可以測試一下 M=larger(A,B); 是否能正常工作。接著嘗試一下:
>> larger(A,B) ------------------------------------------------------------------------ (以下刪除) |
出現了一大串的錯誤,這是因為函式庫沒有考慮「沒有指定任何輸出」,即 nlhs=0 時的情形。一般來說,函式在沒有指定輸出的情況下,應傳回一個輸出參數。因此,我們只需要將
if(nlhs==1)
修正為
if(nlhs<=1)
即可解決這個問題。
現在你已經會使用 C/C++ 撰寫及編譯 Matlab 函式庫了,開始享受 Matlab 的便利和 C/C++ 的高執行效率吧。
隨機文章:
» 撰寫快速的 MATLAB 程式碼
» Del.icio.us、Furl、NewsGator 的 聯播 Linkroll
» 在文章上加入「Add To Del.icio.us」「Add To Furl」連結
» LifeType 與 中部的學校
» LifeType - pLog 的新名字


這篇文章很棒!!!
給你最高的推薦~