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