Coping with errors and the MATLAB debugger

1.4.3 Coping with errors and the MATLAB debugger

No matter how carefully you work, eventually you will produce code with errors in it. The simplest errors are usually due to mangled syntax and are relatively easy to fix. A MATLAB language guide is essential for the beginner to decipher the syntax errors.

More subtle errors only become apparent at runtime after correcting all of the syntax errors. Very often, runtime errors are related to incorrect matrix sizes. For example, suppose we wish to pad a seismic matrix with nzs zero samples on the end of each trace and nzt zero traces on the end of the matrix. The correct way to do this is show in Code Snippet 1.4.2.

Code Snippet 1.4.2. Assume that a matrix seis alreadyexists and that nzs and nzt are already defined as the sizes of zero pads in samples and traces respectively. Then a padded seismic matrix is computed as:

1 %pad with zero samples

2 [nsamp,ntr]=size(seis);

3 seis=[seis;zeros(nzs,ntr)];

4 %pad with zero traces

5 seis=[seis zeros(nsamp+nzs,nzt)];

End Code

The use of [ . . . ] on lines 3 and 5 is key here. Unless they are being used to group the return variables from a function, [ . . . ] generally indicate that a new matrix is being formed from the concatenation of existing matrices. On line 3, seis is concatenated with a matrix of zeros that has the same number of traces as seis but nzs samples. The semi-colon between the two matrices is crucial here as it is the row separator while a space or comma is the column separator. If the elements in [ ] on line 3 were separated by a space instead of a semi-colon, MATLAB would emit the error message:

??? All matrices on a row in the bracketed expression must have the same number of rows.

22 CHAPTER 1. INTRODUCTION This occurs because the use of the column separator tells MATLAB to put seis and zeros(nxs,ntr)

side-by-side in a new matrix; but, this is only possible if the two items have the same number of rows. Similarly, if a row separator is used on line 5, MATLAB will complain about “All matrices on a row in the bracketed expression must have the same number of columns ”.

Another common error is an assignment statement in which the matrices on either side of the equals sign do not evaluate to the same size matrix. This is a fundamental requirement and calls attention to the basic MATLAB syntax: MatrixA = MatrixB. That is, the entities on both sides of the equals sign must evaluate to matrices of exactly the same size. The only exception to this is that the assignment of a constant to a matrix is allowed.

One rather insidious error deserves special mention. MATLAB allows variables to be “declared” by simply using them in context in a valid expression. Though convenient, this can cause problems. For example, if a variable called plot is defined, then it will mask the command plot. All further commands to plot data (e.g. plot(x,y)) will be interpreted as indexing operations into the matrix plot . More subtle, if the letter i is used as the index of a loop, then it can no longer serve its √ predefined task as −1 in complex arithmetic. Therefore some caution is called for in choosing variable names, and especially, the common Fortran practice of choosing i as a loop index is to be discouraged.

The most subtle errors are those which never generate an overt error message but still cause incorrect results. These logical errors can be very difficult to eliminate. Once a program executes successfully, it must still be verified that it has produced the expected results. Usually this means running it on several test cases whose expected behavior is well known, or comparing it with other codes whose functionality overlaps with the new program.

The MATLAB debugger is a very helpful facility for resolving run-time errors, and it is simple to use. There are just a few essential debugger commands such as: dbstop, dbstep, dbcont, dbquit, dbup, dbdown . A debugging session is typically initiated by issuing the dbstop command to tell MATLAB to pause execution at a certain line number, called a breakpoint. For example dbstop at 200 in plotimage will cause execution to pause at the executable line nearest line 200 in plotimage . At this point, you may choose to issue another debug command, such as dbstep which steps execution a line at a time, or you may issue any other valid MATLAB command. This means that the entire power of MATLAB is available to help discover the problem. Especially when dealing with large datasets, it is often very helpful to issue plotting commands to graph the intermediate variables.

As an example of the debugging facility, consider the problem of extracting a slice from a matrix. That is, given a 2D matrix, and a trajectory through it, extract a sub-matrix consisting of those samples within a certain half-width of the trajectory. The trajectory is defined as a vector of row numbers, one-per-column, that cannot double back on itself. A first attempt at creating a function for this task might be like that in Code Snippet 1.4.3.

Code Snippet 1.4.3. Here is some code for slicing through a matrix along a trajectory. Beware, this code generates an error.

1 function s=slicem(a,traj,hwid) 2

3 [m,n]=size(a);

4 for k=1:n %loop over columns

5 i1=max(1,traj(k)-hwid); %start of slice

6 i2=min(m,traj(k)+hwid); %end of slice

7 ind=(i1:i2)-traj(k)+hwid; %output indices

8 s(ind,k) = a(i1:i2,k); %extract the slice

9 end

End Code

23 First, prepare some simple data like this:

1.4. PROGRAMMING TOOLS

a=((5:-1:1)’)*(ones(1,10)) a=

traj=[1:5 5:-1:1] traj =

The samples of a that lie on the trajectory are 5 4 3 2 1 1 2 3 4 5. Executing slicem with the command s=slicem(a,traj,1) generates the following error:

??? Index into matrix isnegative or zero. Error in ==> slicem.m On line 8 ==> s(ind,k) = a(i1:i2,k);

This error message suggests that there is a problem with indexing on line 8; however, this could

be occurring either in indexing into a or s. To investigate, issue the command “dbstop at 8 in slicem ” and re-run the program. Then MATLAB stops at line 8 and prints

8 s(ind,k) = a(i1:i2,k); K ≫

Now, suspecting that the index vector ind is at fault we list it to see that it contains the values

12 and so does the vector i1:i2. These are legal indices. Noting that line 8 is in a loop, it seems possible that the error occurs on some further iteration of the loop (we are at k=1). So, execution is resumed with the command dbcont. At k=2, we discover that ind contains the values 0 1 2 while i1:i2 is 1 2 3. Thus it is apparent that the vector ind is generating an illegal index of 0. A moments reflection reveals that line 7 should be coded as ind=(i1:i2)-traj(k)+hwid+1; which includes an extra +1. Therefore, we exit from the debugger with dbquit, make the change, and re-run slicem to get the correct result:

s=

The samples on the trajectory appear on the central row while the other rows contain neighboring values unless such values exceed the bounds of the matrix a, in which case a zero is returned. A more polished version of this code is found as slicemat in the NumMethToolbox . Note that a simpler debugger procedure (rather than stopping at line 8) would be to issue the command “dbstop if error ” but the process illustrated here shows more debugging features.

24 CHAPTER 1. INTRODUCTION