Octave and Matlab oddities
Update 2019: Matlab has since fixed this behaviour, so it now matches Octave.
This page contains my notes on quirks in the Matlab and Octave programming languages, especially where they differ. Historical note: Octave started out as its own language with many similarities with Matlab. These days Octave strives to support a superset of Matlab’s syntax.
Environment capture by anonymous functions
Create a file called func_creator.m like this:
function [fn, fn2] = func_creator() A = [3 1 4 1 5 9]; fn = @(x) eval(x); fn2 = @() A; A = 'doom';
Now guess the output of running fn_demo.m:
[fn, fn2] = func_creator(); fn2() fn('A')
The behavior of fn2() is as expected from the documentation: in Octave and Matlab it captures the value of A = [3 1 4 1 5 9] at the time it was created. In Octave fn('A') gives an error as I expected, but Matlab returns 'doom'. When an anonymous function is created, Matlab actually stores a copy of the whole environment(!). More accurately, Matlab no longer clears the environment from memory when it would normally go out of scope. The anonymous function doesn’t see a snapshot of the environment at the time the function was created, but its current state.
Matlab’s behavior is a pain, as memory usage occasionally balloons when working with anonymous functions. I sometimes have to create little helper functions that create my functions in a clean environment in order to avoid leaving more variables stored in memory than I intended.
For comparison, Python does not waste memory in the way that Matlab does: variables that are not explicitly referenced by a nested function are cleared. As with Octave, eval-based tricks that attempt to reference them fail. A potential source of confusion is that Python never “snapshots” the variables like Matlab/Octave does. Indeed Python nested functions can reference variables in the surrounding scope before they are even created.
Minimal evaluation or Short-circuit evaluation
Update 2019: Octave now matches Matlab's behaviour for the first example below, but emits a warning about it.
In Octave, as in C, the || operator short-circuits. The | does not, although it has different meanings in Octave and C. Matlab has the same behavior, except in if statements where if every element of the first argument to | is non-zero then a short-circuit occurs. Similarly for & and &&. I prefer Octave’s behavior, where operators behave in the same way wherever they appear. However, if Mathworks were to “fix” Matlab, then some existing code would be broken. I’d stick to || in if statements unless you are sure you know what you are doing.
Example: the following two lines of code are equivalent in Octave but not in Matlab:
if (1 | figure); x=3; end y=(1 | figure); if y; x=3; end
Both lines pop up a figure window in Octave (if one was not already open), the first line does not in Matlab.
The Matlab documentation says: “Using the element-wise operators (& and |) for short-circuiting may yield unexpected results.” Indeed!
Arrays with some of the sizes equal to one
What a nightmare. The languages are too “clever” for their own good.
In both languages sum(A) sums over the first non-singleton dimension. Too much code assumes it means exactly the same as sum(A,1). This will cause problems if occasionally A has only one row. It’s best to always put in the index you want summed. This advice applies to many other Matlab functions. For example say max(A,,1) rather than max(A).
Multiple dimensional arrays cause more problems; in general it seems impossible to create an array with trailing singleton dimensions. Example: size(repmat(1,[a,b,c])) returns [a,b,c], unless c==1, in which case it returns [a,b]. GAAHHH! Presumably this is meant to be for convenience...to reduce the number of calls to squeeze. The downside is that Matlab is full of kludges to work around problems caused by this issue. Examples: if you ask for element A(1,1,1) then it returns a value even if A does not have a third dimension; permute can access singleton dimensions that don’t exist. In the past Octave has had compatibility problems, but now matches much more of Matlab’s behaviour. However, in either language not all functions you use necessarily let you give them matrices if they expect larger arrays. Until very recently sort(randn(3,2,1), 3) was broken in Matlab (fixed in v7.7) and Octave (fixed in a v3.3 dev version). This means that robust code is hard to write and can be complicated, because sometimes you have to check for singleton dimensions to avoid crashes, and it isn't always obvious when this is necessary.
Passing by reference
There are no references in the Matlab language, although the situation isn’t as bad as some people think. If you pass a large matrix to a function and only read that matrix within the function then Matlab doesn’t actually copy the memory. It automatically “passes by reference”. Freemat adds new syntax for pass-by-reference to its clone of the Matlab language, but benchmarking my copy, it appears to still temporarily copy the memory if you alter the matrix!
One reason for wanting a true pass-by-reference is for efficient in-place operations (like an in-place quick-sort or Cholesky-decomposition). However, I don’t necessarily agree with adding to the language (as in FreeMat). It seems to me that if a function is called like this:
C = chol(C);
And the function is defined like this:
function A = chol(A)
Then the interpreter could automatically do stuff in place. Admittedly things could be a bit more complicated if slices of arrays are used for inputs and outputs. A language feature could be added to the languages’ mex/C interfaces allowing external code to ask if it’s allowed to alter things in place. eg if mymex were called with C=mymex(C); then the mymex function could be told it is allowed to alter C in place.
I did some experiments with FreeMat 1.10, Octave 2.1.69 and Matlab 7.0.1 to confirm how much memory is used when passing matrices around under various circumstances. None of them did operations in place when they could have done.
Update: there has been some progress on this issue in Matlab. The optimization described above has now been implemented, as long as the function is called from within a function (not a script or from the command-line). Sadly there still isn’t a documented, safe way of changing variables in place in mex files (there are dodgy unsupported ways of doing it, but that is asking for trouble).
A real example of the benefits of in place operations is plus_diag.m (see tricks page), which adds something onto the diagonal of an existing matrix. A horrible hack used to dramatically out-perfrom this function, but doesn’t any more in recent Matlab (unless being called from a script or the command-line).
Sparse Matrix oddity
This documents an oddity in old versions of Matlab. It was definitely fixed by v7.4, but I’m not sure when it was first fixed. I seem to remember that Octave got it right, then copied Matlab’s buggy behaviour and then went back to being correct again.
0^0 == 1 right? Unless the zero is in a sparse matrix in (some versions of) Matlab:
>> A = sparse([0,1]) A = (1,2) 1 >> A.^0 ans = (1,2) 1
Similarly in some versions of Matlab dividing by zero doesn’t turn zeros into NaNs. Now both Matlab and Octave act correctly on the zero-elements, treating them as zeros. To operate on just the non-zero elements we can do:
>> spfun(@(x) x^0, A) ans = (1,2) 1