<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Toolbox &#8211; Undocumented Matlab</title>
	<atom:link href="https://undocumentedmatlab.com/articles/tag/toolbox/feed" rel="self" type="application/rss+xml" />
	<link>https://undocumentedmatlab.com</link>
	<description>Professional Matlab consulting, development and training</description>
	<lastBuildDate>Mon, 17 Aug 2020 08:29:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.2</generator>
	<item>
		<title>Speeding-up builtin Matlab functions – part 3</title>
		<link>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-3?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=speeding-up-builtin-matlab-functions-part-3</link>
					<comments>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-3#comments</comments>
		
		<dc:creator><![CDATA[Yair Altman]]></dc:creator>
		<pubDate>Mon, 06 Apr 2020 20:44:07 +0000</pubDate>
				<category><![CDATA[Low risk of breaking in future versions]]></category>
		<category><![CDATA[Stock Matlab function]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Pure Matlab]]></category>
		<guid isPermaLink="false">http://undocumentedmatlab.com/?p=11059</guid>

					<description><![CDATA[<p>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example.  </p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-3">Speeding-up builtin Matlab functions – part 3</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 2">Speeding-up builtin Matlab functions &#8211; part 2 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 1">Speeding-up builtin Matlab functions &#8211; part 1 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<p>A recurring theme in this website is that despite a common misperception, builtin Matlab functions are typically coded for maximal accuracy and correctness, but not necessarily best run-time performance. Despite this, we can often identify and fix the hotspots in these functions and use a modified faster variant in our code. I have shown multiple examples for this in various posts (<a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1" target="_blank">example1</a>, <a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2" target="_blank">example2</a>, <a href="https://undocumentedmatlab.com/articles/tag/performance" target="_blank">many others</a>). </p>
<p>Today I will show another example, this time speeding up the <i><b>mvksdensity</b></i> (multi-variate kernel probability density estimate) function, part of the Statistics toolbox since R2016a. You will need Matlab R2016a or newer with the Stats Toolbox to recreate my results, but the general methodology and conclusions hold well for numerous other builtin Matlab functions that may be slowing down your Matlab program. In my specific problem, this function was used to compute the probability density-function (PDF) over a 1024&#215;1024 data mesh. </p>
<p>The builtin <i><b>mvksdensity</b></i> function took <b>76 seconds</b> to run on my machine; I got this down to <b>13 seconds</b>, a <b>6x speedup</b>, without compromising accuracy. Here&#8217;s how I did this:</p>
<h3 id="preparation">Preparing the work files</h3>
<p>While we could in theory modify Matlab&#8217;s installed m-files if we have administrator privileges, doing this is not a good idea for several reasons. Instead, we should copy and rename the relevant internal files to our work folder, and only modify our local copies.</p>
<p>To see where the builtin files are located, we can use the <b><i>which</i></b> function:</p>
<pre lang="matlab">
>> which('mvksdensity')
C:\Program Files\Matlab\R2020a\toolbox\stats\stats\mvksdensity.m
</pre>
<p>In our case, we copy <i>\toolbox\stats\stats\mvksdensity.m</i> as <i>mvksdensity_.m</i> to our work folder, replace the function name at the top of the file from <code>mvksdensity</code> to <code>mvksdensity_</code>, and modify our code to call <i><b>mvksdensity_</b></i> rather than <i><b>mvksdensity</b></i>. </p>
<p>If we run our code, we get an error telling us that Matlab can&#8217;t find the <i><b>statkscompute</b></i> function (in line #107 of our <i>mvksdensity_.m</i>). So we find <i>statkscompute.m</i> in the <i>\toolbox\stats\stats\private\</i> folder, copy it as <i>statkscompute_.m</i> to our work folder, rename its function name (at the top of the file) to <code>statkscompute_</code>, and modify our <i>mvksdensity_.m</i> to call <i><b>statkscompute_</b></i> rather than <i><b>statkscompute</b></i>:</p>
<pre lang="matlab">[fout,xout,u] = statkscompute_(ftype,xi,xispecified,npoints,u,L,U,weight,cutoff,...</pre>
<p>We now repeat the process over and over, until we have all copied all the necessary internal files for the program to run. In our case, it tuns out that in addition to <i>mvksdensity.m</i> and <i>statkscompute.m</i>, we also need to copy <i>statkskernelinfo.m</i>. </p>
<p>Finally, we check that the numeric results using the copied files are exactly the same as from the builtin method, just to be on the safe side that we have not left out some forgotten internal file.</p>
<p>Now that we have copied these 3 files, in practice all our attentions will be focused on the <i>dokernel</i> sub-function inside <i>statkscompute_.m</i>, since the profiling report (below) indicates that this is where all of the run-time is spent.</p>
<h3 id="identify">Identifying the hotspots</h3>
<p>Now we run the code through the Matlab Profiler, using the &#8220;Run and Time&#8221; button in the Matlab Editor, or <i><b>profile on/report</b></i> in the Matlab console (Command Window). The results show that 99.8% of <i><b>mvksdensity</b></i>&#8216;s time was spent in the internal <i>dokernel</i> function, 75% of which was spent in self-time (meaning code lines within <i>dokernel</i>):<br />
<center><figure style="width: 640px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" src="https://undocumentedmatlab.com/images/mvksdensity-profile1.png" alt="Initial profiling results - pretty slow..." title="Initial profiling results - pretty slow..." width="640" height="280" /><figcaption class="wp-caption-text">Initial profiling results - pretty slow...</figcaption></figure></center></p>
<p>Let&#8217;s drill into <i>dokernel</i> and see where the problems are:<br />
<center><figure style="width: 764px" class="wp-caption aligncenter"><img decoding="async" src="https://undocumentedmatlab.com/images/mvksdensity-profile2.png" alt="Initial dokernel profiling results" title="Initial dokernel profiling results" width="764" height="464" /><figcaption class="wp-caption-text">Initial dokernel profiling results</figcaption></figure></center></p>
<h3 id="normal">Evaluating the normal kernel distribution</h3>
<p>We can immediately see from the profiling results that a single line (#386) in <i>statkscompute_.m</i> is responsible for nearly 40% of the total run-time:</p>
<pre lang="matlab">fk = feval(kernel,z);</pre>
<p>In this case, <code>kernel</code> is a function handle to the normal-distribution function in <i>\stats\private\statkskernelinfo&gt;normal</i>, which is evaluated 1,488,094 times. Using <i><b>feval</b></i> incurs an overhead, as can be seen by the difference in run-times: line #386 takes 29.55 secs, whereas the <b><i>normal</i></b> function evaluations only take 18.53 secs. In fact, if you drill into the <b><i>normal</i></b> function in the profiling report, you&#8217;ll see that the actual code line that computes the normal distribution only takes 8-9 seconds &#8211; all the rest (~20 secs, or ~30% of the total) is totally redundant function-call overhead. Let&#8217;s try to remove this overhead by calling the <code>kernel</code> function directly:</p>
<pre lang="matlab">fk = kernel(z);</pre>
<p>Now that we have a local copy of <i>statkscompute_.m</i>, we can safely modify the <i>dokernel</i> sub-function, specifically line #386 as explained above. It turns out that just bypassing the <i><b>feval</b></i> call and using the function-handle directly does not improve the run-time (decrease the function-call overhead) significantly, at least on recent Matlab releases (it has a greater effect on old Matlab releases, but that&#8217;s a side-issue). </p>
<p>We now recognize that the program only evaluates the normal-distribution kernel, which is the default kernel. So let&#8217;s handle this special case by inlining the kernel&#8217;s one-line code (from <i>statkskernelinfo_.m</i>) directly (note how we move the condition outside of the loop, so that it doesn&#8217;t get recomputed 1 million times):</p>
<pre lang="matlab" highlight="2,31-32,34">
...
isKernelNormal = strcmp(char(kernel),'normal');  % line #357 
for i = 1:m
    Idx = true(n,1);
    cdfIdx = true(n,1);
    cdfIdx_allBelow = true(n,1);
    for j = 1:d
        dist = txi(i,j) - ty(:,j);
        currentIdx = abs(dist) <= halfwidth(j);
        Idx = currentIdx &#038; Idx; % pdf boundary
        if iscdf
            currentCdfIdx = dist >= -halfwidth(j);
            cdfIdx = currentCdfIdx & cdfIdx; %cdf boundary1, equal or below the query point in all dimension
            currentCdfIdx_below = dist - halfwidth(j) > 0;                   
            cdfIdx_allBelow = currentCdfIdx_below & cdfIdx_allBelow; %cdf boundary2, below the pdf lower boundary in all dimension
        end
    end
    if ~iscdf
        nearby = index(Idx);
    else
        nearby = index((Idx|cdfIdx)&(~cdfIdx_allBelow));
    end
    if ~isempty(nearby)
        ftemp = ones(length(nearby),1);
        for k =1:d
            z = (txi(i,k) - ty(nearby,k))./u(k);
            if reflectionPDF
                zleft  = (txi(i,k) + ty(nearby,k)-2*L(k))./u(k);
                zright = (txi(i,k) + ty(nearby,k)-2*U(k))./u(k);
                fk = kernel(z) + kernel(zleft) + kernel(zright);  % old: =feval()+...
            elseif isKernelNormal
                fk = exp(-0.5 * (z.*z)) ./ sqrt(2*pi);
            else
                fk = kernel(z);  %old: =feval(kernel,z);
            end
            if needUntransform(k)
                fk = untransform_f(fk,L(k),U(k),xi(i,k));
            end
            ftemp = ftemp.*fk;
        end
        f(i) = weight(nearby) * ftemp;
    end
    if iscdf && any(cdfIdx_allBelow)
        f(i) = f(i) + sum(weight(cdfIdx_allBelow));
    end
end
...
</pre>
<p>This reduced the kernel evaluation run-time from ~30 secs down to 8-9 secs. Not only did we remove the direct function-call overhead, but also the overheads associated with calling a sub-function in a different m-file. The total run-time is now down to <b>45-55</b> seconds (expect some fluctuations from run to run). Not a bad start.</p>
<h3 id="loop-bottom">Main loop &#8211; bottom part</h3>
<p>Now let&#8217;s take a fresh look at the profiling report, and focus separately on the bottom and top parts of the main loop, which you can see above. We start with the bottom part, since we already messed with it in our fix to the kernel evaluation:</p>
<p><center><figure style="width: 550px" class="wp-caption aligncenter"><img decoding="async" src="https://undocumentedmatlab.com/images/mvksdensity-profile3.png" alt="Profiling results for bottom part of the main loop" title="Profiling results for bottom part of the main loop" width="550" height="348" /><figcaption class="wp-caption-text">Profiling results for bottom part of the main loop</figcaption></figure></center></p>
<p>The first thing we note is that there&#8217;s an inner loop that runs d=2 times (d is set in line #127 of <i>mvksdensity_.m</i> &#8211; it is the input mesh&#8217;s dimensionality, and also the number of columns in the <code>txi</code> data matrix). We can easily vectorize this inner loop, but we take care to do this only for the special case of d==2 and when some other special conditions occur. </p>
<p>In addition, we hoist outside of the main loop anything that we can (such as the constant exponential power, and the weight multiplication when it is constant [which is typical]), so that they are only computed once instead of 1 million times:</p>
<pre lang="matlab" highlight="3-8,12-16,34-37,39,45-50">
...
isKernelNormal = strcmp(char(kernel),'normal');
anyNeedTransform = any(needUntransform);
uniqueWeights = unique(weight);
isSingleWeight = ~iscdf && numel(uniqueWeights)==1;
isSpecialCase1 = isKernelNormal && ~reflectionPDF && ~anyNeedTransform && d==2;
expFactor = -0.5 ./ (u.*u)';
TWO_PI = 2*pi;
for i = 1:m
    ...
    if ~isempty(nearby)
        if isSpecialCase1
            z = txi(i,:) - ty(nearby,:);
            ftemp = exp((z.*z) * expFactor);
        else
            ftemp = 1;  % no need for the slow ones()
            for k = 1:d
                z = (txi(i,k) - ty(nearby,k)) ./ u(k);
                if reflectionPDF
                    zleft  = (txi(i,k) + ty(nearby,k)-2*L(k)) ./ u(k);
                    zright = (txi(i,k) + ty(nearby,k)-2*U(k)) ./ u(k);
                    fk = kernel(z) + kernel(zleft) + kernel(zright);  % old: =feval()+...
                elseif isKernelNormal
                    fk = exp(-0.5 * (z.*z)) ./ sqrt(TWO_PI);
                else
                    fk = kernel(z);  % old: =feval(kernel,z)
                end
                if needUntransform(k)
                    fk = untransform_f(fk,L(k),U(k),xi(i,k));
                end
                ftemp = ftemp.*fk;
            end
            ftemp = ftemp * TWO_PI;
        end
        if isSingleWeight
            f(i) = sum(ftemp);
        else
            f(i) = weight(nearby) * ftemp;
        end
    end
    if iscdf && any(cdfIdx_allBelow)
        f(i) = f(i) + sum(weight(cdfIdx_allBelow));
    end
end
if isSingleWeight
    f = f * uniqueWeights;
end
if isKernelNormal && ~reflectionPDF
    f = f ./ TWO_PI;
end
...
</pre>
<p>This brings the run-time down to <b>31-32 secs</b>. Not bad at all, but we can still do much better:</p>
<h3 id="loop-top">Main loop &#8211; top part</h3>
<p>Now let&#8217;s take a look at the profiling report&#8217;s top part of the main loop:</p>
<p><center><figure style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://undocumentedmatlab.com/images/mvksdensity-profile4.png" alt="Profiling results for top part of the main loop" title="Profiling results for to part of the main loop" width="550" height="414" /><figcaption class="wp-caption-text">Profiling results for top part of the main loop</figcaption></figure></center></p>
<p>Again we note is that there&#8217;s an inner loop that runs d=2 times, which we can again easily vectorize. In addition, we note the unnecessary repeated initializations of the <code>true(n,1)</code> vector, which can easily be hoisted outside the loop:</p>
<pre lang="matlab" highlight="2-3,5-13,30">
...
TRUE_N = true(n,1);
isSpecialCase2 = ~iscdf && d==2;
for i = 1:m
    if isSpecialCase2
        dist = txi(i,:) - ty;
        currentIdx = abs(dist) <= halfwidth;
        currentIdx = currentIdx(:,1) &#038; currentIdx(:,2);
        nearby = index(currentIdx);
    else
        Idx = TRUE_N;
        cdfIdx = TRUE_N;
        cdfIdx_allBelow = TRUE_N;
        for j = 1:d
            dist = txi(i,j) - ty(:,j);
            currentIdx = abs(dist) <= halfwidth(j);
            Idx = currentIdx &#038; Idx; % pdf boundary
            if iscdf
                currentCdfIdx = dist >= -halfwidth(j);
                cdfIdx = currentCdfIdx & cdfIdx; % cdf boundary1, equal or below the query point in all dimension
                currentCdfIdx_below = dist - halfwidth(j) > 0;
                cdfIdx_allBelow = currentCdfIdx_below & cdfIdx_allBelow; %cdf boundary2, below the pdf lower boundary in all dimension
            end
        end
        if ~iscdf
            nearby = index(Idx);
        else
            nearby = index((Idx|cdfIdx)&(~cdfIdx_allBelow));
        end
    end
    if ~isempty(nearby)
        ...
</pre>
<p>This brings the run-time down to <b>24 seconds</b>. </p>
<p>We next note that instead of using numeric indexes to compute the <code>nearby</code> vector, we could use faster logical indexes:</p>
<pre lang="matlab" highlight="2,9,26,28,31">
...
%index = (1:n)';  % this is no longer needed
TRUE_N = true(n,1);
isSpecialCase2 = ~iscdf && d==2;
for i = 1:m
    if isSpecialCase2
        dist = txi(i,:) - ty;
        currentIdx = abs(dist) <= halfwidth;
        nearby = currentIdx(:,1) &#038; currentIdx(:,2);
    else
        Idx = TRUE_N;
        cdfIdx = TRUE_N;
        cdfIdx_allBelow = TRUE_N;
        for j = 1:d
            dist = txi(i,j) - ty(:,j);
            currentIdx = abs(dist) <= halfwidth(j);
            Idx = currentIdx &#038; Idx; % pdf boundary
            if iscdf
                currentCdfIdx = dist >= -halfwidth(j);
                cdfIdx = currentCdfIdx & cdfIdx; % cdf boundary1, equal or below the query point in all dimension
                currentCdfIdx_below = dist - halfwidth(j) > 0;
                cdfIdx_allBelow = currentCdfIdx_below & cdfIdx_allBelow; %cdf boundary2, below the pdf lower boundary in all dimension
            end
        end
        if ~iscdf
            nearby = Idx;  % not index(Idx)
        else
            nearby = (Idx|cdfIdx) & ~cdfIdx_allBelow;  % no index()
        end
    end
    if any(nearby)
        ...
</pre>
<p>This brings the run-time down to <b>20 seconds</b>. </p>
<p>We now note that the main loop runs m=1,048,576 (=1024&#215;1024) times over all rows of <code>txi</code>. This is expected, since the loop runs over all the elements of a 1024&#215;1024 mesh grid, which are reshaped as a 1,048,576-element column array at some earlier point in the processing, resulting in a m-by-d matrix (1,048,576-by-2 in our specific case). This information helps us, because we know that there are only 1024 unique values in each of the two columns of <code>txi</code>. Therefore, instead of computing the &#8220;closeness&#8221; metric (which leads to the <code>nearby</code> vector) for all 1,048,576 x 2 values of <code>txi</code>, we calculate separate vectors for each of the 1024 unique values in each of its 2 columns, and then merge the results inside the loop:</p>
<pre lang="matlab" highlight="3-10,13-15">
...
isSpecialCase2 = ~iscdf && d==2;
if isSpecialCase2
    [unique1Vals, ~, unique1Idx] = unique(txi(:,1));
    [unique2Vals, ~, unique2Idx] = unique(txi(:,2));
    dist1 = unique1Vals' - ty(:,1);
    dist2 = unique2Vals' - ty(:,2);
    currentIdx1 = abs(dist1) <= halfwidth(1);
    currentIdx2 = abs(dist2) <= halfwidth(2);
end
for i = 1:m
    if isSpecialCase2
        idx1 = unique1Idx(i);
        idx2 = unique2Idx(i);
        nearby = currentIdx1(:,idx1) &#038; currentIdx2(:,idx2);
    else
        ...
</pre>
<p>This brings the run-time down to <b>13 seconds</b>, a total speedup of almost ~6x compared to the original version. Not bad at all.</p>
<p>For reference, here's a profiling summary of the <i>dokernel</i> function again, showing the updated performance hotspots:</p>
<p><center><figure style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://undocumentedmatlab.com/images/mvksdensity-profile5.png" alt="Profiling results after optimization" title="Profiling results after optimization" width="550" height="201" /><figcaption class="wp-caption-text">Profiling results after optimization</figcaption></figure></center></p>
<p>The 2 vectorized code lines in the bottom part of the main loop now account for 72% of the remaining run-time:</p>
<pre lang="matlab" highlight="4-5">
    ...
    if ~isempty(nearby)
        if isSpecialCase1
            z = txi(i,:) - ty(nearby,:);
            ftemp = exp((z.*z) * expFactor);
        else
            ...
</pre>
<p>If I had the inclination, speeding up these two code lines would be the next logical step, but I stop at this point. Interested readers could pick up this challenge and post a solution in the comments section below. I haven't tried it myself, so perhaps there's no easy way to improve this. Then again, perhaps the answer is just around the corner - if you don't try, you'll never know...</p>
<h3 id="resolution">Data density/resolution</h3>
<p>So far, all the optimization I made have not affected code accuracy, generality or resolution. This is always the best approach if you have some spare coding time on your hands.</p>
<p>In some cases, we might have a deep understanding of our domain problem to be able to sacrifice a bit of accuracy in return for run-time speedup. In our case, we identify the main loop over 1024x1024 elements as the deciding factor in the run-time. If we reduce the grid-size by 50% in each dimension (i.e. 512x512), the run-time decreases by an additional factor of almost 4, down to <b>~3.5 seconds</b>, which is what we would have expected since the main loop size has decreased 4 times in size. While this reduces the results resolution/accuracy, we got a 4x speedup in a fraction of the time that it took to make all the coding changes above. </p>
<p>Different situations may require different approaches: in some cases we cannot sacrifice accuracy/resolution, and must spend time to improve the algorithm implementation; in other cases coding time is at a premium and we can sacrifice accuracy/resolution; and in other cases still, we could use a combination of both approaches.</p>
<h3 id="conclusions">Conclusions</h3>
<p>Matlab is composed of thousands of internal functions. Each and every one of these functions was meticulously developed and tested by engineers, who are after all only human. Whereas supreme emphasis is always placed with Matlab functions on their accuracy, run-time performance often takes a back-seat. Make no mistake about this: code accuracy is almost always more important than speed, so I’m not complaining about the current state of affairs.</p>
<p>But when we run into a specific run-time problem in our Matlab program, we should not despair if we see that built-in functions cause slowdown. We can try to avoid calling those functions (for example, by reducing the number of invocations, or decreasing the data resolution, or limiting the target accuracy, etc.), or we could optimize these functions in our own local copy, as I have shown today. There are multiple techniques that we could employ to improve the run time. Just use the profiler and keep an open mind about alternative speed-up mechanisms, and you’d be half-way there. For ideas about the multitude of different speedup techniques that you could use in Matlab, see my book <b><a href="https://undocumentedmatlab.com/books/matlab-performance" target="_blank">Accelerating Matlab Performance</a></b>.</p>
<p><a href="https://undocumentedmatlab.com/consulting" target="_blank">Let me know</a> if you’d like me to assist with your Matlab project, either developing it from scratch or improving your existing code, or just training you in how to improve your Matlab code’s run-time/robustness/usability/appearance.</p>
<p>In the meantime, Happy Easter/Passover everyone, and stay healthy!</p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-3">Speeding-up builtin Matlab functions – part 3</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 2">Speeding-up builtin Matlab functions &#8211; part 2 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 1">Speeding-up builtin Matlab functions &#8211; part 1 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-3/feed</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Speeding-up builtin Matlab functions &#8211; part 2</title>
		<link>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=speeding-up-builtin-matlab-functions-part-2</link>
					<comments>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2#comments</comments>
		
		<dc:creator><![CDATA[Yair Altman]]></dc:creator>
		<pubDate>Sun, 06 May 2018 16:26:19 +0000</pubDate>
				<category><![CDATA[Low risk of breaking in future versions]]></category>
		<category><![CDATA[Stock Matlab function]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Pure Matlab]]></category>
		<guid isPermaLink="false">http://undocumentedmatlab.com/?p=7533</guid>

					<description><![CDATA[<p>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. </p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2">Speeding-up builtin Matlab functions &#8211; part 2</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 1">Speeding-up builtin Matlab functions &#8211; part 1 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/undocumented-mouse-pointer-functions" rel="bookmark" title="Undocumented mouse pointer functions">Undocumented mouse pointer functions </a> <small>Matlab contains several well-documented functions and properties for the mouse pointer. However, some very-useful functions have remained undocumented and unsupported. This post details their usage....</small></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<p>Last week <a href="/articles/speeding-up-builtin-matlab-functions-part-1" target="_blank">I showed</a> how we can speed-up built-in Matlab functions, by creating local copies of the relevant m-files and then optimizing them for improved speed using a variety of techniques.<span class="alignright"><img loading="lazy" decoding="async" src="https://undocumentedmatlab.com/images/speedometer3b3_200x200.gif" alt="Accelerating MATLAB Performance" title="Accelerating MATLAB Performance" width="200" height="200" /></span> Today I will show another example of such speed-up, this time of the Financial Toolbox&#8217;s <i><b><a href="https://www.mathworks.com/help/finance/maxdrawdown.html" rel="nofollow" target="_blank">maxdrawdown</a></b></i> function, which is <a href="https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp" rel="nofollow" target="_blank">widely used</a> to estimate the relative risk of a trading strategy or asset. One might think that such a basic indicator would be optimized for speed, but experience shows otherwise. In fact, this function turned out to be the main run-time performance hotspot for one of my clients. The vast majority of his code was optimized for speed, and he naturally assumed that the built-in Matlab functions were optimized as well, but this was not the case. Fortunately, I was able to create an equivalent version that was 30-40 times faster (!), and my client remains a loyal Matlab fan.<br />
In today&#8217;s post I will show how I achieved this speed-up, using different methods than the ones I showed last week. A combination of these techniques can be used in a wide range of other Matlab functions. Additional speed-up techniques can be found in other <a href="/articles/tag/performance" target="_blank">performance-related posts</a> on this website, as well in my book <a href="/books/matlab-performance" target="_blank"><b>Accelerating MATLAB Performance</b></a>.<br />
<span id="more-7533"></span></p>
<h3 id="profiling">Profiling</h3>
<p>As I explained last week, the first step in speeding up any function is to profile its current run-time behavior using Matlab&#8217;s builtin <a href="https://www.mathworks.com/help/matlab/matlab_prog/profiling-for-improving-performance.html" rel="nofollow" target="_blank">Profiler tool</a>, which can either be started from the Matlab Editor toolstrip (&#8220;Run and Time&#8221;) or via the <a href="https://www.mathworks.com/help/matlab/ref/profile.html" rel="nofollow" target="_blank"><i><b>profile</b></i></a> function.<br />
The profile report for the client&#8217;s function showed that it had two separate performance hotspots:</p>
<ol>
<li>Code that checks the drawdown format (optional 2nd input argument) against a set of allowed formats</li>
<li>Main code section that iteratively loops over the data-series values to compute the maximal drawdown</li>
</ol>
<p>In order top optimize the code, I copied <i>%matlabroot%/toolbox/finance/finance/maxdrawdown.m</i> to a local folder on the Matlab path, renaming the file (and the function) <i>maxdrawdn</i>, in order to avoid conflict with the built-in version.</p>
<h3 id="strings">Optimizing input args pre-processing</h3>
<p>The main problem with the pre-processing of the optional format input argument is the string comparisons, which are being done even when the default format is used (which is by far the most common case). String comparison are often more expensive than numerical computations. Each comparison by itself is very short, but when <i><b>maxdrawdown</b></i> is run in a loop (as it often is), the run-time adds up.<br />
Here&#8217;s a snippet of the original code:</p>
<pre lang="matlab">
if nargin < 2 || isempty(Format)
    Format = 'return';
end
if ~ischar(Format) || size(Format,1) ~= 1
    error(message('finance:maxdrawdown:InvalidFormatType'));
end
choice = find(strncmpi(Format,{'return','arithmetic','geometric'},length(Format)));
if isempty(choice)
    error(message('finance:maxdrawdown:InvalidFormatValue'));
end
</pre>
<p>An equivalent code, which avoids any string processing in the common default case, is faster, simpler and more readable:</p>
<pre lang="matlab">
if nargin < 2 || isempty(Format)
    choice = 1;
elseif ~ischar(Format) || size(Format,1) ~= 1
    error(message('finance:maxdrawdown:InvalidFormatType'));
else
    choice = find(strncmpi(Format,{'return','arithmetic','geometric'},length(Format)));
    if isempty(choice)
        error(message('finance:maxdrawdown:InvalidFormatValue'));
    end
end
</pre>
<p>The general rule is that whenever you have a common case, you should check it first, avoiding unnecessary processing downstream. Moreover, for improved run-time performance (although not necessarily maintainability), it is generally preferable to work with numbers rather than strings (<code>choice</code> rather than <code>Format</code>, in our case).</p>
<h3 id="vectorizing">Vectorizing the main loop</h3>
<p>The main processing loop uses a very simple yet inefficient iterative loop. I assume that the code was originally developed this way in order to assist debugging and to ensure correctness, and that once it was ready nobody took the time to also optimize it for speed. It looks something like this:</p>
<pre lang="matlab">
MaxDD = zeros(1,N);
MaxDDIndex = ones(2,N);
...
if choice == 1   % 'return' format
    MaxData = Data(1,:);
    MaxIndex = ones(1,N);
    for i = 1:T
        MaxData = max(MaxData, Data(i,:));
        q = MaxData == Data(i,:);
        MaxIndex(1,q) = i;
        DD = (MaxData - Data(i,:)) ./ MaxData;
        if any(DD > MaxDD)
            p = DD > MaxDD;
            MaxDD(p) = DD(p);
            MaxDDIndex(1,p) = MaxIndex(p);
            MaxDDIndex(2,p) = i;
        end
    end
else             % 'arithmetic' or 'geometric' formats
    ...
</pre>
<p>This loop can relatively easily be vectorized, making the code much faster, and arguably also simpler, more readable, and more maintainable:</p>
<pre lang="matlab">
if choice == 3
    Data = log(Data);
end
MaxDDIndex = ones(2,N);
MaxData = cummax(Data);
MaxIndexes = find(MaxData==Data);
DD = MaxData - Data;
if choice == 1	% 'return' format
    DD = DD ./ MaxData;
end
MaxDD = cummax(DD);
MaxIndex2 = find(MaxDD==DD,1,'last');
MaxIndex1 = MaxIndexes(find(MaxIndexes<=MaxIndex2,1,'last'));
MaxDDIndex(1,:) = MaxIndex1;
MaxDDIndex(2,:) = MaxIndex2;
MaxDD = MaxDD(end,:);
</pre>
<p>Let's make a short run-time and accuracy check - we can see that we achieved a 31-fold speedup (YMMV), and received the exact same results:</p>
<pre lang="matlab">
>> data = rand(1,1e7);
>> tic, [MaxDD1, MaxDDIndex1] = maxdrawdown(data); toc  % builtin Matlab function
Elapsed time is 7.847140 seconds.
>> tic, [MaxDD2, MaxDDIndex2] = maxdrawdn(data); toc  % our optimized version
Elapsed time is 0.253130 seconds.
>> speedup = round(7.847140 / 0.253130)
speedup =
    31
>> isequal(MaxDD1,MaxDD2) && isequal(MaxDDIndex1,MaxDDIndex2)  % check accuracy
ans =
  logical
   1
</pre>
<p><b><u>Disclaimer</u></b>: The code above seems to work (quite well in fact) for a 1D data vector. You'd need to modify it a bit to handle 2D data - the returned maximal drawdown are still computed correctly but not the returned indices, due to their computation using the <i><b>find</b></i> function. This modification is left as an exercise for the reader...</p>
<h3 id="related">Related functions</h3>
<p>Very similar code could be used for the corresponding <i>maxdrawup</i> function. Although this function is used much less often than <i><b>maxdrawdown</b></i>, it is in fact widely used and very similar to <i><b>maxdrawdown</b></i>, so it is surprising that it is missing in the Financial Toolbox. Here is the corresponding code snippet:</p>
<pre lang="matlab">
% Code snippet for maxdrawup (similar to maxdrawdn)
MaxDUIndex = ones(2,N);
MinData = cummin(Data);
MinIndexes = find(MinData==Data);
DU = Data - MinData;
if choice == 1	% 'return' format
    DU = DU ./ MinData;
end
MaxDU = cummax(DU);
MaxIndex = find(MaxDD==DD,1,'last');
MinIndex = MinIndexes(find(MinIndexes<=MaxIndex,1,'last'));
MaxDUIndex(1,:) = MinIndex;
MaxDUIndex(2,:) = MaxIndex;
MaxDU = MaxDU(end,:);
</pre>
<p>Similar vectorization could be applied to the <i><b><a href="https://www.mathworks.com/help/finance/emaxdrawdown.html" rel="nofollow" target="_blank">emaxdrawdown</a></b></i> function. This too is left as an exercise for the reader...</p>
<h3 id="conclusions">Conclusions</h3>
<p>Matlab is composed of thousands of internal functions. Each and every one of these functions was meticulously developed and tested by engineers, who are after all only human. Whereas supreme emphasis is always placed with Matlab functions on their accuracy, run-time performance sometimes takes a back-seat. Make no mistake about this: code accuracy is almost always more important than speed (an exception are cases where some accuracy may be sacrificed for improved run-time performance). So I'm not complaining about the current state of affairs.<br />
But when we run into a specific run-time problem in our Matlab program, we should not despair if we see that built-in functions cause slowdown. We can try to avoid calling those functions (for example, by reducing the number of invocations, or limiting the target accuracy, etc.), or optimize these functions in our own local copy, as I've shown last week and today. There are multiple techniques that we could employ to improve the run time. Just use the profiler and keep an open mind about alternative speed-up mechanisms, and you'd be half-way there.<br />
<a href="/consulting" target="_blank">Let me know</a> if you'd like me to assist with your Matlab project, either developing it from scratch or improving your existing code, or just training you in how to improve your Matlab code's run-time/robustness/usability/appearance. I will be visiting Boston and New York in early June and would be happy to meet you in person to discuss your specific needs.</p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2">Speeding-up builtin Matlab functions &#8211; part 2</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 1">Speeding-up builtin Matlab functions &#8211; part 1 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/undocumented-mouse-pointer-functions" rel="bookmark" title="Undocumented mouse pointer functions">Undocumented mouse pointer functions </a> <small>Matlab contains several well-documented functions and properties for the mouse pointer. However, some very-useful functions have remained undocumented and unsupported. This post details their usage....</small></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2/feed</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>Speeding-up builtin Matlab functions &#8211; part 1</title>
		<link>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=speeding-up-builtin-matlab-functions-part-1</link>
					<comments>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1#comments</comments>
		
		<dc:creator><![CDATA[Yair Altman]]></dc:creator>
		<pubDate>Sun, 29 Apr 2018 09:46:29 +0000</pubDate>
				<category><![CDATA[Low risk of breaking in future versions]]></category>
		<category><![CDATA[Stock Matlab function]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Pure Matlab]]></category>
		<guid isPermaLink="false">http://undocumentedmatlab.com/?p=7509</guid>

					<description><![CDATA[<p>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. </p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1">Speeding-up builtin Matlab functions &#8211; part 1</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 2">Speeding-up builtin Matlab functions &#8211; part 2 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/undocumented-mouse-pointer-functions" rel="bookmark" title="Undocumented mouse pointer functions">Undocumented mouse pointer functions </a> <small>Matlab contains several well-documented functions and properties for the mouse pointer. However, some very-useful functions have remained undocumented and unsupported. This post details their usage....</small></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<p>A client recently asked me to assist with his numeric analysis function &#8211; it took 45 minutes to run, which was unacceptable (5000 runs of ~0.55 secs each).<span class="alignright"><img loading="lazy" decoding="async" src="https://undocumentedmatlab.com/images/speedometer4d_200x200.gif" alt="Accelerating MATLAB Performance" title="Accelerating MATLAB Performance" width="200" height="200" /></span> The code had to run in 10 minutes or less to be useful. It turns out that 99% of the run-time was taken up by Matlab&#8217;s built-in <a href="https://www.mathworks.com/help/stats/fitdist.html" rel="nofollow" target="_blank"><i><b>fitdist</b></i></a> function (part of the Statistics Toolbox), which my client was certain is already optimized for maximal performance. He therefore assumed that to get the necessary speedup he must either switch to another programming language (C/Java/Python), and/or upgrade his computer hardware at considerable expense, since parallelization was not feasible in his specific case.<br />
Luckily, I was there to assist and was able to quickly speed-up the code down to <b>7 minutes</b>, well below the required run-time. In today&#8217;s post I will show how I did this, which is relevant for a wide variety of other similar performance issues with Matlab. Many additional speed-up techniques can be found in other <a href="/articles/tag/performance" target="_blank">performance-related posts</a> on this website, as well in my book <a href="/books/matlab-performance" target="_blank"><b>Accelerating MATLAB Performance</b></a>.<br />
<span id="more-7509"></span></p>
<h3 id="profiling">Profiling</h3>
<p>The first step in speeding up any function is to profile its current run-time behavior using Matlab&#8217;s builtin <a href="https://www.mathworks.com/help/matlab/matlab_prog/profiling-for-improving-performance.html" rel="nofollow" target="_blank">Profiler tool</a>, which can either be started from the Matlab Editor toolstrip (&#8220;Run and Time&#8221;) or via the <a href="https://www.mathworks.com/help/matlab/ref/profile.html" rel="nofollow" target="_blank"><i><b>profile</b></i></a> function.<br />
The profile report for the client&#8217;s function showed that 99% of the time was spent in the Statistics Toolbox&#8217;s <i><b>fitdist</b></i> function. Drilling into this function in the profiling report, we see onion-like functions that processed input parameters, ensured data validation etc. The core processing is done inside a class that is unique to each required distribution (e.g., <code>prob.StableDistribution</code>, <code>prob.BetaDistribution</code> etc.) that is invoked within <i><b>fitdist</b></i> using an <i><b>feval</b></i> call, based on the distribution name that was specified by the user.<br />
In our specific case, the external onion layers of sanity checks were unnecessary and could be avoided. In general, I advise <i>not</i> to discard such checks, because you never know whether future uses might have a problem with outlier data or input parameters. Moreover, in the specific case of <i><b>fitdist</b></i> they take only a very minor portion of the run-time (this may be different in other cases, such as the <a href="/articles/ismembc-undocumented-helper-function" target="_blank"><i><b>ismember</b></i></a> function that I described years ago, where the sanity checks have a significant run-time impact compared to the core processing in the internal <i><b>ismembc</b></i> function).<br />
However, since we wanted to significantly improve the total run-time and this was spent within the distribution class (<code>prob.StableDistribution</code> in the case of my client), we continue to drill-down into this class to determine what can be done.<br />
It turns out that <code>prob.StableDistribution</code> basically does 3 things in its main <i>fit()</i> method:</p>
<ol>
<li>pre-process the input data (<i>prob.ToolboxFittableParametricDistribution.processFitArgs()</i> and <i>.removeCensoring()</i> methods) &#8211; this turned out to be unnecessary in my client&#8217;s data, but has little run-time impact.</li>
<li>call <i>stablefit()</i> in order to get fitting parameters &#8211; this took about half the run-time</li>
<li>call <i>stablelike()</i> in order to get likelihood data &#8211; this took about half the run-time as well</li>
<li>call <i>prob.StableDistribution.makeFitted()</i> to create a probability-distribution object returned to the caller &#8211; this also took little run-time that was not worth bothering about.</li>
</ol>
<h3 id="process">The speed-up improvement process</h3>
<p>With user-created code we could simply modify our code in-place. However, a more careful process is necessary when modifying built-in Matlab functions (either in the core Matlab distribution or in one of the toolboxes).<br />
The basic idea here is to create a side-function that would replicate the core processing of <i><b>fitdist</b></i>. This is preferable to modifying Matlab&#8217;s installation files because we could then reuse the new function in multiple computers, without having to mess around in the Matlab installation (which may not even be possible if we do not have admin privileges). Also, if we ever upgrade our Matlab we won&#8217;t need to remember to update the installed files (and obviously retest).<br />
I called the new function <i>fitdist2</i> and inside it I initially placed only the very core functionality of <i>prob.StableDistribution.fit()</i>:</p>
<pre lang="matlab">
% fitdist2 - fast replacement for fitdist(data,'stable')
% equivalent to pd = prob.StableDistribution.fit(data);
function pd = fitdist2(data)
    % Bypass pre-processing (not very important)
    [cens,freq,opt] = deal([]);
    %[data,cens,freq,opt] = prob.ToolboxFittableParametricDistribution.processFitArgs(data);
    %data = prob.ToolboxFittableParametricDistribution.removeCensoring(data,cens,freq,'stable');
    % Main processing in stablefit(), stablelike()
    params = stablefit(data,0.05,opt);
    [nll,cov] = stablelike(params,data);
    % Combine results into the returned probability distribution object
    pd = prob.StableDistribution.makeFitted(params,nll,cov,data,cens,freq);
end
</pre>
<p>If we try to run this as-is, we&#8217;d see errors because <i>stablefit()</i> and <i>stablelike()</i> are both sub-functions within <i>%matlabroot%/toolbox/stats/stats/+prob/StableDistribution.m</i>. So we copy these sub-functions (and their dependent subfunctions <i>infoMtxCal(), intMle(), tabpdf(), neglog_pdf(), stable_nloglf(), varTrans</i>) to the bottom of our <i>fitdist2.m</i> file, about 400 lines in total.<br />
We also remove places that call <i>checkargs(&#8230;)</i> since that seems to be unnecessary &#8211; if you want to keep it then add the <i>checkargs()</i> function as well.<br />
Now we re-run our code, after each speedup iteration verifying that the returned <code>pd</code> object returned by our <i>fitdist2</i> is equivalent to the original object returned by <i><b>fitdist</b></i>.</p>
<h3 id="stablefit">Speeding-up <i>stablefit()</i></h3>
<p>A new profiling run shows that the vast majority of the time in <i>stablefit()</i> is spent in two lines:</p>
<ol>
<li><code>s = load('private/StablePdfTable.mat');</code></li>
<li><code>[parmhat,~,err,output] = fminsearch(@(params)stable_nloglf(x,params),phi0,options);</code></li>
</ol>
<p>The first of these lines is reloading a static data file. The very same static data file is later reloaded in <i>stablelike()</i>. Both of these data-loads is done in every single invocation of <i><b>fitdist</b></i>, so if we have 5000 data fits, we load the same static data file 10,000 times! This is certainly not indicative of good programming practice. It would be much faster to reload the static data once into memory, and then use this cached data for the next 9,999 invocation. Since the original authors of <i>StableDistribution.m</i> seem to like single-character global variables (another bad programming practice, for multiple reasons), we&#8217;ll follow their example (added lines are highlighted):</p>
<pre lang="matlab" highlight="1-3,9">
persistent s  % this should have a more meaningful name (but at least is not global...)!
if isempty(s)
    fit_path = fileparts(which('fitdist'));
    s = load([fit_path '/private/StablePdfTable.mat']);
    a = s.a;
    b = s.b;
    xgd = s.xgd;
    p = s.p;
end
</pre>
<p>In order to speed-up the second line (that calls <b><i>fminsearch</i></b>), we can reduce the tolerances used by this function, by updating the <code>options</code> structure passed to it, so that we use tolerances of 1e-3 rather than the default 1e-6 (in our specific case this resulted in acceptable errors of ~0.1%). Specifically, we modify the code from this:</p>
<pre lang="matlab">
function [parmhat,parmci] = stablefit(x,alpha,options)
...
if nargin < 3 || isempty(options)
    options = statset('stablefit');
else
    options = statset(statset('stablefit'),options);
end
% Maximize the log-likelihood with respect to the transformed parameters
[parmhat,~,err,output] = fminsearch(@(params)stable_nloglf(x,params),phi0,options);
...
end
</pre>
<p>to this (note that the line that actually calls <b><i>fminsearch</i></b> remains unchanged):</p>
<pre lang="matlab" highlight="1,3-4,6-8">
function [parmhat,parmci] = stablefit(x,alpha,unused_options)
...
persistent options
if isempty(options)
    options = statset('stablefit');
    options.TolX   = 1e-3;
    options.TolFun = 1e-3;
    options.TolBnd = 1e-3;
end
% Maximize the log-likelihood with respect to the transformed parameters
[parmhat,~,err,output] = fminsearch(@(params)stable_nloglf(x,params),phi0,options);
...
end
</pre>
<p>The <i><b>fminsearch</b></i> internally calls <i>tabpdf()</i> repeatedly. Drilling down in the profiling report we see that it recomputes a <code>griddedInterpolant</code> object that is essentially the same for all iterations (and therefore a prime candidate for caching), and also that it uses the costly cubic interpolation rather than a more straight-forward linear interpolation:</p>
<pre lang="matlab" highlight="3-6">
function y = tabpdf(x,alpha,beta)
...
persistent G  % this should have a more meaningful name (but at least is not global...)!
if isempty(G)
    G = griddedInterpolant({b, a, xgd}, p, 'linear','none');  % 'linear' instead of 'cubic'
end
%G = griddedInterpolant({b, a, xgd}, p, 'cubic','none');  % original
y = G({beta,alpha,x});
...
</pre>
<p>These cases illustrate two important speedup technique categories: caching data in order to reduce the <i>number of times</i> that a certain code hotspot is being run, and modifying the parameters/inputs in order to reduce the <i>individual run-time</i> of the hotspot code. Variations of these techniques form the essence of effective speedup and can often be achieved by just reflecting on the problem and asking yourself two questions:</p>
<ol>
<li><i>can I reduce the number of times that this code is being run?</i> and</li>
<li><i>can I reduce the run-time of this specific code section?</i></li>
</ol>
<p>Additional important speed-up categories include parallelization, vectorization and algorithmic modification. These are sometimes more difficult programmatically and riskier in terms of functional equivalence, but may be required in case the two main techniques above are not feasible. Of course, we can always combine these techniques, we don't need to choose just one or the other.</p>
<h3 id="stablelike">Speeding-up <i>stablelike()</i></h3>
<p>We now turn our attentions to <i>stablelike()</i>. As for the loaded static file, we could simply use the cached <code>s</code> to load the data in order to avoid repeated reloading of the data from disk. But it turns out that this data is actually not used at all inside the function (!) so we just comment-out the old code:</p>
<pre lang="matlab">
%s = load('private/StablePdfTable.mat');
%a = s.a;
%b = s.b;
%xgd = s.xgd;
%p = s.p;
</pre>
<p>Think about this - the builtin Matlab code loads a data file from disk and then does <i>absolutely nothing</i> with it - what a waste!<br />
Another important change is to reduce the run-time of the <b><i>integral</i></b> function, which is called thousands of times within a double loop. We do this by reducing the tolerances specified in the <b><i>integral</i></b> call from 1e-6:</p>
<pre lang="matlab">
F(i,j) = integral(@(x)infoMtxCal(x,params,step,i,j),-Inf,Inf,'AbsTol',1e-6,'RelTol',1e-4); % original
F(i,j) = integral(@(x)infoMtxCal(x,params,step,i,j),-Inf,Inf,'AbsTol',1e-3,'RelTol',1e-3); % new
</pre>
<p>You can see that once again these two cases follow the two techniques that I mentioned above: we reduced the number of times that we load the data file (to 0 in our case), and we improved the run-time of the individual integral calculation by reducing its tolerances.</p>
<h3 id="conclusions">Conclusions</h3>
<p>The final result of applying the techniques above was a 6-fold speedup, reducing the total run-time from 45 minutes down to 7 minutes. I could probably have improved the run-time even further, but since we reached our target run-time I stopped there. The point after all was to make the code usable, not to reach a world speed record.<br />
In my next article I will present another example of dramatically improving the run-time speed of a built-in Matlab function, this time a very commonly-used function in the Financial Toolbox that I was able to speed-up by a factor of 40.<br />
Matlab releases improve continuously, so hopefully my techniques above (or alternatives) would find their way into the builtin Matlab functions, making them faster than today, out-of-the-box.<br />
Until this happens, we should not lose hope when faced with a slow Matlab function, even if it is a built-in/internal one, as I hope to have clearly illustrated today, and will also show in my next article. Improving the performance is often easy. In fact, it took me much longer to write this article than it was to improve my client's code...<br />
<a href="/consulting" target="_blank">Let me know</a> if you'd like me to assist with your Matlab project, either developing it from scratch or improving your existing code, or just training you in how to improve your Matlab code's run-time/robustness/usability/appearance. I will be visiting Boston and New York in early June and would be happy to meet you in person to discuss your specific needs.</p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1">Speeding-up builtin Matlab functions &#8211; part 1</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-2" rel="bookmark" title="Speeding-up builtin Matlab functions &#8211; part 2">Speeding-up builtin Matlab functions &#8211; part 2 </a> <small>Built-in Matlab functions can often be profiled and optimized for improved run-time performance. This article shows a typical example. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/speeding-up-matlab-jdbc-sql-queries" rel="bookmark" title="Speeding up Matlab-JDBC SQL queries">Speeding up Matlab-JDBC SQL queries </a> <small>Fetching SQL ResultSet data from JDBC into Matlab can be made significantly faster. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/callback-functions-performance" rel="bookmark" title="Callback functions performance">Callback functions performance </a> <small>Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/undocumented-mouse-pointer-functions" rel="bookmark" title="Undocumented mouse pointer functions">Undocumented mouse pointer functions </a> <small>Matlab contains several well-documented functions and properties for the mouse pointer. However, some very-useful functions have remained undocumented and unsupported. This post details their usage....</small></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://undocumentedmatlab.com/articles/speeding-up-builtin-matlab-functions-part-1/feed</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Solving a MATLAB bug by subclassing</title>
		<link>https://undocumentedmatlab.com/articles/solving-a-matlab-bug-by-subclassing?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=solving-a-matlab-bug-by-subclassing</link>
					<comments>https://undocumentedmatlab.com/articles/solving-a-matlab-bug-by-subclassing#comments</comments>
		
		<dc:creator><![CDATA[Yair Altman]]></dc:creator>
		<pubDate>Sun, 07 Feb 2010 23:57:25 +0000</pubDate>
				<category><![CDATA[Guest bloggers]]></category>
		<category><![CDATA[Hidden property]]></category>
		<category><![CDATA[Low risk of breaking in future versions]]></category>
		<category><![CDATA[Stock Matlab function]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Matt Whitaker]]></category>
		<category><![CDATA[Pure Matlab]]></category>
		<category><![CDATA[Undocumented property]]></category>
		<guid isPermaLink="false">http://undocumentedmatlab.com/?p=1110</guid>

					<description><![CDATA[<p>Matlab's Image Processing Toolbox's impoint function contains an annoying bug that can be fixed using some undocumented properties.</p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/solving-a-matlab-bug-by-subclassing">Solving a MATLAB bug by subclassing</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/solving-a-matlab-mcos-bug" rel="bookmark" title="Solving a Matlab MCOS bug">Solving a Matlab MCOS bug </a> <small>Matlab has a bug with handling multi-element class-access constructs. This post explains the problem and solution. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/solving-a-matlab-hang-problem" rel="bookmark" title="Solving a Matlab hang problem">Solving a Matlab hang problem </a> <small>A very common Matlab hang is apparently due to an internal timing problem that can easily be solved. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/solving-an-mput-ftp-hang-problem" rel="bookmark" title="Solving an mput (FTP) hang problem">Solving an mput (FTP) hang problem </a> <small>Matlab may hang when using passive FTP commands such as mput and dir. A simple workaround is available to fix this. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/simple-gui-tabs-for-advanced-matlab-trading-app" rel="bookmark" title="Simple GUI Tabs for Advanced Matlab Trading App">Simple GUI Tabs for Advanced Matlab Trading App </a> <small>A new File Exchange utility enables to easily design GUI tabs using Matlab's GUIDE...</small></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<p><i>I would like to welcome guest blogger <a target="_blank" rel="nofollow" href="https://www.mathworks.com/matlabcentral/newsreader/author/94021">Matthew Whitaker</a>. Many of Matt&#8217;s CSSM submissions offer important insight of internal Matlab functionality. As shall be seen by today&#8217;s article and some future submissions, Matt has plenty to share vis-a-vis Matlab&#8217;s undocumented functionality.</i><br />
In my day-to-day work I make extensive use of MATLAB&#8217;s <a target="_blank" rel="nofollow" href="http://www.mathworks.com/products/image/">Image Processing Toolbox</a> (IPT). One area of the toolbox that has seen considerable change over the last few releases has been the development of a set of <a target="_blank" rel="nofollow" href="http://www.mathworks.com/access/helpdesk/help/toolbox/images/f17-6011.html">modular tools</a> to aid in GUI design for image processing applications. In this article, I examine a bug in one of those tools to illustrate how we can use the power of subclassing these objects (using an undocumented property) to design a simple and effective workaround.</p>
<h3>The problem</h3>
<p>The problem arose as I was refactoring some code that was written in R2006b to R2009b. The code in question uses the <b><i>impoint</i></b> tool on an image along with an associated <b><i>text</i></b> object that moves with the point to display information as it is dragged around the image. At the time of the R2006b release the <b><i>impoint</i></b> tool was written as an API. In R2006b the call to <b><i>impoint</i></b> returns a handle to an <a target="_blank" rel="nofollow" href="http://www.mathworks.com/access/helpdesk/help/techdoc/ref/hggroup.html"><b><i>hggroup</i></b></a> containing a structure of function handles in its application data under the tag &#8216;API&#8217;. This programming pattern was common before the advent of the new class syntax in MATLAB version 7.6 (R2008a).<br />
Here is an example of how <b><i>impoint</i></b> would be used in R2006b:</p>
<pre lang="matlab">
function impointBehavior_R2006b
%IMPOINTBEHAVIOR_R2006B shows how impoint would be used in R2006b
%Note: RUN UNDER R2006B (will run under R2009b but actually uses
%classdef impoint so it will show the same issue)
  % Display the image in a figure window
  figure;  imshow('rice.png');
  % In R2006b calling impoint returns the hggroup handle
  h = impoint(gca,100,200);
  % In 2006b iptgetapi returns a structure of function handles
  api = iptgetapi(h);
  % Add a new position callback to set the text string
  api.addNewPositionCallback(@newPos_Callback);
  % Construct boundary constraint function so we can't go outside the axes
  fcn = makeConstrainToRectFcn('impoint',get(gca,'XLim'),get(gca,'YLim'));
  api.setDragConstraintFcn(fcn);
  % Fire callback so we get initial text
  newPos_Callback(api.getPosition());
  function newPos_Callback(newPos)
    % Display the current point position in a text label
    api.setString(sprintf('(%1.0f,%1.0f)',newPos(1),newPos(2)));
  end %newPos_Callback
end %impointBehavior_R2006b
</pre>
<p>The code above, when run in R2006b, produces the desired behavior of displaying a text object containing the point coordinates that moves around with the point as it is dragged around the axes.<br />
In R2009b, <a target="_blank" rel="nofollow" href="http://www.mathworks.com/access/helpdesk/help/toolbox/images/impoint.html"><b><i>impoint</i></b></a> is now a true MATLAB class using the new <a target="_blank" rel="nofollow" href="http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_oop/brqy3km-6.html"><b><i>classdef</i></b></a> syntax, so I wanted to update the existing code. Initially this appeared to be a straightforward translation of the code to make use of the new <b><i>impoint</i></b> class syntax. The first attempt to rewrite the code was:</p>
<pre lang="matlab">
function impointBehavior_R2009b
%IMPOINTBEHAVIOR_R2009B shows the undesirable behavior when
%using the setString method in R2009b.
  % Display the image in a figure window
  figure;  imshow('rice.png');
  h = impoint(gca,100,200);
  % Add a new position callback to set the text string
  h.addNewPositionCallback(@newPos_Callback);
  % Construct boundary constraint function so we can't go outside the axes
  fcn = makeConstrainToRectFcn('impoint',get(gca,'XLim'),get(gca,'YLim'));
  % Enforce boundary constraint function
  h.setPositionConstraintFcn(fcn);
  % Fire callback so we get initial text
  newPos_Callback(h.getPosition());
  function newPos_Callback(newPos)
    % Display the current point position in a text label
    h.setString(sprintf('(%1.0f,%1.0f)',newPos(1),newPos(2)))
  end %newPos_Callback
end %impointBehavior_R2009b
</pre>
<p>Unfortunately, when this code is run, dragging the mouse around the axes produces a trail of labels as shown below:<br />
<center><figure style="width: 295px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" alt="Before - buggy behavior" src="https://undocumentedmatlab.com/images/impoint_before.png" title="Before - buggy behavior" width="295" height="295" /><figcaption class="wp-caption-text">Before - buggy behavior</figcaption></figure></center><br />
Opening up <b><i>impoint</i></b>.m in the editor and tracing the code revealed that <b><i>impoint</i></b>&#8216;s <i>setString</i> method creates a new <b><i>text</i></b> object each time it is used. I reported this to MATLAB and the bug is now documented on the MathWorks Support site (<a target="_blank" rel="nofollow" href="http://www.mathworks.com/support/bugreports/574846">574846</a>).</p>
<h3>The solution</h3>
<p>So how do we work around this bug to get to the behavior we want? One solution would be to rewrite the offending MATLAB code but this is somewhat risky in terms of maintainability and compatibility.<br />
A more elegant solution is to subclass the <b><i>impoint</i></b> class and substitute the <i>setString</i> behavior we want. Looking at the <b><i>impoint</i></b> code we find that <b><i>impoint</i></b> is a subclass of <a target="_blank" rel="nofollow" href="http://www.mathworks.com/access/helpdesk/help/toolbox/images/imroi.html"><b><i>imroi</i></b></a>. In the <b><i>imroi</i></b> property declarations we see a number of undocumented properties that are protected. We can access these properties in a subclass but not outside the class. One of these undocumented properties is h_group which is an <b><i>hggroup</i></b> that contains the handle graphic objects that make up the <b><i>impoint</i></b> on the screen. The label, when created, becomes part of this <b><i>hggroup</i></b> with its <b>Tag</b> property set to &#8216;label&#8217;. When performing the <i>setString</i> method the behavior we want to see is that if the <b><i>text</i></b> object exists we want to update its <b>String</b> property. If it does not exist we want it to perform its existing functionality:</p>
<pre lang="matlab">
classdef impointtextupdate < impoint
%IMPOINTTEXTUPDATE subclasses impoint to override the setString
%method of impoint so that it does not create a new text object
%each time it is called.
  methods
    function obj = impointtextupdate(varargin)
      obj = obj@impoint(varargin{:});
    end %impointtextupdate
    function setString(obj,str)
      %override impoint setString
      %check to see if there is already a text label
      label = findobj(obj.h_group,'Type','text','Tag','label');
      if isempty(label)
        %do the default behavior
        setString@impoint(obj,str);
      else
        %update the existing tag
        set(label(1),'String',str);
      end %if
    end %setString
  end %methods
end %impointtextupdate
</pre>
<p>Substituting calls to <b><i>impoint</i></b> with the new <b><i>impointupdatetext</i></b> subclass now produces the desired effect as shown below:<br />
<center><figure style="width: 295px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" alt="After - expected behavior" src="https://undocumentedmatlab.com/images/impoint_after.png" title="After - expected behavior" width="295" height="295" /><figcaption class="wp-caption-text">After - expected behavior</figcaption></figure></center></p>
<h3>Conclusions</h3>
<p>This case illustrates a couple of points:</p>
<ul>
<li>Much of the existing code in the MATLAB toolboxes is being updated to the new object oriented syntax. This presents many opportunities to easily and elegantly modify the default behavior without modifying provided toolbox code In the example above we retain all the desirable behavior of <b><i>impoint</i></b> while overriding the undesirable behavior.</li>
<li>Many of the properties and methods in the provided toolbox objects are hidden or protected and are undocumented. It takes some simple detective work to find these out through examining the code. MATLAB is very generous in providing much of the existing code openly. Open the functions and classes you use in the editor to really find out how they work. Over the years I've learned and adopted a lot of useful MATLAB programming patterns by examining the code in the various toolboxes (there are a few coding horrors as well!).</li>
</ul>
<p>I hope to explore some other under-documented features of the IPT and other toolboxes in future posts.</p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/solving-a-matlab-bug-by-subclassing">Solving a MATLAB bug by subclassing</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/solving-a-matlab-mcos-bug" rel="bookmark" title="Solving a Matlab MCOS bug">Solving a Matlab MCOS bug </a> <small>Matlab has a bug with handling multi-element class-access constructs. This post explains the problem and solution. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/solving-a-matlab-hang-problem" rel="bookmark" title="Solving a Matlab hang problem">Solving a Matlab hang problem </a> <small>A very common Matlab hang is apparently due to an internal timing problem that can easily be solved. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/solving-an-mput-ftp-hang-problem" rel="bookmark" title="Solving an mput (FTP) hang problem">Solving an mput (FTP) hang problem </a> <small>Matlab may hang when using passive FTP commands such as mput and dir. A simple workaround is available to fix this. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/simple-gui-tabs-for-advanced-matlab-trading-app" rel="bookmark" title="Simple GUI Tabs for Advanced Matlab Trading App">Simple GUI Tabs for Advanced Matlab Trading App </a> <small>A new File Exchange utility enables to easily design GUI tabs using Matlab's GUIDE...</small></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://undocumentedmatlab.com/articles/solving-a-matlab-bug-by-subclassing/feed</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
