Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Trapping warnings efficiently

July 11, 2012 14 Comments

A not-well-known performance improvement trick for catching errors is to place the entire code section within a try–catch block. This is more efficient than constantly checking for some condition. For example:

% Standard code
for loopIndex = 1 : N
   refIndex = someCalculation();
   if refIndex > 0
      A(loopIndex) = B(refIndex);
   else
      A(loopIndex) = loopIndex;
   end
end
% Faster code
for loopIndex = 1 : N
   refIndex = someCalculation();
   try
      A(loopIndex) = B(refIndex);
   catch
      A(loopIndex) = loopIndex;
   end
end

% Standard code for loopIndex = 1 : N refIndex = someCalculation(); if refIndex > 0 A(loopIndex) = B(refIndex); else A(loopIndex) = loopIndex; end end % Faster code for loopIndex = 1 : N refIndex = someCalculation(); try A(loopIndex) = B(refIndex); catch A(loopIndex) = loopIndex; end end

Trapping warnings

However, what should we do in case the checked condition is meant to prevent a warning (e.g., file-access warnings) rather than an error? It would make sense to use the same exception-handling trick, but unfortunately warnings do not normally raise a trappable exception. This question was asked on the CSSM newsgroup many years ago and received no answer, until Michael Wengler recently provided the undocumented solution on that thread:
It appears that in addition to the documented alternatives for the value of the warning function’s first parameter (namely ‘Message’, , ‘On’, ‘Off’ and ‘Query’), there is also an undocumented alternative of ‘Error’. The effect is to turn the specified warning ID into an error, that can then be trapped in a standard try–catch block. After we have finished processing, we can return the warning state to its previous value.
For example:

% Set a couple of warnings to temporarily issue errors (exceptions)
s = warning('error', 'MATLAB:DELETE:Permission');
warning('error', 'MATLAB:DELETE:FileNotFound');
% Run the processing section
filesList = {'a.doc', 'b.doc', 'c.doc'};
for fileIndex = 1 : length(filesList)
   try
      % Regular processing part
      fileToDelete = filesList{fileIndex};
      delete(fileToDelete);
   catch
      % Exception-handling part
      fprintf('Can''t delete %s (reason: %s)\n', fileToDelete, lasterr);
   end
end
% Restore the warnings back to their previous (non-error) state
warning(s);

% Set a couple of warnings to temporarily issue errors (exceptions) s = warning('error', 'MATLAB:DELETE:Permission'); warning('error', 'MATLAB:DELETE:FileNotFound'); % Run the processing section filesList = {'a.doc', 'b.doc', 'c.doc'}; for fileIndex = 1 : length(filesList) try % Regular processing part fileToDelete = filesList{fileIndex}; delete(fileToDelete); catch % Exception-handling part fprintf('Can''t delete %s (reason: %s)\n', fileToDelete, lasterr); end end % Restore the warnings back to their previous (non-error) state warning(s);

For the record, this warning(‘error’,…) trick appears to work in Matlab releases as far back as R14SP3 (2005), and possibly even earlier (I don’t have older releases readily available, so I couldn’t check). This looks like a pretty stable feature, as far as undocumented features go. Of course, it could well be taken out at any future Matlab release, but for the time being we can definitely make good use of it.

Trapping specific warning IDs

How can we know the specific warning IDs (e.g., ‘MATLAB:DELETE:FileNotFound’) to use? The answer is to call warning(‘on’,’verbose’) and then simulate the warning. For example:

>> warning on verbose
>> delete sadfsefgsdfg
Warning: File 'sadfsefgsdfg' not found.
(Type "warning off MATLAB:DELETE:FileNotFound" to suppress this warning.)

>> warning on verbose >> delete sadfsefgsdfg Warning: File 'sadfsefgsdfg' not found. (Type "warning off MATLAB:DELETE:FileNotFound" to suppress this warning.)

Within the exception-handling part, we could check the specific exception that was thrown and possibly act differently. For example:

try
   % Regular processing part
   fileToDelete = filesList{fileIndex};
   delete(fileToDelete);
