Is it possible to add a customized dbstop condition to Matlab?
Recently I found myself with out of bounds values in multiple variables, one way to track down the first occurance of this would be to set a conditional breakpoint on each line where these values are updated. However, I hope there is an easier way to do this.
I have recently had to track down a NaN which was fairly trivial due to:
dbstop if naninf
Hence I hope that it is possible to get something like:
dbstop if anything outside myBound
or
dbstop if myVariable outside myBound
I would of course be willing to take the performance hit that one may expect.
If you use the editor, you can set a stop as normal, right-click on it, select "set/modify condition" and enter the condition (the stop will turn from red to yellow).
From command line, you can use
dbstop in file if expression
dbstop in file at location if expression
e.g.
dbstop in myFile at 200 if (~isempty(var) && var > 3)
as mentioned by #LuisMendo.
The second option may be more useful, since the first one seems to be only evaluated at the start of the file. In other words, it doesn't seem to be possible to have a similarly generic expression as dbstop if naninf that checks for certain values across an entire file.
The problem with using the form "DBSTOP in FILESPEC if EXPRESSION" of dbstop is that it sets a breakpoint only at the first line of the file. A solution is to use the form "DBSTOP in FILESPEC at LINENO if EXPRESSION" to set a breakpoint at each line.
Consider the following example script, saved on a file called testfile.m.
clear all
for m = 1:10;
k = 2*m
end
Say we want to stop if variable k exceeds the value 6. We first automatically set the breakpoints in all lines of this file:
file = 'testfile.m';
varname = 'k';
expression = 'k>6'; %// it should be 'exist(''k'')&&k>6', but that's added later
%// Determine number of lines of file:
fid = fopen('testfile.m');
cont = 1;
nlines = 0;
while cont
readline = fgetl(fid);
cont = ~isequal(readline,-1);
nlines = nlines + cont;
end
fclose(fid);
%// Set breakpoint at each line. We need eval for this
for n = 1:nlines
eval(['dbstop in ' file ' at ' num2str(n) ' if ( exist(''' varname...
''') && ( ' expression ' ) )'])
end
Now, after running the above (check that every line of testfile.m has a yellow breakpoint), run testfile and check values when it stops:
This is admittedly a little cumbersome if you have several variables or files. Also, I'm not sure how many simultaneous breakpoints Matlab supports (we are using one for each program line).
Thinking outside the box - you could write a class to hold your variable. There you could have a customized setter that will raise a warning if you violate boundaries. dbstop if warning should then be enough.
Related
In Matlab I often use functions in my script that output something to the command window in one or several ways, for instance like this:
function output = mySubFunction(input)
disp(['the input is: ', num2str(input)])
output = input * 2;
disp(['the output is: ', num2str(output)])
end
If I now use this function in my script it would look something like this:
data = 5;
disp('applying transformation...')
transformation = mySubFunction(data);
disp(['the result of the transformation is: ', num2str(transformation)])
This is of course a very simple example, in fact the functions are often quite complicated and give a lot of output. In this case, to keep a better overview of what is going on in my main script using my command window, I would like to suppress the disp() functions in my mySubFunction. Is there any way that I can do this simply from my main script (that is, without diving into possibly very complicated functions and subfunctions to comment out all disp() functions or insert semicolons)?
I believe you want evalc.
From the MATLAB-documentation (the function is similar in Octave):
Use the "evalc" function to redirect all the output displayed on the
command window to a variable. This will not suppress figures, but it
does allow you to prevent print statements from being displayed in the
command window.
As an example:
[results, output] = evalc('mySubFunction(3)');
This displays nothing but stores the following variables in the workspace:
>> [results, output] = evalc('mySubFunction(3)');
>> ans
ans = 6
>> output
output = 6
>> results
results = the input is: 3
the output is: 6
The typical way to do this in any language as far as I'm concerned, not just matlab / octave, is to have a 'debug' or 'verbose' variable present, which is checked against an if statement and decides whether to print those logs. The if statement could be used in the relevant code directly, or wrapped inside a 'prettier' function responsible for doing the logging.
This variable may be passed explicitly to the function, or it could be a global variable. If you plan to run your script directly from the shell rather than directly from a matlab/octave environment, it could even be detected from from a shell-defined environmental variable. Alternatively, it could be read from a config file. It all depends on your use case.
For the sake of an example, here is your session, transformed as above, using the global variable approach.
%% in file mainScript.m
global VERBOSE
VERBOSE = true;
data = 5;
if VERBOSE, disp('applying transformation...'); end
transformation = mySubFunction(data);
if VERBOSE, disp(['the result of the transformation is: ', num2str(transformation)]); end
%% in file mySubFunction.m
function output = mySubFunction(input)
global VERBOSE
if VERBOSE, disp(['the input is: ', num2str(input)]); end
output = input * 2;
if VERBOSE, disp(['the output is: ', num2str(output)]); end
end
When I execute my script, one of the lines of code sets a variable to a 2x2 array of zeros. If I set a breakpoint, highlight the line and execute it in the command window, it produces an integer (which it should).
The other line sets first_peak to 0, when it should be 667.
(I added the cast in an attempt to resolve the problem because matlab was complaining about the variable type. Of course it didn't work.)
I can't seem to create an MWE without one of my datafiles, so attached are screenshots.
in-script:
command window:
If an MWE were going to produce the error, this one should, but again, it doesn't. The peaks(peak_ndx+1) line would produce the aforementioned 2x2 array, and peaks(peak_ndx) would produce the 0 value.
clear
for ndx = 1 : 6
peaks = [667 911 1288 1719 2114 2363 3505 3718 4010 4372 4682 4867];
peak_ndx=(ndx - 1) * 2 + 1;
peaks(peak_ndx)
peaks(peak_ndx+1)
end
TL;DR
When you hover the mouse over a variable, it shows the value that the variable currently has in the workspace.
The answer lies in the first paragraph you wrote. As you have mentioned, "When I execute my script, one of the lines of code sets a variable to a 2x2 array of zeros.", therefore hovering over second_peak on the line second_peak = cast(peaks(peak_ndx+1), 'int32') shows you zeros. Note that you have put a breakpoint on this line and this line is not executed yet. When you execute that line (unpause/continue running from the breakpoint) or enter that in the command window, you get the desired result.
If you put second_peak on another line and put a breakpoint on that line. Then after the second_peak = cast(peaks(peak_ndx+1), 'int32') line is run and program execution is paused at the next breakpoint, you'll see 1x1 int32 911.
Here is a reproducible example for you:
second_peak = int32([0,0;0,0]); %initially the value that you had
second_peak = int32(911); %put a breakpoint here
second_peak %and also here
Also make it sure that you're not doing unnecessary preallocation here.
Read "A Common Misunderstanding in Array Preallocation" in Loren Shure's blog.
If a variable is declared with the same name as a function, the variable may mask the function in some contexts (such as the Command Window), but not in others, such as in a script.
Is it possible to add a customized dbstop condition to Matlab?
Recently I found myself with out of bounds values in multiple variables, one way to track down the first occurance of this would be to set a conditional breakpoint on each line where these values are updated. However, I hope there is an easier way to do this.
I have recently had to track down a NaN which was fairly trivial due to:
dbstop if naninf
Hence I hope that it is possible to get something like:
dbstop if anything outside myBound
or
dbstop if myVariable outside myBound
I would of course be willing to take the performance hit that one may expect.
If you use the editor, you can set a stop as normal, right-click on it, select "set/modify condition" and enter the condition (the stop will turn from red to yellow).
From command line, you can use
dbstop in file if expression
dbstop in file at location if expression
e.g.
dbstop in myFile at 200 if (~isempty(var) && var > 3)
as mentioned by #LuisMendo.
The second option may be more useful, since the first one seems to be only evaluated at the start of the file. In other words, it doesn't seem to be possible to have a similarly generic expression as dbstop if naninf that checks for certain values across an entire file.
The problem with using the form "DBSTOP in FILESPEC if EXPRESSION" of dbstop is that it sets a breakpoint only at the first line of the file. A solution is to use the form "DBSTOP in FILESPEC at LINENO if EXPRESSION" to set a breakpoint at each line.
Consider the following example script, saved on a file called testfile.m.
clear all
for m = 1:10;
k = 2*m
end
Say we want to stop if variable k exceeds the value 6. We first automatically set the breakpoints in all lines of this file:
file = 'testfile.m';
varname = 'k';
expression = 'k>6'; %// it should be 'exist(''k'')&&k>6', but that's added later
%// Determine number of lines of file:
fid = fopen('testfile.m');
cont = 1;
nlines = 0;
while cont
readline = fgetl(fid);
cont = ~isequal(readline,-1);
nlines = nlines + cont;
end
fclose(fid);
%// Set breakpoint at each line. We need eval for this
for n = 1:nlines
eval(['dbstop in ' file ' at ' num2str(n) ' if ( exist(''' varname...
''') && ( ' expression ' ) )'])
end
Now, after running the above (check that every line of testfile.m has a yellow breakpoint), run testfile and check values when it stops:
This is admittedly a little cumbersome if you have several variables or files. Also, I'm not sure how many simultaneous breakpoints Matlab supports (we are using one for each program line).
Thinking outside the box - you could write a class to hold your variable. There you could have a customized setter that will raise a warning if you violate boundaries. dbstop if warning should then be enough.
I'm a Java programmer and have no background of matlab hence I'm really clueless with these lines of code from MATLAB. When I run the code I got an error :
??? Undefined function or variable 'nfile'.
Error in ==> texture_id at 29
fprintf(' \nneural network processing \n',nfile);
I understand that 'path' is a variable that stores string, 'demo' is boolean, but for the other lines, I don't want to assume what it does...Can you please help me and explain each lines?
Here's the code:
path = 'C:\Users\Dais\Documents\MATLAB\Data Sets\';
demo = true;
elfile = dir('*.jpg');
[lu ri] = size(elfile); feat=zeros(lu,29); nomf=cell(lu,1);
for nfi = 1:lu
nfile = elfile(nfi).name;
fprintf(' feature extraction file: %s \n',nfile);
nomf{nfi} = upper(nfile);
feat(nfi,:) = feature_ex([path nfile],demo);
end
fprintf(' \nneural network processing \n',nfile);
I would guess that whats happening here is that elfile = dir('*.jpg'); does not find any jpegs in the local directory and hence lu is empty and nfile is never populated. Place a breakpoint there in the code and check this. The way I would set up the loop would be something like this:
for nfi=1:numel(elfile)
As #Rody Oldenhuis said, use doc and help to elarn more about each function (or press F1 when the cursor is in the function name) but this should get you started..
%Looks for all files with extention .jpg in current directory
elfile = dir('*.jpg');
%lu and ri hold the rows, column lengths of elfile respectively
[lu ri] = size(elfile);
%creates an array of zeros of dimensions lu rows by 29 columns
feat=zeros(lu,29);
%creates an empty cell array (doc cell) dimensions lu rows by 1
nomf=cell(lu,1); columns
for nfi = 1:lu %look through all files
nfile = elfile(nfi).name; %get index nfi file
fprintf(' feature extraction file: %s \n',nfile); %print string
nomf{nfi} = upper(nfile); %upper case
feat(nfi,:) = feature_ex([path nfile],demo); %some external function
end
fprintf(' \nneural network processing \n',nfile); %print string
Rather than explain all and everything about MATLAB, I'll say this: MATLAB is interactive! And, one of the things why you pay good money for MATLAB, is that the documentation is awesome, and getting help is super easy.
For instance, you can type help <command> on the MATLAB command line, and get a short help on that command, or doc <command> to get the complete documentation, often with examples and demonstrations. The whole documentation is also online, should you prefer Google and being in a browser.
Should you have a script or function or class that has problems, you can issue dbstop if error, so that you drop into the debugger when an error occurs, and then you can view the contents of all variables just prior to the error, type new commands to investigate the error, etc. You can set breakpoints by clicking on the line number next to where you want to break, dbstep then makes a single step, dbup moves you up a level, etc. Have a look at doc dbstop.
You can select portions of code and press F9, which will execute those lines of code. Note that that is equivalent to copy-pasting the code to the command window and running it, so you will often have problems with undefined variables (and similar problems) that way (this or something similar is what I suspect happened in your particular case, as the code you posted should not give that error).
I'm curious about the progress of the running program and I print some information about the current iteration such as:
for i = 1:N
...
...
msg = sprintf('Processed %d/%d', i, N);
display(msg)
end
I don't want to print the progress on separate lines, instead, I want the last line to replace the previous one. I don't want to use clc which clears all the content.
I know that '\b' can clear the last character (like backspace) and I can create a function with a for loop which clears the items till the previous new line before the last. But is there a better way to do that? If not, how can I check whether the last character on the command line is a new line or not?
I've looked at the problem, a while ago. And I've noticed that the character \r (used to erase the last line) works with matlab in command-line (-nodesktop) but not with the graphic mode...
The best solution I found is to do something like that:
n=0;
for ...
...
fprintf(repmat('\b',1,n));
fprintf(msg);
n=numel(msg);
end
Yair Altman has a very nice example on his blog of how you can use the backspace control-character (\b) to do what you want but in an easier way than you were considering. Modifying your code to resemble his example, you could do something like this:
reverseStr = '';
for i = 1:N
...
...
msg = sprintf('Processed %d/%d', i, N);
fprintf([reverseStr, msg]);
reverseStr = repmat(sprintf('\b'), 1, length(msg));
end
I use 'dispstat' function just for this purpose. It can update the previous output which is a missing function of default 'disp'. Very simple to use. It can be downloaded from here: http://www.mathworks.com/matlabcentral/fileexchange/44673-overwritable-message-outputs-to-commandline-window
***Sample usage:
dispstat('','init'); % One time only initialization
dispstat(sprintf('Begining the process...'),'keepthis','timestamp');
for i = 97:100
dispstat(sprintf('Progress %d%%',i),'timestamp');
%doing some heavy stuff here
end
dispstat('Finished.','keepprev');
***Output:
11:25:37 Begining the process...
11:25:37 Progress 100%
Finished.
All the best
Is this about what you are looking for
%# create title
fprintf('processed: %03d',0)
for i=1:10
%# delete last three digit number and replace with new
%# loop index
fprintf('\b\b\b\b %03d',i);
%# process here
pause(.5)
end
%# clear line
fprintf('\n');
But if your code displays other results this won't work. and you might want to consider using a message box to update progress.
Another solution that overwrites the entire previous line relies on the \r formatting character,
ctrl=0;
while ctrl<5
fprintf('\rctrl: %i',ctrl);
ctrl=ctrl+1;
pause(2); % To highlight overwrite
end
fprintf('\n'); % Don't forget the newline