Jekyll2017-03-10T15:08:11+00:00/Unruhschuh.comThis is me rambling about programming, music and whatever comes to mind.
Matlab: Multiplication of multidimensional arrays2017-03-10T18:12:15+00:002017-03-10T18:12:15+00:00/matlab/2017/03/10/matlab-multidimensional-array-multiplication<p>In Matlab, there is no builtin function for the multiplication of multidimensional arrays.
There is a function called <a href="https://de.mathworks.com/matlabcentral/fileexchange/16275-tprod-arbitary-tensor-products-between-n-d-arrays">TPROD</a> on the file exchange, which does the job, but it depends on mex files, and therefore on a compiler, and it also does not support sparse matrices.</p>
<p>I wrote a pure matlab script, called <a href="https://github.com/unruhschuh/tensor_mult">tensor_mult</a>, which does the same thing, sometimes faster, sometimes slower. I haven’t figured out why, yet.
It simply uses <code class="highlighter-rouge">reshape</code>, <code class="highlighter-rouge">permute</code> and basic matrix-matrix multiplication to do the job.</p>
<p>Below you can see the whole script.
An example, using the (semi-)Einstein convention, is <code class="highlighter-rouge">C_{bde} = A_{abc} B_{dcea}</code>, i.e. summation is to be done over the indices <code class="highlighter-rouge">a</code> and <code class="highlighter-rouge">c</code>.
The function call is <code class="highlighter-rouge">tensor_mult(A, B, [1 3], [4 2])</code>, which means: compute the tensor product between <code class="highlighter-rouge">A</code> and <code class="highlighter-rouge">B</code>, while summing over the 1st index of A and the 4th index of B, and over the 3rd index of A and the 2nd index of B.</p>
<div class="language-matlab highlighter-rouge"><pre class="highlight"><code><span class="k">function</span> <span class="n">C</span> <span class="o">=</span> <span class="n">tensor_mult</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">sum_idx_A</span><span class="p">,</span> <span class="n">sum_idx_B</span><span class="p">)</span>
<span class="n">sum_idx_A</span> <span class="o">=</span> <span class="nb">reshape</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">numel</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">));</span>
<span class="n">sum_idx_B</span> <span class="o">=</span> <span class="nb">reshape</span><span class="p">(</span><span class="n">sum_idx_B</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">numel</span><span class="p">(</span><span class="n">sum_idx_B</span><span class="p">));</span>
<span class="n">size_A</span> <span class="o">=</span> <span class="nb">size</span><span class="p">(</span><span class="n">A</span><span class="p">);</span>
<span class="n">size_B</span> <span class="o">=</span> <span class="nb">size</span><span class="p">(</span><span class="n">B</span><span class="p">);</span>
<span class="n">num_size_A</span> <span class="o">=</span> <span class="nb">numel</span><span class="p">(</span><span class="n">size_A</span><span class="p">);</span>
<span class="n">num_size_B</span> <span class="o">=</span> <span class="nb">numel</span><span class="p">(</span><span class="n">size_B</span><span class="p">);</span>
<span class="n">perm_A</span> <span class="o">=</span> <span class="mi">1</span><span class="p">:</span><span class="n">num_size_A</span><span class="p">;</span>
<span class="n">perm_B</span> <span class="o">=</span> <span class="mi">1</span><span class="p">:</span><span class="n">num_size_B</span><span class="p">;</span>
<span class="n">num_idx</span> <span class="o">=</span> <span class="nb">size</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
<span class="nb">assert</span><span class="p">(</span><span class="nb">isequal</span><span class="p">(</span><span class="nb">size</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">)</span> <span class="p">,</span> <span class="nb">size</span><span class="p">(</span><span class="n">sum_idx_B</span><span class="p">)</span> <span class="p">));</span>
<span class="nb">assert</span><span class="p">(</span><span class="nb">isequal</span><span class="p">(</span><span class="n">size_A</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">),</span> <span class="n">size_B</span><span class="p">(</span><span class="n">sum_idx_B</span><span class="p">)));</span>
<span class="n">sum_dim</span> <span class="o">=</span> <span class="nb">prod</span><span class="p">(</span><span class="n">size_A</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">));</span>
<span class="k">for</span> <span class="nb">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">:</span><span class="n">num_idx</span>
<span class="n">perm_A</span> <span class="o">=</span> <span class="n">perm_A</span><span class="p">(</span><span class="n">perm_A</span><span class="o">~=</span><span class="n">sum_idx_A</span><span class="p">(</span><span class="nb">i</span><span class="p">));</span>
<span class="n">perm_B</span> <span class="o">=</span> <span class="n">perm_B</span><span class="p">(</span><span class="n">perm_B</span><span class="o">~=</span><span class="n">sum_idx_B</span><span class="p">(</span><span class="nb">i</span><span class="p">));</span>
<span class="k">end</span>
<span class="n">perm_A</span> <span class="o">=</span> <span class="p">[</span><span class="n">perm_A</span><span class="p">,</span> <span class="n">sum_idx_A</span><span class="p">];</span>
<span class="n">perm_B</span> <span class="o">=</span> <span class="p">[</span><span class="n">sum_idx_B</span><span class="p">,</span> <span class="n">perm_B</span><span class="p">];</span>
<span class="n">size_A</span><span class="p">(</span><span class="n">sum_idx_A</span><span class="p">)</span> <span class="o">=</span> <span class="p">[];</span>
<span class="n">size_B</span><span class="p">(</span><span class="n">sum_idx_B</span><span class="p">)</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">if</span> <span class="nb">isempty</span><span class="p">(</span><span class="n">size_A</span><span class="p">)</span>
<span class="n">size_A</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">end</span>
<span class="k">if</span> <span class="nb">isempty</span><span class="p">(</span><span class="n">size_B</span><span class="p">)</span>
<span class="n">size_B</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">end</span>
<span class="n">C</span> <span class="o">=</span> <span class="nb">squeeze</span><span class="p">(</span><span class="nb">reshape</span><span class="p">(</span><span class="k">...</span>
<span class="nb">reshape</span><span class="p">(</span><span class="nb">permute</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">perm_A</span><span class="p">),</span> <span class="p">[</span><span class="nb">prod</span><span class="p">(</span><span class="n">size_A</span><span class="p">),</span> <span class="n">sum_dim</span><span class="p">])</span> <span class="o">*</span> <span class="k">...</span>
<span class="nb">reshape</span><span class="p">(</span><span class="nb">permute</span><span class="p">(</span><span class="n">B</span><span class="p">,</span> <span class="n">perm_B</span><span class="p">),</span> <span class="p">[</span><span class="n">sum_dim</span><span class="p">,</span> <span class="nb">prod</span><span class="p">(</span><span class="n">size_B</span><span class="p">)]),</span> <span class="k">...</span>
<span class="p">[</span><span class="n">size_A</span><span class="p">,</span><span class="n">size_B</span><span class="p">]));</span>
<span class="k">end</span>
</code></pre>
</div>In Matlab, there is no builtin function for the multiplication of multidimensional arrays. There is a function called TPROD on the file exchange, which does the job, but it depends on mex files, and therefore on a compiler, and it also does not support sparse matrices.Matlab: Open current document in MacVim / GVim2017-03-05T21:15:31+00:002017-03-05T21:15:31+00:00/matlab/2017/03/05/matlab-open-in-vim<p>I tried many times to replace the default editor of Matlab with vim, but there are too many things, that are simply great about the Matlab IDE, namely</p>
<ul>
<li><a href="http://blogs.mathworks.com/videos/2014/01/31/refactor-code-to-rename-variable-with-with-matlab-editor/" target="_blank">code refactoring</a></li>
<li><a href="https://de.mathworks.com/help/matlab/matlab_prog/debugging-process-and-features.html" target="_blank">debugging</a></li>
<li><a href="https://de.mathworks.com/help/matlab/matlab_prog/profiling-for-improving-performance.html" target="_blank">profiling</a></li>
</ul>
<p>The one feature of vim I miss the most, in almost any editor, is search / replace using regular expressions (well, that and navigating with h-j-k-l).</p>
<p>For these reasons, I wrote a little script, which will open the current document – at the current line – in either MacVim or GVim, depending on which OS I am running.
Of course you need to have MacVim or GVim installed on your system for this to work.
On a Mac, you also need to put the shell script <code class="highlighter-rouge">mvim</code>, which comes with the installer of MacVim, in <code class="highlighter-rouge">YOUR_HOME/bin/mvim</code>, as described in the <a href="https://github.com/macvim-dev/macvim/wiki/FAQ#how-can-i-open-files-from-terminal" target="_blank">MacVim FAQ</a>.</p>
<p>Now save the script below as <code class="highlighter-rouge">open_in_vim.m</code> in a directory, which is included in your Matlab’s <a href="https://de.mathworks.com/help/matlab/ref/path.html" target="_blank">path variable</a>.
Any time you want to open the current document in Vim, simply type <code class="highlighter-rouge">open_in_vim</code> in the command window.
To make this new functionality more accessible, you can create a shortcut in <a href="https://de.mathworks.com/help/matlab/matlab_env/create-matlab-shortcuts-to-rerun-commands.html" target="_blank">Matlab’s toolbar</a>.</p>
<script src="https://gist.github.com/unruhschuh/2becfe1bc1705ae168a3d6f38fc33080.js"></script>
<!--
<figure class="highlight"><pre><code class="language-matlab" data-lang="matlab"><span class="k">function</span> <span class="n">open_in_vim</span>
<span class="n">os</span> <span class="o">=</span> <span class="nb">strsplit</span><span class="p">(</span><span class="n">system_dependent</span><span class="p">(</span><span class="s1">'getos'</span><span class="p">),</span> <span class="s1">' '</span><span class="p">);</span>
<span class="n">os</span> <span class="o">=</span> <span class="n">os</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="n">edhandle</span> <span class="o">=</span> <span class="n">com</span><span class="o">.</span><span class="n">mathworks</span><span class="o">.</span><span class="n">mlservices</span><span class="o">.</span><span class="n">MLEditorServices</span><span class="o">.</span><span class="n">getEditorApplication</span><span class="o">.</span><span class="n">getActiveEditor</span><span class="p">;</span>
<span class="n">storageClass</span> <span class="o">=</span> <span class="n">edhandle</span><span class="o">.</span><span class="n">getStorageLocation</span><span class="o">.</span><span class="n">getClass</span><span class="p">;</span>
<span class="n">lineNumber</span> <span class="o">=</span> <span class="n">edhandle</span><span class="o">.</span><span class="n">getLineNumber</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">% weirdly enough, matlab starts counting line numbers at 0</span>
<span class="k">if</span> <span class="nb">isequal</span><span class="p">(</span><span class="n">storageClass</span><span class="o">.</span><span class="n">toString</span><span class="o">.</span><span class="n">toCharArray</span><span class="o">.</span><span class="s1">', '</span><span class="nb">class</span> <span class="n">com</span><span class="o">.</span><span class="n">mathworks</span><span class="o">.</span><span class="n">widgets</span><span class="o">.</span><span class="n">datamodel</span><span class="o">.</span><span class="n">FutureFileStorageLocation</span><span class="o">'</span><span class="p">)</span>
<span class="nb">disp</span><span class="p">(</span><span class="s1">'Error: The file has not been saved yet.'</span><span class="p">)</span>
<span class="k">elseif</span> <span class="nb">isequal</span><span class="p">(</span><span class="n">storageClass</span><span class="o">.</span><span class="n">toString</span><span class="o">.</span><span class="n">toCharArray</span><span class="o">.</span><span class="s1">', '</span><span class="nb">class</span> <span class="n">com</span><span class="o">.</span><span class="n">mathworks</span><span class="o">.</span><span class="n">widgets</span><span class="o">.</span><span class="n">datamodel</span><span class="o">.</span><span class="n">FileStorageLocation</span><span class="o">'</span><span class="p">)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">edhandle</span><span class="o">.</span><span class="n">getLongName</span><span class="o">.</span><span class="n">toString</span><span class="o">.</span><span class="n">toCharArray</span><span class="o">.'</span><span class="p">;</span>
<span class="k">if</span> <span class="nb">strcmp</span><span class="p">(</span><span class="n">os</span><span class="p">,</span> <span class="s1">'Linux'</span><span class="p">)</span>
<span class="nb">system</span><span class="p">([</span><span class="s1">'/usr/bin/gvim +'</span><span class="p">,</span> <span class="nb">num2str</span><span class="p">(</span><span class="n">lineNumber</span><span class="p">),</span> <span class="s1">' "'</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="s1">'"'</span><span class="p">]);</span>
<span class="k">elseif</span> <span class="nb">strcmp</span><span class="p">(</span><span class="n">os</span><span class="p">,</span> <span class="s1">'Darwin'</span><span class="p">)</span>
<span class="nb">system</span><span class="p">([</span><span class="s1">'~/bin/mvim +'</span><span class="p">,</span> <span class="nb">num2str</span><span class="p">(</span><span class="n">lineNumber</span><span class="p">),</span> <span class="s1">' "'</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="s1">'"'</span><span class="p">]);</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
-->I tried many times to replace the default editor of Matlab with vim, but there are too many things, that are simply great about the Matlab IDE, namely code refactoring debugging profiling