catch
   % Exception-handling part
   err = lasterror;
   switch identifier
      case 'MATLAB:DELETE:Permission'
         fprintf('Can''t delete %s (reason: no permission)\n', fileToDelete);
      case 'MATLAB:DELETE:FileNotFound'
         fprintf('Can''t delete %s (reason: file not found)\n', fileToDelete);
      otherwise
         fprintf('Can''t delete %s (reason: %s)\n', fileToDelete, lasterr);
   end
end

try % Regular processing part fileToDelete = filesList{fileIndex}; delete(fileToDelete); catch % Exception-handling part err = lasterror; switch identifier case 'MATLAB:DELETE:Permission' fprintf('Can''t delete %s (reason: no permission)\n', fileToDelete); case 'MATLAB:DELETE:FileNotFound' fprintf('Can''t delete %s (reason: file not found)\n', fileToDelete); otherwise fprintf('Can''t delete %s (reason: %s)\n', fileToDelete, lasterr); end end

Note that within the exception-handling part, I used the lasterr and lasterror functions, rather than lastwarn. The reason is that the warnings have been converted into standard errors, and are no longer even reported by lastwarn.
The acute reader will have noticed that I am using the older (deprecated) manner of exception handling, that does not directly pass the error struct into an identifier next to the catch keyword. The reason is that I usually intend my code to be backward compatible. Had I used the newer syntax, the code would not have worked on old Matlab releases; this way it does, subject to the availability of the above-mentioned undocumented warning(‘error’,…) trick. If you read through the code of my numerous submissions on the File Exchange, you will see that this is a recurring theme. I often use old deprecated syntax to ensure that my code will run on as many Matlab releases as possible.
Are you interested in learning more performance improvement methods? Then consider joining my Matlab Performance Tuning seminar/workshop in Geneva on August 21, 2012 – email me (altmany at gmail dot com) for details.

Related posts:

  1. getundoc – get undocumented object properties – getundoc is a very simple utility that displays the hidden (undocumented) properties of a specified handle object....
  2. A couple of internal Matlab bugs and workarounds – A couple of undocumented Matlab bugs have simple workarounds. ...
  3. Afterthoughts on implicit expansion – The new implicit expansion feature of Matlab R2016b can break user code in unexpected ways. ...
  4. Parsing XML strings – Matlab's xmlread function cannot process XML data directly, but this can easily be overcome. ...
  5. More undocumented timing features – There are several undocumented ways in Matlab to get CPU and clock data...
  6. Parsing mlint (Code Analyzer) output – The Matlab Code Analyzer (mlint) has a lot of undocumented functionality just waiting to be used. ...
