Compressing and decompressing multiple input arguments in Matlab/Octave

Posted on

Many functions in Matlab/Octave (particularly integration and optimization functions), are designed to accept function handles that only take a single vector input, that is, function handles of the form g(x). Hence anytime you want to use a function with multiple input arguments, such as

you need to write custom boilerplate code to make it work. This is repetitive, error-prone, and a waste of time. So here I am going to introduce some code and methodology that you can use to minimize the boilerplate code you have to write.

 

First, let’s look at a specific example. To minimize the single-input function

I would create an initial guess (e.g. x0 = zeros(2,11);), and then call a function like fminunc to do the minimization:

x = fminunc( @g, x0 )

However, to use fminunc with functions that have more than one input, such as f(x,y,z), I would typically have to vectorize the initial guess, and modify f so that it takes a single vector input. For instance, I could modify the function f to something like:

which I could then call from fminunc using a vectorized initial guess:

x0   = zeros(2,11);
y0   = zeros(3,4);
z0   = zeros(5,7);
xyz0 = [ x0(:) ; y0(:) ; z0(:) ];
xyz  = fminunc( @fmod, xyz0 )

The obvious problem here is that I have now hard-coded my input dimensions, thereby limited the versatility of my code. I could cook up some more advanced ways of getting around this problem, but there is no point. The result will be a mess, and I will spend a lot of time on what should be a trivial problem. Instead, let’s look at how to use the code I provide…

 

First of all, the code I present is called press, and is available in its raw form here: press.m. Using press still requires that the inputs get vectorized, but the boilerplate footprint is trivial. Instead of the nasty function fmod that we created before, your modified function f(x,y,z) will now look quite nice:

Furthermore, even the vectorization is fairly benign:

x0   = zeros(2,11);
y0   = zeros(3,4);
z0   = zeros(5,7);
xyz0 = press( 'xyzKey', x0, y0, z0 );
xyz  = fminunc( @fnew, xyz0 )

So what is going on here? The basic idea is that the press function is internally saving the dimensions of your input arguments during compression (that is, during the call xyz0 = press( 'xyzKey', x, y, z );), and then using those saved dimensions to handle decompression inside the function (that is, during the call [ x, y, z ] = press( 'xyzKey', xyz );). The string 'xyzKey' is simply some unique key that you must choose so that the code knows which set of arguments to compress or decompress. This unique string is necessary because you could be handling multiple compression/decompression events in your code, and so the code needs to know which set of arguments to work with. So, for instance, I could handle something like

x0   = zeros(2,11);
y0   = zeros(3,4);
xy0  = press( 'xy', x0, y0 );
z0   = zeros(5,7);
xyz0 = press( 'xyZ', xy0, z0 );
[ x, y ] = press( 'xy', xy0 );

To see the full project code and examples, see Github. Although you can find the complete code there, here is the specific code for the press function: