如何加速Matlab 程式

在使用Matlab時或許有人發現,當迴圈的數目增加到三個以上時,計算的速度會突然變慢。這是Matlab 這套軟體的特性,因此,減少迴圈的數目就成了撰寫Matlab script 一個重要的藝術。

在一般的程式語言中,要避開三個迴圈以上的程式並不容易,也不會因為if than 判斷式增加,就大幅降低計算的速度。但是在Matlab 裡面,判斷式和迴圈只要超過三階以上,就會拖慢整體運算的速度。還好,Matlab 有幾個很特別的運算子是專門提供給矩陣計算使用的,利用這些運算子,可以巧妙的讓迴圈數目減少,達到增加運算速度的目的。

首先要介紹 colon 運算子,在Matlab 裡面,":" 這個冒號指令可以省下許多需要寫for 迴圈的指令,例如

x = 1:100;

可以產生一個由1 遞增到100,間隔為1的向量,並且存入變數x。

這個效果和

for i = 1 : 100

  x(i)=i;

end

是一樣的。

colon 有許多應用的變化形式,例如,要製造出一個間隔為5,以37 為起始值,大於-100的遞減序列。我們使用

x = 37:-5:-100;

來達成,在兩個colon 之間的數字,代表遞增的間隔,若為負數表示遞減數列。

第二,是善用index。 Matlab 中要提取一個向量或是矩陣的部份元素,直接把需要的index 餵到矩陣當中,是最快的方法。例如我們要提取矩陣A的第1 個row。作法是

r = A(1,:);

這裡的"1" 代表row 的第一個元素,":" 代表column 的第一個到最後一個元素。":" 前後都沒有加東西,代表所有(從頭到尾)的意思。再舉一個例子:

B 是提取A 的奇數列和偶數行的元素所成的一個新矩陣,我們若使用for 迴圈的寫法,程式為

[m,n] = size(A);

for i = 1 :floor( m/2)

    for j =  1: floor(n/2)

         B(i,j) = A(2*i-1,2*j);

    end

end

其中,size() 是計算A 矩陣大小的函數,floor(n) 是取小於等於n 又最靠近n 的整數。這裡我們使用了兩個迴圈才達到目的,事實上,我們可以用下列簡單的方式達到同樣的目的。

B = A(1:2:end,2:2:end);

在A 矩陣的行與列中加入適當的index 便可以達到目的,colon 後面的 "end" 表示最大可能的數字,這樣使用者不需要特別去記住或計算到底最後一個數字是多少。

除了透過colon 製造出我們想要的index 之外,有時候我們可以用find() 指令或是一些邏輯判斷式來簡化程式。舉例來說,要找出A 矩陣中大於0 的元素,並且將其設成0,用傳統的寫法,我們會使用兩個for 迴圈在加上一個判斷式。

[m,n] = size(A);

for i = 1 : m

    for j = 1 : n

        if A(i,j)>0

            A(i,j)=0;

        end

    end

end

在Matlab 裡面 A>0; 這一個指令,會造出一個和A 大小一樣的矩陣,若A(i,j) >0 對應的元素就是1反之為0。所以,上述的程式可以簡化成一行,就是

A(A>0)=0;

括號內的A>0 提供滿足判斷式的元素的位置,然後A(滿足判斷式的index)=0,把對應的index 的元素設成0。經過這樣的修改,馬上降低的for 迴圈的使用量,也增加了Matlab 的運算速度。find() 指令也有類似的效果,上述程式也可以改寫成

A(find(A>0))=0;

其結果相同。

最後,Matlab 提供的.*,./ 以及.^ 運算子也可以用來減少迴圈的數目。例如,要將相同大小的A,B 矩陣的對應元素相乘,然後存到C 矩陣。傳統的寫法是

[m,n] = size(A);

C = zeros(m,n);

for i = 1 : m

    for j = 1 : n

        C(i,j) = A(i,j)*B(i,j);

    end

end

這裡我們使用了兩個迴圈,然而,用.* 運算子,我們可以將上述程式簡化成

C = A.*B;

.* 的意思是對應元素相乘,同理,./ 就是對應元素相除。

透過以上的介紹,我們知道,透過 Matlab  所提供的特殊運算指令以及算子,可以減少使用for 迴圈的機會,這樣就可以增加Maltab 的運算速度了。