Matrix multiplication operator

I'm writing a program just to show that I can use operators in matrices. I've done it for addition and subtraction but I'm struggling to apply operator * to multiply two 3x3 matrices. Any help would be appreciated, thank you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372


// PHYS 30762 Programming in C++
// Assignment 6

// A matrix class - skeleton code

// You are advised to write your own code from scratch but
// you may use this code if you do not know how to get started.

// Note: for longer functions, you are advised to prototype them
// within class and put the function code itself immediately below class. 

#include<iostream>
using namespace std;

class Matrix
	{
		// Friends
		friend ostream & operator<<(ostream &os, const Matrix &mat);
	private:
		double *MatrixData;
		int Rows,Columns;
	public:
		// Default constructor
		Matrix(){MatrixData=0; Rows=Columns=0;}
		// Parameterized constructor
		Matrix(int MatrixRow, int MatrixColumn)
		{
			Rows=MatrixRow;
			Columns=MatrixColumn;
			int Size=MatrixRow*MatrixColumn;
			MatrixData=new double[Size];
			for(int i=0; i<Size; i++)
			{
				MatrixData[i]=0;
			}
		}
		
		// Copy constructor
		Matrix::Matrix(const Matrix &MatrixGroup)
		{
			MatrixData=0;
			Rows=MatrixGroup.GetRows();
			Columns=MatrixGroup.GetColumns();
			
			int Size=MatrixGroup.GetRows()*MatrixGroup.GetColumns();
			if(Size>0)
			{
				MatrixData=new double[Size];
				for(int i=0; i<Size; i++)
				{
					MatrixData[i]=MatrixGroup.MatrixData[i];
				}
			}
			
		}
		
		Matrix & Matrix::operator=(const Matrix &MatrixGroup)
		{
			if(&MatrixGroup==this) return *this;
			
			delete[] MatrixData;
			MatrixData=0;
			int Size=0; 
			Size=MatrixGroup.GetRows()*MatrixGroup.GetColumns();
			
			if(Size>0)
			{
				MatrixData=new double[Size];
				for(int i=0; i<Size; i++)
				{MatrixData[i]=MatrixGroup.MatrixData[i];}
			}
			else{cout<<"Error: Out of Range"<<endl; exit(1);}
			
			return *this;
		}
		
		// Destructor
		~Matrix(){delete[] MatrixData;}
		
		// Access functions
		int GetRows() const {return Rows;} // Return number of rows
		int GetColumns() const {return Columns;} // Return number of columns
		int SetRowsColumns(int a, int b) const {a=Rows; b=Columns; return 0;}
		int Index(int m, int n) const // Return position in array of element (m,n)
		{
			if(m>0 && m<=Rows && n>0 && n<=Columns) 
			{
				return (n-1)+(m-1)*Columns;
			}
			else {cout<<"Error: out of range"<<endl; exit(1);}
		}
		double & operator()(int m, int n) {return MatrixData[Index(m,n)];}
		// Other access functions go here
		double SetMatrixData(int a, int b, double c)
		{
			MatrixData[Index(a,b)]=c;
			return 0;
		}
		
		double GetMatrixGroup(int a)
		{return MatrixData[a];}
		
		double GetMatrixData(int a, int b) const
		{return MatrixData[Index(a,b)];}
		
		// Other functions 
		// Assignment operator
		
		
		
		// Addition, subtraction and multiplication
		//Addition
		Matrix operator+(const Matrix &x)
		{
			if(Rows == x.GetRows() && Columns == x.GetColumns())
			{  
				int Size =x.GetRows()*x.GetColumns();
				Matrix Temp(x.GetRows(),x.GetColumns());
				for(int i=0; i<Size; i++)
				{
				Temp.MatrixData[i]=MatrixData[i]+x.MatrixData[i];
				}
				return Temp;
			}
			else 
			{
				cout<<"matrices not the same size"<<endl;
				exit (1);
			}
		}
		
		//Subtraction
		Matrix operator-(const Matrix &x)
		{ 
			if(Rows == x.GetRows() && Columns == x.GetColumns())
			{	  
				int Size =x.GetRows()*x.GetColumns();
				Matrix Temp(x.GetRows(), x.GetColumns());
				for(int i=0; i<Size; i++)
				{
					Temp.MatrixData[i]=MatrixData[i]-x.MatrixData[i];
				}
				return Temp;
			}
		else 
		{
			cout<<"matrices not the same size"<<endl;
			exit (1);
		}
		} 
		
		
		//========================================================================
		// multiplcation
		
		Matrix operator*(const Matrix &x)
		{ 
			if(Rows == x.GetColumns() && Columns==x.GetRows())
			{ 
				Matrix Temp1(Rows,x.GetColumns());
				
				for(int i=1;i<=Rows;i++)
				{	for(int j=1; j<=x.GetColumns();j++)
				{ for( int k=1; k<=x.Rows;k++)
				{
					
				Temp1.SetMatrixData(i,j,(MatrixData[Index(j,k)]+x.GetMatrixData(k,j)));
					
				}
				}
				}
				return Temp1;
			}
			
			else{cout<<"incorrect matrices dimensions"<<endl;
			exit (1);}
			
			return x;
		}
		
		
		
		//========================================================================

		
		
		
		
		// Transpose
		Matrix Transpose() const
		{
			//int Size=Columns*Rows;
			Matrix Temp(Columns,Rows);
			for (int i=1; i<=Temp.GetRows();i++)
			{
				for(int j=1; j<=Temp.GetColumns();j++)
				{
					Temp.SetMatrixData(i,j,MatrixData[Index(j,i)]);
				}
			}
			return Temp;
		}
		
		
		// Determinant (2x2 or 3x3)
		double Determinant()
		{
			if(Rows == Columns && Rows <=3 && Rows >=2)
			{
				if(Rows == 2)
				{ 
					double a=MatrixData[0]*MatrixData[3]-MatrixData[2]*MatrixData[1];
					return a;
				}
				else
				{ 
					double b=MatrixData[0]*MatrixData[4]*MatrixData[8]+MatrixData[1]*MatrixData[5]*MatrixData[6]+MatrixData[2]*MatrixData[3]*MatrixData[7]-MatrixData[2]*MatrixData[4]*MatrixData[6]-MatrixData[1]*MatrixData[3]*MatrixData[8]-MatrixData[0]*MatrixData[5]*MatrixData[7];
					return b;
				}
			}
			
			else {cout<<"matrices not the same size"<<endl; exit (1);
			}
		}
		
		
	};

