Matrix Multiplication - C++ Program

DavidB 3 Tallied Votes 2K Views Share

Here is a small--complete--program that includes a sub-routine that inputs two matrices and then multiplies them.

Notes:

  • 1) I happen to like taking input from a text file. It eliminates the need to type input from the console, especially when debugging, it prevents the possibility of making typos.

  • 2) The sub-routine includes several checks to make sure the array sizes are correct. These checks are not necessary for this particular program, but the checks were added in case the sub-routine is ever copied and used somewhere other than this program.

  • 3) To make the code more concise, I have used typedef to re-name vector<vector<double> > as "C2DArray".

  • 4) This program also shows an example of two more aspects of C++ programming: (i) dynamic arrays using <vector>, and (ii) inputting data from a text file and putting it into arrays

===========================

// Mat_Mul1.cpp - This program inputs two matrices, [A] and [B], from a file and then multiplies them:
     // [A][B] = [C]
     // First, the user is prompted to input the sizes of the arrays to be multiplied, M X N, and N X P.
     // The arrays are then created. The entries for all three arrays are input from a text file.
     // The product array, [C], is output to another text file.
     // Written in Visual C++ 2012 Express Edition
     // 7 June 2013
    
     #include <iostream>
     #include <fstream>
     #include <cctype>
     #include <cmath>
     #include <vector>
     #include <float.h>
    
     using namespace std;
    
     typedef vector<vector<double> > C2DArray;
    
     void Matrix_Mult(bool* error_flag, const int mRows, const int nCols, const int pCols, const C2DArray A_Matrix, const C2DArray B_Matrix, C2DArray& C_Matrix) {
     // Routine to compute the product of two matrices: [A][B] = [C]
     // [A] and [B] are inputs, [C] is the product matrix, output.
     // [A] is of size M X N
     // [B] is of size N X P
     // [C] is of size M X P
    
    	 int i = A_Matrix.size(), j = A_Matrix[0].size(), k = B_Matrix[0].size();
    	 double dummy;
    
    	 // Do some double-checks to make sure matrix dimensions are actually what was fed in to this sub-routine.
    	 // If data not consistent, perhaps other problems present too. User should re-check information.
    
    	 if ((j != B_Matrix.size()) || (i != mRows) || (j != nCols) || (k != pCols))  *error_flag = true;
    
    	 // Make sure C matrix is proper size to receive data
    
    	 if ((C_Matrix.size() != i) || (k != C_Matrix[0].size()))  *error_flag = true;
    
    	 if (!(*error_flag)){
    		for (k = 0; k < mRows; k++) { // Do each row of A with each column of B
    			for (i = 0; i < pCols; i++) {
    				dummy = 0.0;
    				for (j = 0; j < nCols; j++) {
    					dummy += A_Matrix[k][j]*B_Matrix[j][i];
    			    } // End for j
    			    C_Matrix[k][i] = dummy;
    			} // End for i
    		} // End for k
    	 }
    
         return;
     } // End Matrix_Mult
    
     int main()
     {char rflag = 0; //Readiness flag 
    
     cout << "                 Mat_Mul1 (7 June 2013)\n";
     cout << "=========================================================================== \n";
     cout << "This program multiplies two matrices, [A] and [B]: [A][B] = [C].\n";
     cout << "[A] is M X N, [B] is N X P, and [C] is M X P\n";
     cout << "The dimensions of the [A] and [B] matrices, M, N, and P, should \n";
     cout << "have been saved beforehand in a file named mulmatdat.\n";
     cout << "mulmatdat should be in the same folder as the Mat_Mul1 executable.\n";
     cout << "The next values of mulmatdat should be the entries for matrix [A],\n";
     cout << "with data for row 1 first, then row 2, then row 3, etc.\n";
     cout << "The entries for the [B] matrix should follow, in the same order.\n";
     cout << "\nThe data is assumed to be of type double. Variables used within this program\n";
     cout << "are type double.\n";
     cout << "\nThe output is written to the file mulmatout.txt.\n";
    
     cout << "\nIs everything ready (are you ready to continue?)? If yes, Enter y. \n";
     cout << "Otherwise Enter any other key. \n";
     cin >> rflag;
    
     if (toupper(rflag) == 'Y') {
    	C2DArray A, B, C; // A, B, and C Matrices
    	int i, j, mDim, nDim, pDim; // Array index variables and matrix dimensions
    	bool erFlag = false;  // Error flag
    
    	ifstream in("mulmatdat.txt", ios::in);
    
    	if (!in) {
             cout << "\nCannot open the input file.\n";
    	     cout << "\nEnter any key to continue. \n";
    	     cin >> rflag;
             return 0;
    	}
    
    	in >> mDim >> nDim >> pDim; //Input the Matrices' dimensions from the file
    	
    	if ((mDim < 1) || (nDim < 1) || (pDim < 1)){
             cout << "\nInvalid dimension entered. Program terminated. \n";
    	     cout << "\nEnter any key to continue. \n";
    	     cin >> rflag;
             in.close(); //Close the input file before terminating
             return 0;
    	}
    
    	ofstream out("mulmatout.txt", ios::out);
    	if (!out) {
             cout << "\nCannot open the output file. Program terminated.\n";
    	     cout << "\nEnter any key to continue. \n";
    	     cin >> rflag;
             in.close(); //Close the input file before terminating
             return 0;
    	}
    
    	// Beginning of try block, if vector re-sizing unsuccessful
    	try {
    
            // Resize the arrays to the appropriate sizes
             A.resize(mDim); // M rows
    	     B.resize(nDim); // N rows
    	     C.resize(mDim); // M rows
             for (i = 0; i < mDim; i++){
                A[i].resize(nDim); // M columns
    	        C[i].resize(pDim); // P columns
             } // End for i
    
    	     for (i = 0; i < nDim; i++){
                B[i].resize(pDim); // P columns
             } // End for i
    
    	} // End of try block
    
    	catch (bad_alloc& xa) { // Catch block, for exceptions
    
             in.close();
             out.close();
             cerr << "\nIn catch block, so an exception occurred: " << xa.what() << "\n";
             cout << "\nEnter any key to continue. \n";
             cin >> rflag;
             return 0;
    
    	} // End of catch block
    
    	for (i = 0; i < mDim; i++){ //Input the A Matrix from the file
             for (j = 0; j < nDim; j++){
               in >> A[i][j];
             }//End for j
    	}//End for i
    
    	for (i = 0; i < nDim; i++){ //Input the B Matrix from the file
             for (j = 0; j < pDim; j++){
              in >> B[i][j];
             }//End for j
    	}//End for i
    
    	in.close(); //Close the input file
    
    	Matrix_Mult(&erFlag, mDim, nDim, pDim, A, B, C);
    
    	if (erFlag){
    	  cout << "Inconsistent data sent to Matrix_Mult routine. Matrix multiplication NOT performed. Check data before running again.\n";
    	}
    	else {
    
    	 out.precision(DBL_DIG);
    
    	 out << "\nThe A matrix follows:\n";
    	 out << "\n";
    	 for (i = 0; i < mDim; i++){
    	  for (j = 0; j < nDim; j++){
    		out << A[i][j] << " ";
    	  } // End for j
    	  out << "\n";
    	 }//End for i
    
    	 out << "\nThe B matrix follows:\n";
    	 out << "\n";
    	 for (i = 0; i < nDim; i++){
    	  for (j = 0; j < pDim; j++){
    		out << B[i][j] << " ";
    	  } // End for j
    	  out << "\n";
    	}//End for i
    
    	 out << "\nThe product matrix, C, follows:\n";
    	 out << "\n";
    	 for (i = 0; i < mDim; i++){
    	  for (j = 0; j < pDim; j++){
    	   out << C[i][j] << " ";
    	  } // End for j
    	  out << "\n";
    	 }//End for i
    
    	 cout << "\nDone! The solution is in the text file mulmatout.txt \n";
    	} // End else !erFlag
    	out.close();
     } //End if rflag = 'Y'
     else cout << "\nNot ready. Try again when ready with information. \n";
     cout << "\nEnter any key to continue. \n";
     cin >> rflag;
     return 0;
     } // End main program.
