CMSC 341 Spring 2001

Project 2

Assigned  14 February 2001
Due  28 February 2001


Background

    A matrix is a set of values arranged in rows and columns.  Matrices are used in many fields of mathematics including linear algebra.  In that application, the values represent the coefficients of the terms of many simultaneous equations.  In some applications, most of the values in the matrix are zero.  Such a matrix is known as a "sparse" matrix since it has few non-zero values.  Because there are few non-zero values, programs which implement sparse matrices do not use the usual 2-dimensional array -- to do so would be a large waste of memory.  Instead, sparse matrices are implemented with other data structures whose structure is hidden by the implementation of the matrix operations.

Description

    In this project, you will implement a sparse matrix class (SMatrix) using the List ADT.  You will write the main program which will be used to test your SMatrix class based on requirements and pseudo code provided for you.  You will also create an SMatrixData class as well as iterators for the SMatrix.  As discussed in class, you will also need to use ListIterators.  See the details below.
    You must implement the List ADT as a sorted linked list  Code for the textbook's linked list and linked list iterator classes is provided.  You are free to use this code if you wish. You must create your own Makefile for this project as well.  Use the makefile from project 1 and modify it as necessary.
    Remember that class template files do not get compiled, and therefore their .o files SHOULD NOT be included in the list of object files.  Any .o files for non-template classes SHOULD be listed.

    The ADTs described here are expanded on in the "ADT" section, below. Use these expanded versions to design your classes. Please remember that you must provide good documentation as described in the "Project Organization" handout.

Here are your tasks:

  1. Read and understand the List and ListIterator ADTs described in the text and discussed in class. Code for the textbook's linked list and linked list iterator classes is available in the public directory.

  2. /afs/umbc.edu/users/d/e/dennis/pub/CMSC341
    Your List must store the matrix data (described below) in sorted order. To do so, you may choose one of the following approaches:
            1. Copy the Linked List code from the text, change the necessary methods to maintain a sorted linked list,
                and rename the class and all related files to SortedLinkedList
            2. Create a SortedLinkedList class by using inheritance to derive SortedLinkedList from the LinkedList class and overriding the necessary methods

      Be sure that your makefile references the appropriate files.
     

  1. Implement the SMatrixData ADT described below. This class stores the 0-base row number, 0-based column number, and the value for each non-zero element of the matrix.

  2.  
  3. Implement the SMatrix ADT described below.  This ADT must throw errors when operations are attempted on incompatible SMatrix objects.

  4.  
  5. Implement the test program Proj2.C, based on the pseudo code found in the file

  6. /afs/umbc.edu/users/d/e/dennis/pub/CMSC341/Proj2/Proj2.C

    In this program, main( ) takes three parameters -- the names of files which contain the data from which to construct three sparse matrices.  The format of these files is specified below.  Test files are located in the directory
    /afs/umbc.edu/users/d/e/dennis/pub/CMSC341/Proj2/

    There are three data files in this directory.  The files matrix1.dat and matrix2.dat are both 10 X 8 matrices.  This allows them to be added together, but not multiplied together.  The file matrix3.dat is an 8 X 8 matrix.  This allows it to be multipiled with either matrix1 or matrix2 and allows us to print the diagonal.  Any of these may be transposed. Feel free to construct your own data files for further testing. NOTE: The test files supplied may not be the same ones used to grade your project, but will have the relative dimensions as matrix1, matrix2 and matrix3 described above.
     

  7. Answer the questions posed in 341-Spring01-proj2_questions.txt. Copy the file

  8. /afs/umbc.edu/users/d/e/dennispub/CMSC341/Proj2/341-Spring01-proj2_questions.txt

    to your own directory and edit it to provide your answers to the questions. Don't forget to submit the edited file; it is 10% of this project's grade.
     

  9. Modify the makefile you submitted for project 1 to be suitable for project 2

