Sample Assignment: The Matrix Class
(Chapter 3)



Data Structures and Other Objects Using C++
Third Edition
by Michael Main and Walter Savitch
ISBN 0-321-19716-X

The Assignment:
You will implement and test a class for matrixes that have up to ten rows and ten columns. The coefficients of the matrix will be stored in a fixed 10x10 array of double numbers.
Purposes:
Ensure that you can write a small collection class.
Before Starting:
Read Sections 3.1 and 3.3. Section 3.2 might also be helpful, but it is not required reading.
Know how to compile and run C++ programs on your system.
Files that you must write:
  1. matrix.h: The header file for the new matrix class.
  2. matrix.cxx: The implementation file for the new matrix class. You will write all of this file, which will have the implementations of all the matrix's member functions.
  3. matrixtest.cxx A simple interactive test program. You may write this program on your own, or you may work together with one or two other students (sharing your test code).

The Matrix Class
Discussion of the Assignment

As indicated above, you will implement a new class called matrix, using a header file and an implementation file. Each matrix object is a rectangular grid of double numbers. The maximum number of rows and columns for the matrix is defined by a static member constant of the matrix class called MAX, which should be set to ten for this assignment. Keep in mind that your implementation should continue to work correctly when we change the size of MAX (something that you can be sure the TA will do when grading your work). Also, the date type of the entries should be declared with a typedef statement, like this:

typedef double value_type;
Everywhere else that the entries' type is referred to must use the name value_type. For example, you will need a two-dimensional array to store the coefficients of the matrix:
class matrix
{
...
private:
    value_type data[MAX][MAX];
    ...
};

The rows and columns of any matrix can be indexed by size_t numbers starting at zero. So, if a matrix has seven rows, then the indexes of those rows are 0 through 6. All functions that have indexes as arguments must use an assert statement to check that the sizes of the indexes are valid for the matrix.

Your matrix class must have these functions:

  1. A constructor with two arguments: the number of rows and the number of columns in the matrix. Both have a default value of 1. The constructor sets all coefficients of the matrix to zero.
  2. Two const member functions called many_rows and many_columns which return the number of rows or columns in a matrix.
  3. A const member function that allows you to retrieve the value of any coefficient.
  4. A member function that allows you to set the value of any coefficient.
  5. A non-member function that is an operator * to allow a matrix to be multiplied by a scalar. For example, if s and t are matrixes, I may write the statement: s = 4.2*t;
  6. A non-member function that is an operator * allows two matrixes to be multiplied together using the usual matrix multiplication. For example, if s and t are two matrixes with sizes that are compatible for matrix multiplication, then I may write a statement such as r = s*t; (where r is another matrix).
  7. A non-member function that is an operator % computes the Kronecker product of two matrixes. See Wikipedia or Wolfram Mathworld for a definition of this product.
  8. A const member function to print a matrix to any ostream--or, if you prefer you may overload the << operator as shown below.

This is a pretty big assignment, so I will help you out with a few items. In my implementation, the function to retrieve an element is:

value_type entry(size_t row, size_t column) const;
Using this member function, I can write the function that prints the array to an ostream, like this (you need <iomanip> for using setw, < ostream& operator << (ostream& outs, const matrix& m) { const int WIDTH=10; // Width for printing an entry size_t i, j; // Row and column numbers for (i = 0; i < m.many_rows( ); ++i) { for (j = 0; j < m.many_columns( ); ++j) { outs << setw(WIDTH) << m.entry(i,j); } outs << endl; } return outs; } Here's one more function that I wrote. I used a member function called set to set an entry in a matrix:
matrix operator * (matrix::value_type scalar, const matrix& m)
{
    matrix answer(m.many_rows( ), m.many_columns( ));
    size_t i, j; // Row and column numbers

    for (i = 0; i < answer.many_rows( ); ++i)
    {
        for (j = 0; j < answer.many_columns( ); ++j)
        {
            answer.set(i, j, scalar*m.entry(i,j));
        }
    }
    return answer;
}
You may use these functions as I have written them, or you may make changes. For example, you might change things so that the WIDTH is no longer a constant. Instead, it could be a new member variable that is set by some new member function that you design.
Michael Main (main@colorado.edu)