Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add debug code to error messages in Matlab?

In Matlab, I often have to work with matrices coming from another person's code, and there's not always a clear convention on the orientation of the matrices (transposed or not) and if a certain row/column is added. Therefore I spend much of my time debugging the following error

Error using  * 
Inner matrix dimensions must agree.

And similar errors for +,.*,-,etc.

It would save me a lot of time if I could modify this error message to include the dimensions, so that I know which one to switch, and potentially guess where the wrong dimension got into. Hence, I would like to somehow modify the error message to include the dimensions at hand:

Error using  * 
Inner matrix dimensions must agree: 243 x 23 and 98 x 23.

Is this possible, and if so, how can I do it? I currently spend a lot of time adding/removing/testing debug code that prints out this info, so any solution that brings this any closer would be helpful!

like image 909
user1111929 Avatar asked Sep 16 '15 13:09

user1111929


2 Answers

You can use a try-catch block:

a = rand(12);
b = rand(10);

try
    c = a*b;
catch err
    % Because err is read-only, generate new error structure
    % We can copy most of old one

    newerr.identifier = err.identifier;
    newerr.cause = err.cause;
    newerr.stack = err.stack;
    newerr.message = sprintf('%s size(a): [%u, %u] size(b): [%u, %u]', err.message, size(a), size(b));
    error(newerr) % Throw new error
end

Now we get:

Error using testcode (line 5)
Inner matrix dimensions must agree. size(a): [12, 12] size(b): [10, 10]
like image 60
sco1 Avatar answered Oct 30 '22 05:10

sco1


Each arithmetic operator in Matlab has an associated method that gets called when you invoke that operator. For example, the method corresponding to * (matrix multiplication) is called mtimes.

For each operator, you can define a method for variables of type double that shadows the builtin method and modifies its behaviour: in your case, include custom error checking and then call the builtin method.

The advantages of this approach are:

  • No modification in your code is neccessary: you will use *, *., + etc normally; but their (error-checking) behaviour will change.

  • When (you think) you're done debugging, you only need to remove your custom methods from the path. This will restore normal behaviour and thus avoid any speed penalty. Later, if you need to debug again, all you need to do is place the modified methods back on the path.

In the following I use * and its associated mtimes as an example. Your new mtimes method should be placed in Matlab's path, in an appropriate folder so that it has precedence over the bulitin mtimes. That means the folder should be up in Matlab's path. Or you can use the current folder, which has precedence over all others.

Within the selected folder create a folder called @double, and in it create a file called mtimes.m. This tells Matlab that your mtimes.m file should be used whenever the * is invoked with double inputs.

The contents of mtimes.m whould be something along the following lines:

function C = mtimes(A,B)
if ndims(A)~=2 || ndims(B)~=2
    %// number of dimensions is incorrect
    error('MATLAB:mtimes_modified:ndims', ...
        'One of the arrays is not a matrix: numbers of dimensions are %i and %i',...
        ndims(A), ndims(B));
elseif max(size(A))>1 & max(size(B))>1 size(A,2)~=size(B,1)
    %// dimensions are not appropriate for matrix multiplication,
    %// or for multiplying by a matrix by a scalar
    error('MATLAB:plus_modified:dimagree',...
        'Sizes do not match: %i x %i and %i x %i', ...
        size(A,1), size(A,2), size(B,1), size(B,2));
else
    C = builtin('mtimes', A, B); %// call actual mtimes to multiply matrices
end

Example results:

>> rand(3,4,5)*rand(6,7)
Error using  *  (line 3)
One of the arrays is not a matrix: numbers of dimensions are 3 and 2 

>> rand(3,4)*rand(2,5)
Error using  *  (line 7)
Sizes do not match: 3 x 4 and 2 x 5 

>> rand(3,4)*rand(4,2)
ans =
    0.3162    0.3009
    1.2628    0.7552
    1.2488    0.8559
like image 26
Luis Mendo Avatar answered Oct 30 '22 06:10

Luis Mendo