////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Copyright -C- 1997, by Richard E. Pattis // // Class Name : Matrix // // Classification : Templated Class // // Files : Declaration - matrix.h // Definition - matrix.cpp // // Author : Richard E. Pattis // Computer Science Department // Carnegie Mellon University // 5000 Forbes Avenue // Pittsburgh, PA 15213-3891 // e-mail: pattis@cs.cmu.edu // // Maintainer : Author // // // Description: // // A templated Matrix class combines all the advantages of a C/C++ 2-dimensional // raw array with a struct that contains a 2-d array and its allocated/used sizes. // Basically, we can use this templated class to construct a 2-d array object and // access its homogenous members. For example, we can declare // // Matrix M(10,10); // // to construct an object M with 10 rows and 10 colums (100 int members, // numbered [0,0] to [9,9]). Note how we instantiate the Matrix class with // a member type int: Matrix. We can then access the members in this // object just like a 2-d array: e.g., M[4,6]. By carefully seting // Row_Used and Col_Used of the Matrix to the right values, we can ensure // that all member accesses are legal. // // We think about Matrix M(3,4) as follows: It has 3 rows, 4 columns (it is // accessed by Row first and then Colum) and can be visualized as // // Cols | 0 | 1 | 2 | 3 | // Rows | | | | | // ---------+--------+--------+--------+--------+ // | | | | | // 0 | [0][0] | [0][1] | [0][2] | [0][3] | // | | | | | // ---------+--------+--------+--------+--------+ // | | | | | // 1 | [1][0] | [1][1] | [1][2] | [1][3] | // | | | | | // ---------+--------+--------+--------+--------+ // | | | | | // 2 | [2][0] | [2][1] | [2][2] | [2][3] | // | | | | | // ---------+--------+--------+--------+--------+ // // Another advantage of this class is that the number of members can be // programmed to grow or shrink. So, we don't need to know how big a 2-d array // is at compile time, but can re-size it as necessary during runtime. // // Note the ~Matrix is a destructor. It is called automatically by C++ // for an object of the Matrix class when its scope is exited. This // function must reclaim all the storage the Matrix uses. For example // { // Matrix M(10,10); //Constructor for M is called explicitly // Matrix X(3,4); //Constructor for X is called explicitly // ... // } //Destructor for M and X is called implicitly // // // Known Bugs : None // // Future Plans : None // // History: // 11/15/97: R. Pattis - Operational // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Declarations // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //When we instantiate the templated Matrix class, we specify a Member_Type, // which is the name of a type (or class). Each member of the vector is a // value of this type or class. #ifndef __Matrix__ //Do not duplicate in a compilation #define __Matrix__ #include "vector.h" template class Matrix { /////// public: /////// //Constructors Matrix (); //Default Constructor Matrix (const Matrix& M); //Copy Constructor explicit Matrix (int Row_Size, int Col_Size); //Value Constructor //Destructor ~Matrix( ); //Assignment const Matrix& operator = (const Matrix& RHS); //Accessors int Row_Size () const; int Row_Used () const; int Col_Size () const; int Col_Used () const; const Vector& operator[](int R) const; bool Is_Full () const; //Mutators Vector& operator[](int R); void Fill_With (const Member_Type& Value); void Set_Size (int New_Row_Size, int New_Col_Size); void Set_Used (int New_Row_Used, int New_Col_Used); void Set_Size_From_Used (); void Set_Used_From_Size (); //////// private: //////// int my_Row_Size; int my_Col_Size; int my_Row_Used; int my_Col_Used; Vector< Vector > my_Values; }; template bool operator== (const Matrix& Left, const Matrix& Right); template bool operator!= (const Matrix& Left, const Matrix& Right); template ostream& operator<<(ostream& OS, const Matrix& M); //Template classes must include their code, so this .h file includes the .cpp //file automatically; for this reason there is no compiled version of the .cpp //file in the 15-127 class library (or any project) #include "matrix.cpp" #endif ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Semantics // // Requirements for Member_Type // 1) Must be primitive/struct or be a class with a default constructor // 2) Must have = (assignment) defined, and == and != relational operators // 3) Must have operators<< overloaded, inserting onto the console stream // Otherwise you will get a compiler error when this class is instantiated // // // Because the Matrix class was instantiated with int as the Member_Type, all the // members in the Matrix are unintialized; if Member_Type were a class, the // default constructor defined for that class would initialize every member in // the Matrix. // // // Class Invariants: // my_Row_Size * my_Col_Size = Allocated size of array pointed to by my_Values // my__Row_Used <= my_Row_Size (can use some or all of allocated array) // my__Col_Used <= my_Col_Size (can use some or all of allocated array) // my_Values Stores a Vector of Vector: this detail is not important // // Matrix (); // Pre : None // Post : Object constructed with all Sizes and Used = 0 // Note : This constructor is useful if you want to declare a Matrix in // some scope, but not specify its size until later (e.g., Set_Size): // for example, you might declare the Matrix in the main function, // and then pass it to a Load_From_File function which opens a file that // specifies the needed size; often Matrices are read this way // This constructor is also necessary to declare Matrix of Matrices // // // Matrix (const Matrix& M); // Pre : None // Post : Object is copy of M (same Sizes, Useds, all used values) // // // explicit Matrix (int Row_Size, int Col_Size); // PreExc : Row_Size and Col_Size >= 0; throws invalid_argument // Post : Object constructed with Row_Size() = Row_Size and Row_Used() = 0; // Col_Size() = Col_Size and Col_Used() = 0 // Note : Like Vectors, the Used accessors are initially set to 0 right after // an object is constructed; Unlike Vectors there is no append function, // so we typically call Set_Used to set these values // // // ~Matrix( ); // Pre : None // Post : All memory allocated for Matrix is deallocated // // // const Matrix& operator = (const Matrix& RHS); // Pre : None // Post : Object is copy of RHS (same Sizes, Useds, all used values) // // // int Row_Size () const; // Pre : None // Post : Returns maximum number of rows in the Matrix // // // int Col_Size () const; // Pre : None // Post : Returns maximum number of columns in the Matrix // // // int Row_Used () const; // Pre : None // Post : Returns number of rows being used // Note : This value is the one checked by the first argument in M[R][C] so it // appears in the upper bounds of for loops that iterate over rows // // // int Col_Used () const; // Pre : None // Post : Returns number of columns being used // Note : This value is the one checked by the second argument in M[R][C] so it // appears in the upper bounds of for loops that iterate over columns // // // const Member_Type& operator[] (int R, int C) const; // PreExc : 0 <= R <= Row_Used()-1; throws invalid_argument // 0 <= C <= Col_Used()-1; throws invalid_argument // Post : Returns value stored in the Rth row and Cth column member of this Matrix // Note : This operator throws an exception based on Useds not Sizes // // // bool Is_Full () const; // Pre : None // Post : Returns whether both Useds are the same as Sizes // // // Member_Type& operator[] (int R, int C); // PreExc : 0 <= R <= Row_Used()-1; throws invalid_argument // 0 <= C <= Col_Used()-1; throws invalid_argument // Post : Returns the storage location of the Rth row and Cth column member // of this Matrix (used to store a new value there) // Note : This operator throws an exception based on Useds not Size() // Example: M[2,2] = 0; // // // void Fill_With (const Member_Type& Value); // Pre : none // Post : Fills all used Rows/Columns with Value // // // void Set_Size (int New_Row_Size, int New_Col_Size); // PreExc : Row_Used() <= New_Row_Size; throws invalid_argument // Col_Used() <= New_Col_Size; throws invalid_argument // Post : Row_Size() = New_Row_Size and Col_Size() = New_Col_Size // Note : Increases or decreases Sizes, but not below Useds // // // void Set_Used (int New_Row_Used, int New_Col_Used); // PreExc : 0 <= New_Row_Used <= Row_Size(); throws invalid_argument // 0 <= New_Col_Used <= Col_Size(); throws invalid_argument // Post : Row_Used() = New_Row_Used and Col_Used() = New_Col_Used // Note : Increase or decreases Useds, but not below 0 or above Sizes // // // void Set_Size_From_Used (); // Pre : None // Post : Both Sizes are set from Useds; Matrix is now an exact fit // // // void Set_Used_From_Size (); // Pre : None // Post : Both Useds are set from Sizes; Matrix is now an exact fit // // // ostream& operator<<(ostream& OS, const Matrix& V); // Pre : operator<< must be overloaded for Member_Type; compilation error // Post : Displays members in [] with columns separated by commas and rows // separated by bars, suffixed by (Row_Size = ..., Col_Size =) // Example: Matrix M(5,5); // M.Set_Used(3,2); // M.Fill_With(8); //Fill the 3x2 Matrix with 8s // cout << M; prints [ 8,8 | 8,8 | 8,8 ] (Row_Size = 5, Col_Size = 5) // Note : From this we can infer M.Row_Used() is 3 and M.Col_Use() is 2 // (because of the pattern of | and ,) // ////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////