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 is not always a clear agreement on the orientation of the matrices (transposed or not) and a certain row / column is added. Therefore, most of the time I spend debugging the following error:

Error using * Inner matrix dimensions must agree. 

And similar errors for + .* , - etc.

This will save me a lot of time if I can modify this error message to enable measurements, so that I know which one needs to be switched, and perhaps guess where the wrong measurement was. Therefore, I would like to somehow modify the error message to include dimensions:

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

Is this possible, and if so, how can I do this? I am currently spending a lot of time adding / removing / testing a debug code that outputs this information, so any solution that brings this closer would be helpful!

+5
source share
3 answers

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

For each operator, you can define a method for variables of type double , which shadow is an inline method and changes its behavior: in your case, enable custom error checking, and then call the inline method.

The advantages of this approach are as follows:

  • No changes are required in your code : you usually use * , *. , + , etc .; but their behavior (error checking) will change.

  • When you think that you have done debugging, you only need to remove your own methods from this path. This will restore normal behavior and thus avoid a speed penalty . Later, if you need to debug again, all you have to do is return the modified methods to the path.

In the following example, I use * and the associated mtimes . Your new mtimes method should be placed in the Matlab path in the appropriate folder so that it takes precedence over bulitin mtimes . This means that the folder must be in the matlab path . Or you can use the current folder, which takes precedence over everyone else.

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

The contents of mtimes.m will consist of 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: %ix %i and %ix %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 

Examples of 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 
+5
source

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] 
+7
source

If you have to do this with many matrix calculations, you can write functions like this, for example:

 function C = matproduct(A, B) try C = A * B; catch ME switch ME.identifier case 'MATLAB:dimagree' msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.']; case 'MATLAB:innerdim' msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.']; % other cases and corresponding modified msg here end throw(MException(ME.identifier, msg)); end end 

However, I'm not sure if this affects the speed ... And if you use it as matproduct(matproduct(a, b), c) for a * b * c , for example, the name of the first input cannot be displayed.

+2
source

All Articles