KaeLL 0 Newbie Poster

I'm waiting for someone write the matrix multiplication algotithm using C++11 std::future's! But Good Snippet, though! :D (y)

DavidB 44 Junior Poster

Any other feedback?

In particular, I am curious to know if there is a better way to keep the console open. Presently, I keep the console open by waiting for input of a character (lines 192 and 193). "rflag" is already declared, so it is not like I am creating a brand-new variable solely for this purpose.

I tried replacing lines 192 and 193 by the following two lines:

cout << "\nPress Enter to continue. \n";
cin.ignore(numeric_limits<streamsize>::max(), '\n');

Had expected to avoid accepting a character. Doesn't cin.ignore just wait for the "Enter" key? The program no longer waits for a character input; in fact, it doesn't wait at all. The console closes so fast I can't see what error messages or comments may have been output.

I had to add TWO lines of cin.ignore:

cout << "\nPress Enter to continue. \n";
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin.ignore(numeric_limits<streamsize>::max(), '\n');

Now the console stays open until the "Enter" key is pressed, and whether or not gibberish is typed in beforehand. Does this mean there were two newline characters in the buffer waiting to be cleared out?

In any case, I am not sure if doing it this way makes the program better.

Any thoughts? Is the original program fine, or should I edit it to use cin.ignore?

Member Avatar for iamthwee
iamthwee

In regards to keeping the console open:

http://www.daniweb.com/software-development/cpp/threads/90228/flushing-the-input-stream

Discusses the issue in great detail. Most cases you can get away with numeric_limits like you've used.
If you can't then a foolproof way would be to accept everything as strings and convert to ints/floats where necessary. I prefer this as a much more robust solution and reduces having to know/remember all the intricacies stated in the above link.

As to the actual code for matrix multiplication I'll look over it at some point. Maybe for improvement look into implementing the adjoint, finding the determinant etc and other useful matrix ops relevant for systems engineering problems and mathematics.

Ta

_______________
!Edit

As a comment/feedback it would be nice if you provided sample example of the input file.

Shellback3 0 Newbie Poster

My mind set would establish a format for the imput files with the data either separated by commas or white space (spaces and tabs) so that the user need not specifiy the sizes as they could be determined progrmatically. I realize that this may be outside the scope of what you are attempting to demonstrate but having a library of functions like this is quite usefull.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.