Performance Pure Matlab Undocumented feature
Print Print
« Previous
Next »
14 Responses
  1. John Thompson August 19, 2012 at 13:48 Reply

    Hello,
    Very informative post. I found a bug in the code in the ‘Trapping warnings block’: you initialize your counter with filesIndex = 1, but index with filesList{fileIndex}. There is a mismatch between filesIndex and fileIndex (i.e. one is plural and the other is singular).

    Best,
    John

    • Yair Altman August 19, 2012 at 15:37 Reply

      @John – thanks, corrected

  2. Baz November 12, 2012 at 12:23 Reply

    Hi there, I have tried to use your template above to do my own error trapping. However, I have found some rather strange behavior. When I run the code as shown below, the code runs and delivers the correct results. However when I %matlabpool open, %matlabpool close and change parfor to a simple for, the code will not run and I get the following error:

    Running...       ??? Error using ==> mldivide
    Matrix is singular to working precision.
     
    Error in ==> NSS_betas at 11
        betas = Gdata.y2.';
     
    Error in ==> DElambda at 19
            betas(:,ii) = NSS_betas(P1(:,ii),data); end
     
    Error in ==> Individual_Lambdas at 46
        beta{ii} = DElambda(de,dataList, @OF_NSS);

    Running... ??? Error using ==> mldivide Matrix is singular to working precision. Error in ==> NSS_betas at 11 betas = Gdata.y2.'; Error in ==> DElambda at 19 betas(:,ii) = NSS_betas(P1(:,ii),data); end Error in ==> Individual_Lambdas at 46 beta{ii} = DElambda(de,dataList, @OF_NSS);

    Now I am not surprised to be getting the error, this is the result of the

    warnState(1) = warning('error', 'MATLAB:singularMatrix');
    warnState(2) = warning('error', 'MATLAB:illConditionedMatrix');

    warnState(1) = warning('error', 'MATLAB:singularMatrix'); warnState(2) = warning('error', 'MATLAB:illConditionedMatrix');

    I included (there is not try catch yet included yet in the function DElambda). What confuses me though it why when I run this code as part of a parallel loop no errors are generated? Do trapping warnings work with parfor?

    clear all, clc
    load Euro_CRM_22_12.mat
    matlabpool open
     
    tic
    warnState(1) = warning('error', 'MATLAB:singularMatrix'); 
    warnState(2) = warning('error', 'MATLAB:illConditionedMatrix'); 
     
    mats  = 1:50;
    mats2 = [2 5 10 30];
     
    % RO: unloop these
    de = struct(...
        'min', [0;0],...
        'max', [50;50],...
        'd'  , 2,...
        'nP' , 500,...
        'nG' , 600,...
        'ww' , 0.1,...
        'F'  , 0.5,...
        'CR' , 0.99,...
        'R'  , 0,...
        'oneElementfromPm',1);
     
    % RO: initialize beta
    beta  = cell(size(rates,1),1);
     
    clc, fprintf('Running...       ');
     
    %for ii = 1:size(rates,1)
    parfor ii = 1:size(rates,1)    
        % RO: use status indicator for things that take this long
        %fprintf('bbbbbbb%6.2f%%', ii/size(rates,1)*100);
     
        dataList = struct(...
            'yM'   , rates(ii,:),...
            'mats' , mats,...
            'model', @NSS,...
            'mats2', mats2,...
            'y2'   , rates(ii,mats2));
     
        beta{ii} = DElambda(de,dataList, @OF_NSS);
    end
    toc
    matlabpool close

    clear all, clc load Euro_CRM_22_12.mat matlabpool open tic warnState(1) = warning('error', 'MATLAB:singularMatrix'); warnState(2) = warning('error', 'MATLAB:illConditionedMatrix'); mats = 1:50; mats2 = [2 5 10 30]; % RO: unloop these de = struct(... 'min', [0;0],... 'max', [50;50],... 'd' , 2,... 'nP' , 500,... 'nG' , 600,... 'ww' , 0.1,... 'F' , 0.5,... 'CR' , 0.99,... 'R' , 0,... 'oneElementfromPm',1); % RO: initialize beta beta = cell(size(rates,1),1); clc, fprintf('Running... '); %for ii = 1:size(rates,1) parfor ii = 1:size(rates,1) % RO: use status indicator for things that take this long %fprintf('bbbbbbb%6.2f%%', ii/size(rates,1)*100); dataList = struct(... 'yM' , rates(ii,:),... 'mats' , mats,... 'model', @NSS,... 'mats2', mats2,... 'y2' , rates(ii,mats2)); beta{ii} = DElambda(de,dataList, @OF_NSS); end toc matlabpool close

    • Yair Altman November 12, 2012 at 12:32 Reply

      @Baz – apparently this only works in a non-distributed environment…

      • Baz November 12, 2012 at 12:51

        Thanks, the reason I am doing the coding this way is that rdivide is generating these error messages when it enounters a singular/badly conditioned matrix, so rdivide is clearly already using rcond() to test the conditioning of the matrices. I need to check the conditioning of the matrices, rather than me having to call rcond() again to duplicate this work, I would just like to get access to the rcond values and/or the decision as to whether the matrix is badly conditioned or not that rdivide is already producing. Ideally within a parallel structure if this is possible?

        To be clear the parallel toolbox does still produce these warning messages, its just when I add:

        warnState(1) = warning('error', 'MATLAB:singularMatrix'); 
        warnState(2) = warning('error', 'MATLAB:illConditionedMatrix');

        warnState(1) = warning('error', 'MATLAB:singularMatrix'); warnState(2) = warning('error', 'MATLAB:illConditionedMatrix');

        to turn them into errors that the divergence between parfor and for arises.

        Would I be better to just call rcond() myself, this will mean duplication of work (which is annoying), but as least it will work.

  3. Steve Coleman June 19, 2013 at 08:37 Reply

    Just a note. The Try/Catch construct can have a tremendous performance hit if used inside a loop that is executed many many times, but this can very by environment. I have one report that would run fine on my laptop in a matter of hours, but when placed on the Big-Server in the basement that time literally turned into days. Profiling on each machine showed a very clear difference in the time allocated to the same try/catch, running on the same dataset, in the two different environments. After removing the try/catch statement from a very tight loop in the core of the main algorithm, that change made all the difference.

    Try/Catch by its very nature does a *lot* of housekeeping under the covers, to build stack frames that can be unwound back up to higher levels, which the if/else construct does not have to do. If a condition is a simple test (e.g. >0 or isempty) and in a very tight loop, it can be much more efficient to just use the if/else construct.

    After the above experience I now reserve try/catch for main-level to second-tier level functions and try to keep them out of the often called modules. Try/catch is great, but use them wisely. If its called more than 100 times in a given run then if/else may be a better bet. For checking user input or possibly tainted network data, try/catch is great! Using it in a loop running a million times, maybe not so much.

    • Yair Altman June 19, 2013 at 12:16 Reply

      @Steve – thanks for the clarification, duly noted.

  4. Matlab warning('error') produces not enough arguments error - DexPage July 17, 2015 at 15:07 Reply

    […] additional input (a message identifier). It is used for trapping/catching warnings as errors. See this Undocumented Matlab post and this MathWorks Newsgroup […]

  5. Noam G October 26, 2015 at 16:17 Reply

    Hi Yair,
    Do you have any idea how could I find all the warnings occurred since a certain point and on?
    lastwarn returns only the last warning, but let’s say that I want to test some code, and I want to track ALL the warnings it had produced.
    Do you think it’s possible?

    • Yair Altman October 27, 2015 at 09:15 Reply

      @Noam – I am not aware of any way to achieve this. But I very rarely say that anything is impossible…

  6. Ken Johnson July 27, 2022 at 09:24 Reply

    Why does the second catch block in this code example not work? (It works if you restart MATLAB and then omit the first try-catch block.)

    try
        a = [0,0;0,0][1;1];
    catch
        disp('Caught.')
    end
    lastwarn('')
    warning('error','MATLAB:singularMatrix')
    try
        a = [0,0;0,0][1;1];
    catch
        disp('Caught.')
    end
    lasterr
    lastwarn

    try a = [0,0;0,0][1;1]; catch disp('Caught.') end lastwarn('') warning('error','MATLAB:singularMatrix') try a = [0,0;0,0][1;1]; catch disp('Caught.') end lasterr lastwarn

    • Yair Altman August 9, 2022 at 12:55 Reply

      @Ken – I cannot reproduce your report, it works as expected for me even on R2022b

  7. Bob Pownalll June 12, 2024 at 16:40 Reply

    Thanks! I was trying to figure out how to do exactly this (i.e. Use a try / catch block with something that generated a warning, not an error) and you pointed me to a solution!

    I have one question, though.

    At the very start of your example, you have:

    % Set a couple of warnings to temporarily issue errors (exceptions)
    s = warning('error', 'MATLAB:DELETE:Permission');

    and then at the end, you have:

    % Restore the warnings back to their previous (non-error) state
    warning(s);

    Won’t this restore the warnings back to the state with the first warning-converted-to-error, not the “previous (non-error) state”?

    To restore the warnings to the previous (non-error) state, shouldn’t your example be:
    (Note that the assignment of s has changed.)

    s = warning;
    warning('error', 'MATLAB:DELETE:Permission');
    ...
    % Restore the warnings back to their previous (non-error) state
    warning(s);

    That seems to be the the way my MATLAB version (R2018a) works.

    Or am I misunderstanding something?

    • Yair Altman June 14, 2024 at 10:39 Reply

      @Bob – you are mistaken: s=warning(...) returns the warnings state as it was before the state was modified, so my code is correct. There is no need for a separate call to s=warning;.
      I agree that this is not clearly explained in the official doc-page, but you can see the behavior in the example that is provided in that doc-page: https://www.mathworks.com/help/matlab/ref/warning.html#buh8kqc-13

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top