ADT Definitions

    The following ADT must be implemented for this project.  In some instances, the implementation of the ADT is at least partially specified.
    All ADTs require the "big 4" -- default constructor, destructor, assignment operator and copy constructor, even if there is no code to write.  All ADTs require that all data members be private.
    You may add whatever private data and methods you deem appropriate for any class.
    Note that although the List ADT is implemented as a class template, these ADTs are not templates.

The SMatrix ADT

    A sparse matrix is a set of values arranged in rows and columns, but in which the vast majority are zero.  The sparse matrix supports all the usual matrix operations.  For this project, you may assume that the sparse matrix will consist of integer values.

    The operations allowed on the SMatrix ADT are:

    Your SMatrix class MUST be implemented using a single, sorted LIST of SMatrixData objects (described below) and use SMatrix iterators to traverse the matrix to perform the matrix operations defined above.
 

The SMatrixData ADT

    Because the data for the sparse matrix is not stored in a 2-dimensional array, the row and column information for each non-zero value must be specified.  This ADT provides accessor and mutator methods for the row, column and value. Further, because the SMatrix keeps the non-zero values in a sorted List, this ADT must support a comparison operator.

    The operations allowed on the SMatrixData ADT are:

The SMatrix Iterator ADTs

    Iterators are used with any data structure if it is necessary to access the individual elements of that data structure.  Even if the application does not need to access the elements directly, it is still a good idea to use iterators within the data structure's internal methods.
    In the case of the SMatrix class, it is necessary to access the individual elements two ways. One way is starting at (row 0, column 0), and moving along the row (across the columns) to (row 0, column 1), (row 0, column 2), .... to (row 0, column N-1).  This iterator could be used for output (among other things).  It is also necessary to have an iterator that starts at (row 0, column 0) and moves down the column (across the rows) to (row 1, column 0), (row 2, column 0), ... to (row M-1, column 0). This iterator might be used in operator * (matrix multiplication).
    These iterators are referred to as SMRowIter and SMColumnIter, respectively. An SMRowIter is considered "past end" when it gets to the end of the row.  Similarly, an SMColumnIter is considered "past end" when it is at the bottom of the column.

As iterators, these ADTs support the generic iterator methods described in class:

Exceptions in Project 2

    Since some SMatrix operations are invalid unless the matrices are "compatible", these methods must detect this incompatibility and throw an exception when it occurs.  These exceptions are then caught in main( ) and the appropriate action is taken.  In general, good design dictates that "low-level" code should only detect and report errors, not act on them.

    In this project, will create our own exception class(es).  The file "P2Exceptions.H" defines the BadMatrix exception class which should be thrown when certain matrix operations are not possible because the matrices are incompatible.  You will also use "dsexceptions.h" which defines the BadIterator exception class to be thrown when an iterator that "is past end" is used inappropriately.

    If you wish to add more exceptions in this project, you may do so.  In that case, copy the P2Exceptions.H file into your directory and modify as you deem necessary.  If you do make additions to P2Exceptions.H, be sure to submit your version of P2Exceptions.H and make the necessary changes to your makefile.


C++ Exceptions

C++ exceptions are used by the text in various places. Perhaps the first use is on page 74 in the retrieve method. Since you will be seeing exceptions throughout the course, this project will give you some easy experience with them. The particular exceptions you will use are the BadMatrix and BadIterator provided to you. The text defines a few other exceptions such as Underflow, Overflow, and OutOfMemory. You will not be using these in this project, but you will see them used in the text.

An exception can be "thrown" at any point in a program when an exceptional situation occurs. For example, an Overflow exception might be thrown when a quotient has a denominator of zero. An exception is  thrown by using the syntax "throw exception".  Typical code for Overflow would be:

       if (denom == 0)
          throw Overflow()
       else
          quotient = numer/denom;

When an exception is thrown, the normal flow of control is terminated while a suitable "catcher" is sought along the calling sequence. In this project, the SMatrix operator+ and others will throw the BadMatrix exception if the matrices are incompatible for the operation.  Iterators also throw the BadIterator exception if used improperly when "past end".

