{"id":269,"date":"2013-04-12T23:02:05","date_gmt":"2013-04-12T23:02:05","guid":{"rendered":"http:\/\/www.timokorthals.de\/?p=269"},"modified":"2016-12-28T00:12:47","modified_gmt":"2016-12-27T23:12:47","slug":"matlab-build-in-vs-mex-vs-naiv","status":"publish","type":"post","link":"http:\/\/www.timokorthals.de\/?p=269","title":{"rendered":"Matlab: Build-In vs. MEX vs. &#8220;naiv&#8221; loops"},"content":{"rendered":"<p>Ich wurde vor kurzem nach einem Minimalbeispiel f\u00fcr eine MEX-Funktion in MATLAB gefragt, da ich so davon geprahlt habe. Wer MEX nicht kennt, dass sind &#8220;MATLAB EXecutables&#8221;, welche in C\/C++ oder Fortran geschrieben werden k\u00f6nnen. Sofern man diese dann mit dem MEX-Compiler \u00fcbersetzen kann, ruft man sie <em>straight-forward<\/em> aus einem Matlab-Skript auf. Dies f\u00fchrt <span style=\"text-decoration: underline;\">unter Umst\u00e4nden<\/span> zu einem gewaltigen Geschwindigkeitsschub, in Bezug auf eine gleiche Implementierung in MATLAB.<\/p>\n<p>Als Minimalbeispiel habe ich mir die Spaltensummenfunktion \u00fcberlegt, welche alle Zeileneintr\u00e4ge einer Spalte subsummiert. In Matlab ist diese bereits implementiert und kann wie folgt genutzt werden:<!--more--><\/p>\n<pre class=\"lang:matlab decode:true\">&gt;&gt; sum([ 1 2 3; 1 2 3])\r\nans =\r\n     2   4   6<\/pre>\n<p>Eine \u00e4quivalente MEX-Funktion sieht wie folgt aus:<\/p>\n<pre class=\"lang:matlab decode:true\" title=\"sumcol.cpp\">#include \"mex.h\"\r\n\r\n\/\/ By Timo Korthals\r\n\/\/ Add, for the cols of a matrix:    [ 2 4 6 ] = sumcol([1 2 3;1 2 3])\r\n\r\ndouble ColSum(double* matrix, double* colSumMatrix, unsigned int NumRows, unsigned int NumCols) {\r\n    \/\/ Iterate through every col\r\n    for(unsigned int IdxCol = 0; IdxCol &lt; NumCols; IdxCol++) {\r\n        \/\/ Iterate through every row\r\n        colSumMatrix[IdxCol] = matrix[IdxCol*NumRows];\r\n        for(unsigned int IdxRow = 1; IdxRow &lt; NumRows; IdxRow++) {\r\n            colSumMatrix[IdxCol] += matrix[IdxRow+IdxCol*(NumRows)];\r\n        }\r\n    }\r\n}\r\n\r\nvoid mexFunction(int nlhs,       mxArray *plhs[ ],\r\n                 int nrhs, const mxArray *prhs[ ]) {\r\n    \/\/ Some declarations\r\n    double* matrix;\r\n    double* colSumMatrix;\r\n    unsigned int NumRows = mxGetM(prhs[0]);\r\n    unsigned int NumCols = mxGetN(prhs[0]);\r\n\r\n    \/\/ Alloc output\r\n    plhs[0] = mxCreateDoubleMatrix(1, NumCols, mxREAL);\r\n\r\n    \/\/ Assigne matrix to the input\r\n    matrix       = mxGetPr(prhs[0]);\r\n    \/\/ Assigne colSumMatrix to the output\r\n    colSumMatrix = mxGetPr(plhs[0]);\r\n\r\n    \/\/ Calculate the col.-sum\r\n    ColSum(matrix, colSumMatrix, NumRows, NumCols);\r\n}<\/pre>\n<p>Der obige code kann als colsum.cpp gespeichert werden und wie folgt kompiliert und ausgef\u00fchrt werden:<\/p>\n<pre class=\"lang:matlab decode:true \">&gt;&gt; mex sumcol.cpp; sumcol([1 2 3;1 2 3])\r\nans =\r\n     2   4   6<\/pre>\n<h1 style=\"text-align: center;\">Evaluierung<\/h1>\n<p>Nun kommt der spannende Teil. Wie macht sich die MEX-Funktion im Vergleich zu einer naiven Schleifen-, semi-naiven Schleifen- und der MATLAB-Build-In-Implementierung. Hier ein kleines Evaluationsskript in MATLAB:<\/p>\n<pre class=\"lang:matlab decode:true \">%% Init\r\nNumCols = 10000;\r\nNumRows = 10000;\r\nA = ones(NumRows, NumCols);\r\nColSum = zeros(1, NumCols);\r\n\r\n%% (1) Matlab naive implementation\r\nColSum = zeros(1, NumCols);\r\ntic\r\nfor ColIdx = 1 : NumCols\r\n    for RowIdx = 1 : NumRows\r\n      ColSum(ColIdx) = ColSum(ColIdx) + A(RowIdx, ColIdx);\r\n    end\r\nend\r\nfprintf('(1) Naive:      %f s\\n',toc);\r\n\r\n%% (2) Matlab semi-naive implemention\r\nColSum = zeros(1, NumCols);\r\ntic\r\nfor ColIdx = 1 : NumCols\r\n    ColSum(ColIdx) = sum(A(:, ColIdx));\r\nend\r\nfprintf('(2) Semi-naive: %f s\\n',toc);\r\n\r\n%% (3) Matlab build-in implemention\r\nColSum = zeros(1, NumCols);\r\ntic\r\nColSum = sum(A);\r\nfprintf('(3) Build-in:   %f s\\n',toc);\r\n\r\n%% (4) MEX implemention\r\nColSum = zeros(1, NumCols);\r\ntic\r\nColSum = sumcol(A);\r\nfprintf('(4) MEX:        %f s\\n',toc);<\/pre>\n<p>Hier die Auswertung des Skriptes auf einem i7 970:<\/p>\n<div>(1) ist buchst\u00e4blich die Umsetzung der Mex-Funktion in Matlab -&gt; <strong> ca 8 s<\/strong><\/div>\n<div>(2) unter Teil-Ausnutzung der sum()-Funktion von Matlab -&gt; <strong>ca 0.25 s<\/strong><\/div>\n<div>(3) unter Ausnutzung der sum()-Funktion von Matlab -&gt; <strong> ca 0.07 s<\/strong><\/div>\n<div>(4) MEX-Funktion -&gt; <strong>ca 0.4 s<\/strong><\/div>\n<div><\/div>\n<div>Es gilt also bei MATLAB immer folgendes zu beachten, wenn es um Implementierungen mittels Schleifen geht:<\/div>\n<div><\/div>\n<h1><strong>MATLAB-BuildIn-Funktionen <span style=\"color: #ff0000;\">vor<\/span> MEX-Funktionen <span style=\"color: #ff0000;\">evtl. vor<\/span> Schleifen verwenden!<\/strong><\/h1>\n<div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Ich wurde vor kurzem nach einem Minimalbeispiel f\u00fcr eine MEX-Funktion in MATLAB gefragt, da ich so davon geprahlt habe. Wer MEX nicht kennt, dass sind &#8220;MATLAB EXecutables&#8221;, welche in C\/C++ oder Fortran geschrieben werden k\u00f6nnen. Sofern man diese dann mit dem MEX-Compiler \u00fcbersetzen kann, ruft man sie straight-forward aus einem Matlab-Skript auf. Dies f\u00fchrt unter &hellip; <a href=\"http:\/\/www.timokorthals.de\/?p=269\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Matlab: Build-In vs. MEX vs. &#8220;naiv&#8221; loops<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1,8,4,6],"tags":[],"_links":{"self":[{"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/posts\/269"}],"collection":[{"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=269"}],"version-history":[{"count":3,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/posts\/269\/revisions"}],"predecessor-version":[{"id":401,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=\/wp\/v2\/posts\/269\/revisions\/401"}],"wp:attachment":[{"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=269"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=269"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.timokorthals.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=269"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}