Octave and Matlab oddities
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 it occasionally balloons memory usage 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.
Octave’s behavior does have a problem though:
x = 3; fn = @() @() x; % Octave allows the syntax "fn()()", but Matlab doesn't gn = fn(); gn()
This returns 3 in Matlab, but Octave (version 3.0.2) gives an error. I have run across this problem in real code.
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. Unlike Octave the equivalent of the nested functions example above works. (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
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. There is similar madness with & and &&. Octave’s behavior, where operators behave in the same way wherever they appear, is clearly more sane. 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 not equivalent in Matlab:
if (1 | figure); x=3; end y=(1 | figure); if y; x=3; end
The second one pops up a figure window if one is not open; the first does not.
The Matlab documentation says: “Using the element-wise operators (& and |) for short-circuiting may yield unexpected results.” I think they should really say “using the element-wise operators with side-effects is dangerous because we do undocumented weird things”.
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 stupid behaviour. However, in either language not all functions you use necessarily let you give them matrices if they expect larger arrays. Currently broken: sort(randn(3,2,1), 3). This means that robust code has to be more complicated, because sometimes you have to check for the stupidness to avoid crashes.
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 (although none of the current versions do). I guess things could be a bit more complicated if slices of arrays are used for inputs and outputs, but maybe still doable. 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’ve done 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.)
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).
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
0^0 == 1 right? Unless the zero is in a sparse matrix in Matlab:
>> A = sparse([0,1]) A = (1,2) 1 >> A.^0 ans = (1,2) 1
Similarly dividing by zero doesn’t turn zeros into NaNs. Some versions of Octave copy these mistakes, others return full arrays with the correct answers. The safe and consistent way of operating on just the non-zero elements is:
>> spfun(@(x) x^0, A) ans = (1,2) 1
(The fancy functional syntax needs a pretty recent version of Octave or Matlab.)
Another sparse matrix oddity
Some versions of Matlab have crazy performance problems (e.g. 7.2.0.294 (R2006a), fixed by version 7.3.0), for example this performance bug:
>> tic;M=sprand(1e4,1e4,1e-2);toc Elapsed time is 2.206404 seconds. >> tic;M=M*2;toc Elapsed time is 2.454867 seconds. >> tic;M=spfun(@(x) x*2,M);toc Elapsed time is 0.182895 seconds.
The differences in performance under octave are somewhat more understandable:
octave:1> tic; M = sprand(1e4, 1e4, 1e-2); toc ans = 2.1400 octave:2> tic; M = M*2; toc ans = 0.021055 octave:3> tic; M = spfun(@(x) x*2, M); toc ans = 0.64994