鑑於信息Polygon
是2維的,point
是行向量和其他變量是標量,這裏是你的新功能的第一個版本(向下滾動看到,有很多方法對皮膚這個貓):
function [result] = newHitTest (point,Polygon,r,tol,stepSize)
result = 0;
linDiff = Polygon-repmat(point,size(Polygon,1),1);
testLogicals = sqrt(sum((linDiff).^2 ,2)) < tol*r;
if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end
在Matlab矢量化的思想過程涉及嘗試使用單個命令操作儘可能多的數據。大多數基本的Matlab內置函數在多維數據上運行非常高效。使用for
循環與此相反,因爲您正在將數據分解爲更小的數據段進行處理,每個數據段都必須單獨解釋。通過使用for
循環進行數據分解,您可能會失去與Matlab內置函數背後的高度優化代碼相關的一些大規模性能優勢。
在您的示例中首先要考慮的是主循環中的條件中斷。你無法從矢量化過程中解脫出來。相反,計算所有可能性,爲每行數據創建一個結果數組,然後使用關鍵字any
來查看是否有任何行已發出信號表明circleTest
函數應該被調用。
注意:在Matlab中有效地有條件地打破計算並不容易。但是,由於您只是在循環中計算歐幾里德距離,所以通過使用矢量化版本和計算所有可能性,您可能會看到性能提升。如果循環中的計算更加昂貴,輸入數據很大,並且一旦遇到特定條件就想要分解,那麼使用編譯語言編寫的matlab擴展可能比矢量化版本快得多你可能正在執行不必要的計算。然而,這是假設您知道如何編寫與編譯爲本地代碼的語言相匹配的Matlab內置函數性能的代碼。
回到主題...
做的第一件事就是把Polygon
和你的行向量point
之間(在代碼示例linDiff
)線性差。要以矢量化的方式進行此操作,2個變量的尺寸必須相同。達到此目的的一種方法是使用repmat
複製point
的每一行,使其與Polygon
的大小相同。然而,bsxfun
通常是一個更好的選擇repmat(as described in this recent SO question),使得代碼...
function [result] = newHitTest (point,Polygon,r,tol,stepSize)
result = 0;
linDiff = bsxfun(@minus, Polygon, point);
testLogicals = sqrt(sum((linDiff).^2 ,2)) < tol*r;
if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end
我通過在第二軸求和軋製您d
值成d
列(注意去除所述陣列的Polygon
的索引和在sum
命令中增加,2
)。然後,我進一步深入並評估邏輯陣列testLogicals
與距離測量的計算內嵌。您很快就會發現重矢量化的一個缺點就是它可以讓那些不熟悉Matlab的人對代碼的可讀性降低,但性能提升是值得的。評論是非常必要的。
現在,如果你想完全瘋狂,你可能會認爲測試函數非常簡單,因此它保證使用'匿名函數'或'lambda'而不是完整的函數定義。測試是否值得執行circleTest
不需要參數stepSize
,這也許是使用匿名函數的另一個原因。您可以將測試轉換爲匿名函數,然後在調用腳本中使用circleTest
,從而使代碼在某種程度上自行記錄。 。 。
doCircleTest = @(point,Polygon,r,tol) any(sqrt(sum(bsxfun(@minus, Polygon, point).^2, 2)) < tol*r);
if doCircleTest(point,Polygon,r,tol)
result = circleTest (point,Polygon,r,tol,stepSize);
else
result = 0;
end
現在一切都是向量化的,使用函數句柄給了我另一個想法。 。 。
如果您計劃在代碼中的多個點執行此操作,那麼if
語句的重複會變得有點難看。要保持dry,將條件函數的測試放入單個函數似乎是明智的,就像您在原始文章中所做的那樣。但是,該函數的實用程序將非常狹窄 - 它只會測試circleTest
函數是否應該執行,然後在需要時執行它。
現在想象一下,過了一段時間,您還有其他一些條件函數,就像circleTest
一樣,其自身等效於doCircleTest
。也許重用條件轉換代碼會很好。對於這一點,讓喜歡你原來的一個函數,它的默認值,計算上廉價的測試功能的布爾結果,以及與其相關的參數的昂貴條件函數的功能手柄...
function result = conditionalFun(default, cheapFunResult, expensiveFun, varargin)
if cheapFunResult
result = expensiveFun(varargin{:});
else
result = default;
end
end %//of function
你可以使用以下命令從主腳本調用此函數。 。 。
result = conditionalFun(0, doCircleTest(point,Polygon,r,tol), @circleTest, point,Polygon,r,tol,stepSize);
...它的美麗之處在於您可以使用任何測試,默認值和昂貴的功能。這個簡單的例子可能有點矯枉過正,但是當我提出使用函數句柄的想法時,它就是我思緒徘徊的地方。
感謝您的解釋。它確實有幫助。但還有一個問題..當我運行向量化代碼時,我會得到以下的錯誤信息。 '錯誤使用 - 矩陣尺寸必須一致。' 我們從矩陣中減去一個定標器,錯誤不應該出現。 – Vikram
在哪一行?假設點,r和tol是標量,Polygon是二維數據,那麼我的代碼就完全符合你的想法。 – learnvst
here..'(多邊形點)' – Vikram