// Member functions defined outside class



// Overload insertion to output stream for matrices
ostream & operator<<(ostream &os, const Matrix &Mat)
{
	// Code goes here
	//prints out matrix
	for(int i=1;i<=Mat.GetRows();i++)
	{
		cout<<"\n";
		for(int j=1;j<=Mat.GetColumns();j++)
		{
			os<<Mat.GetMatrixData(i,j)<<"\t";
		}
	}
	return os;
	}

// Main program

int main()
{
	
	//
	// First part of assignment: constructing and deep copying matrices
	//
	
	// Demonstrate default constructor
	Matrix a1();
	//cout<<"Matrix 1"<<a1<<"\n"<<endl;
	
	// Parameterized constructor
	const int m(2),n(2);
	
	Matrix a2(m,n);
	// Set values for a2
	a2.SetMatrixData(1,1,1);
	a2.SetMatrixData(1,2,1);
	a2.SetMatrixData(2,1,1);
	a2.SetMatrixData(2,2,1);
	cout<<"Define Matrix 2:"<<a2<<"\n"<<endl;	
	
	// Deep copy by assignment: define new matrix a3 then copy from a2 to a3
	Matrix a3(m,n);
	cout<<"Define Matrix 3:"<<a3<<"\n"<<endl;
	cout<<">>> Deep copy by assignment from Matrix 2 to Matrix 3."<<endl;
	a3=a2;
	cout<<"Matrix 3 becomes:"<<a3<<"\n"<<endl;
	
	// Modify contents of original matrix
//show assigned matrix isunchanged here
	a2.SetMatrixData(1,1,3);
	a2.SetMatrixData(1,2,4);
	a2.SetMatrixData(2,1,1);
	a2.SetMatrixData(2,2,5);
	cout<<">>> Modify contents of Matrix 2."<<endl;
	cout<<"Matrix 2 becomes:"<<a2<<"\n"<<endl;
	cout<<"Matrix 3 remains unchanged:"<<a3<<"\n"<<endl;
	
	// Deep copy using copy constructor 
	Matrix a4(a2);
	cout<<">>> Deep copy using constructor from Matrix 2 to Matrix 4."<<endl;
	cout<<"Matrix 4 becomes:"<<a4<<"\n"<<endl;
	
	// Modify contents of original matrix and show copied matrix is unchanged here
	a2.SetMatrixData(1,1,9);
	a2.SetMatrixData(1,2,8);
	a2.SetMatrixData(2,1,9);
	a2.SetMatrixData(2,2,8);
	cout<<">>> Modify contents of Matrix 2."<<endl;
	cout<<"Matrix 2 becomes:"<<a2<<"\n"<<endl;
	
	cout<<"Matrix 4 remians unchanged:"<<a4<<"\n"<<endl;

	a2=a2;
	cout<<">>> Self assign Matrix 2."<<endl;
	cout<<"Matrix 2 becomes:"<<a2<<"\n"<<endl;
	
	//
	// Second part of assignment: matrix operations
	//
	
	// Addition of 2 matrices
	Matrix b1(m,n);
	b1=a2+a4;
	cout<<">>> Add Matrix 2 and Matrix 4."<<endl;
	cout<<b1<<"\n"<<endl;
	
	// Subtraction of 2 matrices
	Matrix b2(m,n);
	b2=a4-a2;
	cout<<">>> Subtract Matrix 2 from Matrix 4."<<endl;
	cout<<b2<<"\n"<<endl;
	
	
	// Multiplication of 2 matrices
	Matrix a5(3,3);
	a5.SetMatrixData(1,1,1);
	a5.SetMatrixData(1,2,2);
	a5.SetMatrixData(1,3,3);
	a5.SetMatrixData(2,1,4);
	a5.SetMatrixData(2,2,5);
	a5.SetMatrixData(2,3,6);
	a5.SetMatrixData(3,1,2);
	a5.SetMatrixData(3,2,6);
	a5.SetMatrixData(3,3,3);

	cout<<"Define Matrix 5."<<endl;
	cout<<a5<<endl;
	
	Matrix a6(3,3);
	a6.SetMatrixData(1,1,1);
	a6.SetMatrixData(1,2,2);
	a6.SetMatrixData(1,3,3);
	a6.SetMatrixData(2,1,4);
	a6.SetMatrixData(2,2,5);
	a6.SetMatrixData(2,3,6);
	a6.SetMatrixData(3,1,1);
	a6.SetMatrixData(3,2,2);
	a6.SetMatrixData(3,3,3);
	
	cout<<"Define Matrix 6:"<<endl;
	cout<<a6<<endl;
	
	cout<<">>> Multiply Matrix 5 and Matrix 6."<<endl;
	cout<<a5*a6<<endl;
	
	// Transpose
	cout<<">>> Transpose Matrix 6.\n"<<endl;
	cout<<a6.Transpose()<<"\n"<<endl;
	
	// Determinant 
	cout<<"Find determinant of Matrix 4:"<<endl;
	cout<<a4.Determinant()<<"\n"<<endl;

	
	return 0;
}

The errors lie line 169 :
- you need to take line "i" of the left matrix, not "j"
- you're supposed to multiply the values, not add them
- the results should be accumulated, but SetMatrixData only stores the newest one.

To improve readability, you should define a 2nd Matrix::operator():
double operator()(int m, int n) const {return MatrixData[Index(m,n)];}

Using it and the fact that your constructor initializes the matrix elements to 0, this line could be rewritten Temp1(i,j) += (*this)(i,k) * x(k,j);
The error that toum pointed out is a good reason to use names something like Row & Col not i & j. As you have found out these errors are hard to see.

I have seen this lots of times before - do a find replace and the error is much easier to see. It is good to use meaningful names.

You seem to have some of these:

for(int i=1;i<=Rows;i++)

Although you make adjustments in your functions, IMO it might be better if you always worked from 0

for(int i=0;i < Rows;i++)

This way you don't have to adjust any subscripts, and avoid the possibility of overstepping the array.

You have all your code in 1 file - it is much better practice to put the class declaration in a header file, with the functions definitions in a .cpp file. If you are using an IDE, is there a class wizard which creates the files and can create functions stubs from declarations? My IDE (KDevelop on Linux) does that, I am not sure if yours does.

Hope all goes well.
Topic archived. No new replies allowed.