SMatrix::operator+ (const SMatrix& rhs)
{
   if (the matrices are incompatible)
       throw BadMatrix
   else
       do the operation
}

The code in main( ) that calls operator+ is surrounded by a "try-catch" block.

  try
 {
      matrix1 = matrix2 + matrix3;
 }
 catch (BadMatrix & exc)
 {
      cout <<  "Exception: Incompatible Matrices for addition" << endl;
 }

What happens is that if the call to operator+ is made on an incompatible SMatrix, the BadMatrix exception will be thrown. The enclosing "catch" block catches the exception and deals with it. In this case it simply prints an error message. If the "try-catch" block were not present, the exception would not be caught, and it would cause the program to terminate.


Proj2.C

    A skeleton version of Proj2.C is publicly available in the directory

        /afs/umbc.edu/users/d/e/dennis/pub/CMSC341

    This file has not been compiled and serves only as a framework for Proj2.C that you must complete it and submit.
    Note that Proj2.C uses try/catch blocks around SMatrix object methods.  It expects your code to throw
error.  Check out "dsexceptions.h" which is used in the textbook's LinkedList code on how to define  exception objects and how to throw and catch them.



 

Sparse Matrix Data Files

    Within Proj2.C, main( ) expects two command line arguments which are the names of files that contain the sparse matrix data.  If the arguments are present, you can assume that they are valid filenames and the data follows the format specified below.  The row/column/value triple will be randomly generated.  NO ORDERING should be assumed.



What to Submit

    For this project, you must submit the following files:
  1. Your makefile -- it must be named "makefile" or "Makefile".  The graders will simply type "make" and your file must compile and link all source files as appropriate
  2. Proj2.C -- after you have completed it by adding the missing code.  DO NOT change the #include directives
  3. SMatrix.H and SMatrix.C -- the definition and implementation files for the SMatrix class.  Because all they are tightly related, the SMatrixRowIter, SMatrixColumnItr and SMatrixData classes may also be defined and implemented in these files.  You may, of course, choose to implement each of these in it's own .H and .C files.
  4. P2Exceptions.H, only if you have added your own exception classes.
  5. Your answers to the project questions.


Grading and Academic Integrity


Project grading is described in the Project Policy handout.

Your answers to 341-Spring01-proj2_questions.txt are worth 10% of your project grade.

Cheating in any form will not be tolerated. Please re-read the Project Policy handout for further details on honesty in doing
projects for this course.

Remember, the due date is firm. Submittals made after midnight of the due date will not be accepted. Do not submit any files
after that time.


Matrix Operations

    For those who have not taken MATH 221 yet, or have simply forgotten, this section gives a brief explanation of matrix addition and multiplication.

    Matrix Addition

    Two matricies may be added if and only if they have the same dimensions (number of rows and columns).  To add the matrices, simply add the corresponding elements of each matrix.  The resulting matrix will be the same size as the matrices added together.

    Matrix Multiplication

    Two matrices can be multiplied if and only if the number of columns of the left hand matrix is the same as the number of rows of the right hand matrix.  For example, you can multiply a 3 x 4 matrix with
a 4 X 2 matrix (the result is a 3 X 2 matrix), but you can't multiply a 3 X 4 matrix with a 2 X 4 matrix.
Consider the following example which multiplies the 2 X 3 matrix on the right with the 3 X 2 matrix on
the left, resulting in the 2 X 2 matrix at the bottom.  Each element is labelled with its row and column number.
                Matrix A is 2 X 3                Matrix B is 3 X 2
               a11    a12    a13                        b11    b12
               a21    a22    a23                        b21    b22
                                                                b31    b32

                                         The result is 2 x 2
            a11*b11 + a12*b21 + a13*b31    a11*b12 + a12*b22 + a13*b32
            a21*b11 + a22*b21 + a23*b31    a21*b12 + a22*b22 + a23*b32

To form the product, we multiply the elements of each of matrix A's rows with the corresponding elements of each of matrix B's columns and sum the product of each element-wise multiplication.