1 //
2 // MyMatrix.h
3 // pb_solvers_code
4 //
5 /*
6 Copyright (c) 2015, Teresa Head-Gordon, Lisa Felberg, Enghui Yap, David Brookes
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 * Neither the name of UC Berkeley nor the
17 names of its contributors may be used to endorse or promote products
18 derived from this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef MyMatrix_h
33 #define MyMatrix_h
34
35 #include <stdio.h>
36 #include <vector>
37 #include <sstream>
38
39 using namespace std;
40
41
42 class MatrixAccessException: public exception
43 {
44 protected:
45 int i_, j_;
46 int nrows_, ncols_;
47
48 public:
MatrixAccessException(const int i,const int j,const int nrows,const int ncols)49 MatrixAccessException(const int i, const int j,
50 const int nrows, const int ncols)
51 :i_(i), j_(j), nrows_(nrows), ncols_(ncols)
52 {
53 }
54
what()55 virtual const char* what() const throw()
56 {
57 ostringstream ss;
58 ss << "Cannot access point [" << i_ << "," << j_ <<
59 "] in matrix of size (" << nrows_ << "," << ncols_ << ")" << endl;
60 return ss.str().c_str();
61 }
62 };
63
64
65 enum ArithmeticType { ADDITION, MULTIPLICATION, INNER_PRODUCT };
66
67
68 class MatrixArithmeticException: public exception
69 {
70 protected:
71 int nrows1_, ncols1_;
72 int nrows2_, ncols2_;
73 ArithmeticType type_;
74
75 public:
76
MatrixArithmeticException(ArithmeticType type,const int nrows1,const int ncols1,const int nrows2,const int ncols2)77 MatrixArithmeticException(ArithmeticType type, const int nrows1,
78 const int ncols1, const int nrows2,
79 const int ncols2)
80 :nrows1_(nrows1), ncols1_(ncols1), nrows2_(nrows2),
81 ncols2_(ncols2), type_(type)
82 {
83 }
84
what()85 virtual const char* what() const throw()
86 {
87 ostringstream ss;
88 string start;
89 if (type_ == ADDITION) start = "Cannot add matrices of sizes (";
90 else if (type_ == MULTIPLICATION)
91 start = "Cannot multiply matrices of size (";
92 else if (type_ == INNER_PRODUCT)
93 start = "Cannot find inner product of vectors of sizes (";
94 else start = "Unknown arithmetic error with matrices of sizes (";
95 ss << start << nrows1_ << "," << ncols1_ << ") and (" <<
96 nrows2_ << "," << ncols2_ << ")" << endl;
97 return ss.str().c_str();
98 }
99
100 };
101
102
103 template <typename T>
104 class MyMatrix
105 {
106 protected:
107 int nrows_;
108 int ncols_;
109 vector< vector<T> > vals_; //Len of 1st vector is # of rows,
110 // length of second is ncols
111 public:
112
113 /*
114 Initialize an empty matrix (call default constructors of T)
115 Default is 1 x 1 matrix
116 */
117 MyMatrix(const int nrows=1, const int ncols=1)
nrows_(nrows)118 : nrows_(nrows), ncols_(ncols), vals_ (nrows, vector<T>(ncols))
119 {
120 }
121
MyMatrix(vector<vector<T>> vals)122 MyMatrix(vector< vector<T> > vals)
123 : vals_(vals), nrows_( (int) vals.size()), ncols_( (int) vals[0].size())
124 {
125 }
126
MyMatrix(const int nrows,const int ncols,T * val)127 MyMatrix(const int nrows, const int ncols, T * val)
128 :nrows_(nrows), ncols_(ncols), vals_(nrows, vector<T> (ncols))
129 {
130 int i, j, ct(0);
131 for (i = 0; i < nrows; i++)
132 for (j = 0; j < ncols; j++)
133 {
134 vals_[i][j] = val[ct];
135 ct++;
136 }
137 }
138 /*
139 Fill with a default value (good for initializing memory)
140 */
MyMatrix(const int nrows,const int ncols,T default_val)141 MyMatrix(const int nrows, const int ncols, T default_val)
142 :nrows_(nrows), ncols_(ncols), vals_(nrows, vector<T> (ncols, default_val))
143 {
144 int i, j;
145 for (i = 0; i < nrows; i++)
146 {
147 for (j = 0; j < ncols; j++)
148 {
149 vals_[i][j] = default_val;
150 }
151 }
152 }
153
154 /*
155 Set the value of a coordinate in this matrix given the position (i, j)
156 */
set_val(const int i,const int j,T val)157 void set_val(const int i, const int j, T val)
158 {
159 vals_[i][j] = val;
160 }
161
162 /*
163 Element access operator given position (i, j)
164 */
operator()165 T& operator()(const int i, const int j)
166 {
167 if (i < 0 || j < 0 || i > nrows_ || j > ncols_)
168 {
169 throw MatrixAccessException(i, j, nrows_, ncols_);
170 }
171 else
172 {
173 return vals_[i][j];
174 }
175 }
176
177 /*
178 Addition operator returns new matrix
179 */
180 MyMatrix<T> operator+(MyMatrix<T>& rhs)
181 {
182 if (ncols_ != rhs.ncols_ || nrows_ != rhs.nrows_)
183 {
184 throw MatrixArithmeticException(ADDITION, nrows_, ncols_, rhs.nrows_,
185 rhs.ncols_);
186 }
187
188 MyMatrix<T> result = MyMatrix<T>(nrows_, ncols_);
189 int i, j;
190 for (i = 0; i < nrows_; i++)
191 {
192 for (j= 0; j < ncols_; j++)
193 {
194 result.set_val(i, j, vals_[i][j] + rhs(i, j));
195 }
196 }
197 return result;
198 }
199
200 /*
201 summation operator adds to existing matrix
202 */
203 MyMatrix<T>& operator+=(MyMatrix<T>& rhs)
204 {
205 if (ncols_ != rhs.ncols_ || nrows_ != rhs.nrows_)
206 {
207 throw MatrixArithmeticException(ADDITION, nrows_, ncols_, rhs.nrows_,
208 rhs.ncols_);
209 }
210 int i, j;
211 for (i = 0; i < nrows_; i++)
212 {
213 for (j= 0; j < ncols_; j++)
214 {
215 set_val(i, j, vals_[i][j] + rhs(i, j));
216 }
217 }
218 return *this;
219 }
220
221 /*
222 Compute Forbenius inner product of two matrices
223 */
inner(MyMatrix<T> & rhs)224 T inner(MyMatrix<T>& rhs)
225 {
226 if (ncols_ != rhs.ncols_ || nrows_ != rhs.nrows_)
227 {
228 throw MatrixArithmeticException(INNER_PRODUCT, nrows_,
229 ncols_, rhs.nrows_, rhs.ncols_);
230 }
231
232 T result = T();
233
234 for (int i = 0; i < nrows_; i++)
235 {
236 for (int j = 0; j < ncols_; j++)
237 {
238 result += vals_[i][j] * rhs(i, j);
239 }
240 }
241 return result;
242 }
243
244 /*
245 Matrix multiplication. If this is size n x m, then rhs must be size m x p
246 */
247 MyMatrix<T> operator*(MyMatrix<T>& rhs)
248 {
249 if (ncols_ != rhs.nrows_)
250 {
251 throw MatrixArithmeticException(MULTIPLICATION, nrows_,
252 ncols_, rhs.nrows_, rhs.ncols_);
253 }
254
255 int n, m, p;
256 n = nrows_;
257 m = ncols_;
258 p = rhs.ncols_;
259
260 MyMatrix<T> result = MyMatrix<T>(n, p);
261 int i, j, k;
262 T inner_sum;
263 for (i = 0; i < n; i++)
264 {
265 for (j= 0; j < p; j++)
266 {
267 inner_sum = T(); // default constructor should be equivalent to zero
268 for (k = 0; k < m; k++)
269 {
270 inner_sum += vals_[i][k] * rhs(k, j);
271 }
272 result.set_val(i, j, inner_sum);
273 }
274 }
275 return result;
276 }
277
get_nrows()278 const int get_nrows() { return nrows_; }
get_ncols()279 const int get_ncols() { return ncols_; }
280
281 };
282
283
284 /*
285 Vector class is implemented as extension of matrix class but
286 with only one column
287 */
288 template<typename T>
289 class MyVector : MyMatrix<T>
290 {
291 public:
292
293 /*
294 Initialize empty vector given the size
295 */
296 MyVector(const int size=1)
297 :MyMatrix<T>(size, 1)
298 {
299 }
300
MyVector(T * vals,int size)301 MyVector(T * vals, int size)
302 :MyMatrix<T>(size, 1)
303 {
304 int i;
305 for (i = 0; i < size; i++)
306 {
307 this->vals_[i][0] = vals[i];
308 }
309 }
310
MyVector(vector<T> vals)311 MyVector(vector<T> vals)
312 :MyMatrix<T>((int) vals.size(), 1)
313 {
314 int i;
315 for (i = 0; i < vals.size(); i++)
316 {
317 this->vals_[i][0] = vals[0];
318 }
319 }
320
MyVector(const int size,T default_val)321 MyVector(const int size, T default_val)
322 :MyMatrix<T>(size, 1)
323 {
324 int i;
325 for (i = 0; i < size; i++)
326 {
327 this->vals_[i][0] = default_val;
328 }
329 }
330
set_val(const int i,T val)331 void set_val(const int i, T val)
332 {
333 MyMatrix<T>::set_val(i, 0, val);
334 }
335
336 /*
337 Addition operator returns new vector
338 */
339 MyVector<T> operator+(MyVector<T>& rhs)
340 {
341 if (this->nrows_ != rhs.nrows_)
342 {
343 throw MatrixArithmeticException(ADDITION, this->nrows_, 1,
344 rhs.nrows_, 1);
345 }
346
347 MyVector<T> result = MyVector<T>(this->nrows_);
348 int i;
349 for (i = 0; i < this->nrows_; i++)
350 {
351 result.set_val(i, this->vals_[i][0] + rhs[i]);
352 }
353 return result;
354 }
355
356 /*
357 summation operator adds to existing vector
358 */
359 MyVector<T>& operator+=(MyVector<T>& rhs)
360 {
361 if (this->nrows_ != rhs.nrows_)
362 {
363 throw MatrixArithmeticException(ADDITION, this->nrows_, 1, rhs.nrows_,
364 1);
365 }
366 int i;
367 for (i = 0; i < this->nrows_; i++)
368 {
369 set_val(i, this->vals_[i][0] + rhs[i]);
370 }
371 return *this;
372 }
373
374 // scalar multiplication
375 MyVector<T> operator*(T scal)
376 {
377 MyVector vout (get_nrows());
378 for (int i = 0; i < get_nrows(); i++)
379 {
380 vout[i] = this->vals_[i][0] * scal;
381 }
382
383 return vout;
384 }
385
386 /*
387 Access operator with brackets only requires one value
388 */
389 T& operator[](int i)
390 {
391 return this->vals_[i][0];
392 }
393
394 /*
395 The multiplication operator now computes the inner product
396 */
mult(const MyVector<T> & rhs)397 MyVector<T> mult(const MyVector<T>& rhs)
398 {
399 if (rhs.nrows_ != this->nrows_)
400 {
401 throw MatrixArithmeticException(INNER_PRODUCT, this->nrows_,
402 this->ncols_, rhs.nrows_, rhs.ncols_);
403 }
404 MyVector<T> out = MyVector<T>(this->nrows_);
405 int i;
406 for(i = 0; i < this->nrows_; i++)
407 {
408 out.set_val(i, this->operator[](i) * rhs.vals_[i][0]);
409 }
410 return out;
411 }
412
get_nrows()413 const int get_nrows() { return this->nrows_; }
get_ncols()414 const int get_ncols() { return this->ncols_; }
415 };
416
417 /*
418 Convenience classes for matrices of matrices, vectors of vectors
419 and vectors of matrices.
420
421 These are used by calling the name of the class and then ::type
422 to retrieve the typedef that they contain.
423
424 So to get a matrix of matrices containing ints you would write:
425
426 MatofMats<int>::type my_mat;
427
428 */
429 template <typename T>
430 struct MatOfMats
431 {
432 typedef MyMatrix<MyMatrix<T> > type;
433 };
434
435 template <typename T>
436 struct VecOfVecs
437 {
438 typedef MyVector<MyVector<T> > type;
439 };
440
441 template <typename T>
442 struct VecOfMats
443 {
444 typedef MyVector<MyMatrix<T> > type;
445 };
446
447 #endif /* MyMatrix_h */
448