1 #ifndef DENSEMATRIX_H
2 #define DENSEMATRIX_H
3 
4 #include "Matrix.h"
5 
6 #include <iostream>
7 
8 namespace ATC_matrix {
9 
10   /**
11    *  @class  DenseMatrix
12    *  @brief  Class for storing data in a "dense" matrix form
13    */
14 
15 template <typename T>
16 class DenseMatrix : public Matrix<T>
17 {
18 public:
19   DenseMatrix(INDEX rows=0, INDEX cols=0, bool z=1) { _create(rows, cols, z); }
DenseMatrix(const DenseMatrix<T> & c)20   DenseMatrix(const DenseMatrix<T>& c) : _data(NULL){ _copy(c); }
DenseMatrix(const SparseMatrix<T> & c)21   DenseMatrix(const SparseMatrix<T>& c): _data(NULL){ c.dense_copy(*this);}
DenseMatrix(const Matrix<T> & c)22   DenseMatrix(const Matrix<T>& c)      : _data(NULL){ _copy(c); }
23 //  const SparseMatrix<T> * p = sparse_cast(&c);
24 //  (p) ? p->dense_copy(*this) : _copy(c); }
~DenseMatrix()25   ~DenseMatrix()                                    { _delete();}
26 
27   void reset (INDEX rows, INDEX cols, bool zero=true);
28   void resize(INDEX rows, INDEX cols, bool copy=false);
29   void copy (const T * ptr, INDEX rows, INDEX cols);
30   /** returns transpose(this) * B */
31   DenseMatrix<T> transMat(const DenseMatrix<T>& B) const;
32   /** returns by element multiply A_ij = this_ij * B_ij */
33   DenseMatrix<T> mult_by_element(const DenseMatrix<T>& B) const;
34   /** returns by element multiply A_ij = this_ij / B_ij */
35   DenseMatrix<T> div_by_element(const DenseMatrix<T>& B) const;
36 
37   /** overloaded virtual functions */
38   //T& operator()(INDEX i, INDEX j)       { MICK(i,j) return DATA(i,j); }
operator()39   T& operator()(INDEX i, INDEX j)       { MICK(i,j) return DATA(i,j); }
operator()40   T  operator()(INDEX i, INDEX j) const { MICK(i,j) return DATA(i,j); }
41   T  operator[](INDEX i)          const { VICK(i) return _data[i]; }
42   T& operator[](INDEX i)                { VICK(i) return _data[i]; }
nRows()43   INDEX nRows()                   const { return _nRows; }
nCols()44   INDEX nCols()                   const { return _nCols; }
ptr()45   T * ptr()                   const { return _data;  }
46   void write_restart(FILE *f)     const;
47   void from_file(std::string & name);
48   void set_all_elements_to(const T &v);
49   DiagonalMatrix<T> diag()    const;
50 
51   DenseMatrix<T>& operator=(const T &v);
52   DenseMatrix<T>& operator=(const Matrix<T> &c);
53   DenseMatrix<T>& operator=(const DenseMatrix<T> &c);
54   DenseMatrix<T>& operator=(const SparseMatrix<T> &c);
55 
56   //* checks if all values are within the prescribed range
57   virtual bool check_range(T min, T max) const;
58 
59 protected:
60   void _delete();
61   void _create(INDEX rows, INDEX cols, bool zero=false);
62   void _copy(const Matrix<T> &c);
63 
64   T *_data;
65   INDEX _nRows, _nCols;
66 };
67 
68 //! Computes the cofactor matrix of A.
69 template<typename T>
70 DenseMatrix<T> adjugate(const Matrix<T> &A, bool symmetric=false);
71 
72 //! Returns a the tensor product of two vectors
73 template<typename T>
74 DenseMatrix<T> tensor_product(const Vector<T> &a, const Vector<T> &b);
75 
76 //----------------------------------------------------------------------------
77 // Returns an identity matrix, defaults to 3x3.
78 //----------------------------------------------------------------------------
79 template<typename T>
80 DenseMatrix<T> eye(INDEX rows=3, INDEX cols=3)
81 {
82   const double dij[] = {0.0, 1.0};
83   DENS_MAT I(rows, cols, false);  // do not need to pre-zero
84   for (INDEX j=0; j<cols; j++)
85     for (INDEX i=0; i<rows; i++)
86       I(i,j) = dij[i==j];
87   return I;
88 }
89 //----------------------------------------------------------------------------
90 // resizes the matrix and optionally zeros it out (default - zero)
91 //----------------------------------------------------------------------------
92 template <typename T>
reset(INDEX rows,INDEX cols,bool zero)93 void DenseMatrix<T>::reset(INDEX rows, INDEX cols, bool zero)
94 {
95   if (!this->is_size(rows, cols))
96   {
97      _delete();
98      _create(rows, cols);
99   }
100   if (zero) this->zero();
101 }
102 //----------------------------------------------------------------------------
103 // resizes the matrix and optionally copies over what still fits
104 //----------------------------------------------------------------------------
105 template <typename T>
resize(INDEX rows,INDEX cols,bool copy)106 void DenseMatrix<T>::resize(INDEX rows, INDEX cols, bool copy)
107 {
108   if (this->is_size(rows, cols)) return;  // if is correct size, done
109   if (!copy)
110   {
111      _delete();
112      _create(rows, cols);
113      return;
114   }
115   DenseMatrix<T> temp(*this);
116   _delete();
117   _create(rows, cols);
118   int szi = this->nRows();
119   int szj = this->nCols();
120   for (INDEX i = 0; i < szi; i++)
121     for (INDEX j = 0; j < szj; j++)
122       (*this)(i,j) = temp.in_range(i,j) ? temp(i,j) : T(0);
123 }
124 //----------------------------------------------------------------------------
125 // resizes the matrix and copies data
126 //----------------------------------------------------------------------------
127 template <typename T>
copy(const T * ptr,INDEX rows,INDEX cols)128 void DenseMatrix<T>::copy(const T * ptr, INDEX rows, INDEX cols)
129 {
130   resize(rows, cols, false);
131   memcpy(_data, ptr, this->size()*sizeof(T));
132 }
133 //----------------------------------------------------------------------------
134 // returns transpose(this) * B
135 //----------------------------------------------------------------------------
136 template <typename T>
transMat(const DenseMatrix<T> & B)137 DenseMatrix<T> DenseMatrix<T>::transMat(const DenseMatrix<T>& B)          const
138 {
139   DenseMatrix C;
140   MultAB(*this, B, C, true);
141   return C;
142 }
143 //----------------------------------------------------------------------------
144 // returns this_ij * B_ij
145 //----------------------------------------------------------------------------
146 template <typename T>
mult_by_element(const DenseMatrix<T> & B)147 DenseMatrix<T> DenseMatrix<T>::mult_by_element(const DenseMatrix<T>& B)   const
148 {
149   DenseMatrix C;
150   C.reset(_nRows,_nCols);
151   if (B.nCols() == _nCols) {
152     int szi = this->nRows();
153     int szj = this->nCols();
154     for (INDEX i = 0; i < szi; i++)
155       for (INDEX j = 0; j < szj; j++)
156         C(i,j) = (*this)(i,j)*B(i,j);
157   }
158   else if (B.nCols() == 1) {
159     std::cout << "MULTIPLYING\n";
160     int szi = this->nRows();
161     int szj = this->nCols();
162     for (INDEX i = 0; i < szi; i++)
163       for (INDEX j = 0; j < szj; j++)
164         C(i,j) = (*this)(i,j)*B(i,0);
165   }
166   else {
167     SSCK(B, *this, "DenseMatrix::mult_by_element");
168   }
169   return C;
170 }
171 //----------------------------------------------------------------------------
172 // returns this_ij / B_ij
173 //----------------------------------------------------------------------------
174 template <typename T>
div_by_element(const DenseMatrix<T> & B)175 DenseMatrix<T> DenseMatrix<T>::div_by_element(const DenseMatrix<T>& B)   const
176 {
177   DenseMatrix C;
178   C.reset(_nRows,_nCols);
179 
180   if (B.nCols() == _nCols) {
181     int szi = this->nRows();
182     int szj = this->nCols();
183     for (INDEX i = 0; i < szi; i++)
184       for (INDEX j = 0; j < szj; j++)
185         C(i,j) = (*this)(i,j)/B(i,j);
186   }
187   else if (B.nCols() == 1) {
188     int szi = this->nRows();
189     int szj = this->nCols();
190     for (INDEX i = 0; i < szi; i++)
191       for (INDEX j = 0; j < szj; j++)
192         C(i,j) = (*this)(i,j)/B(i,0);
193   }
194   else {
195     SSCK(B, *this, "DenseMatrix::div_by_element");
196   }
197   return C;
198 }
199 //----------------------------------------------------------------------------
200 // writes the matrix data to a file
201 //----------------------------------------------------------------------------
202 template <typename T>
write_restart(FILE * f)203 void DenseMatrix<T>::write_restart(FILE *f)                               const
204 {
205   fwrite(&_nRows, sizeof(INDEX),1,f);
206   fwrite(&_nCols, sizeof(INDEX),1,f);
207   if (this->size()) fwrite(_data, sizeof(T), this->size(), f);
208 }
209 //----------------------------------------------------------------------------
210 // reads matrix from text file (matrix needs to be sized)
211 //----------------------------------------------------------------------------
212 template <typename T>
from_file(std::string & name)213 void DenseMatrix<T>::from_file(std::string & name)
214 {
215   GCHK(_nRows == 0,"from_file needs nRows > 0");
216   GCHK(_nCols == 0,"from_file needs nCols > 0");
217   std::ifstream in(name.c_str(),std::ifstream::in);
218   const int lineSize = 256;
219   char line[lineSize];
220   if (! in.good()) gerror(name+" is not available");
221   in.getline(line,lineSize); // header
222   int szi = this->nRows();
223   int szj = this->nCols();
224   for (INDEX i = 0; i < szi; i++)
225     for (INDEX j = 0; j < szj; j++)
226       in >> (*this)(i,j);
227 }
228 //----------------------------------------------------------------------------
229 // sets all elements to a value (optimized)
230 //----------------------------------------------------------------------------
231 template <typename T>
set_all_elements_to(const T & v)232 inline void DenseMatrix<T>::set_all_elements_to(const T &v)
233 {
234   int sz = this->size();
235   for (INDEX i = 0; i < sz; i++) _data[i] = v;
236 }
237 //-----------------------------------------------------------------------------
238 // Return a diagonal matrix containing the diagonal entries of this matrix
239 //-----------------------------------------------------------------------------
240 template<typename T>
diag()241 DiagonalMatrix<T> DenseMatrix<T>::diag() const
242 {
243   DiagonalMatrix<T> D(nRows(), true); // initialized to zero
244   INDEX i;
245   for (i=0; i<nRows(); i++)
246   {
247     D(i,i) = DATA(i,i);
248   }
249   return D;
250 }
251 //----------------------------------------------------------------------------
252 // clears allocated memory
253 //----------------------------------------------------------------------------
254 template <typename T>
_delete()255 void DenseMatrix<T>::_delete()
256 {
257   _nRows = _nCols = 0;
258   if (_data){
259     delete [] _data;
260   }
261 }
262 //----------------------------------------------------------------------------
263 // allocates memory for an rows by cols DenseMatrix
264 //----------------------------------------------------------------------------
265 template <typename T>
_create(INDEX rows,INDEX cols,bool zero)266 void DenseMatrix<T>::_create(INDEX rows, INDEX cols, bool zero)
267 {
268 
269   _nRows=rows;
270   _nCols=cols;
271   _data = (this->size() ? new T [_nCols*_nRows] : NULL);
272   if (zero) this->zero();
273 }
274 //----------------------------------------------------------------------------
275 // creates a deep memory copy from a general matrix
276 //----------------------------------------------------------------------------
277 template <typename T>
_copy(const Matrix<T> & c)278 void DenseMatrix<T>::_copy(const Matrix<T> &c)
279 {
280   if (!_data || this->size()!=c.size())
281   {
282     _delete();
283     _create(c.nRows(), c.nCols());
284   }
285   else
286   {
287     _nRows = c.nRows();
288     _nCols = c.nCols();
289   }
290   memcpy(_data, c.ptr(), c.size()*sizeof(T));
291 }
292 //----------------------------------------------------------------------------
293 // sets all elements to a constant
294 //----------------------------------------------------------------------------
295 template <typename T>
296 DenseMatrix<T>& DenseMatrix<T>::operator=(const T &v)
297 {
298   this->set_all_elements_to(v);
299   return *this;
300 }
301 //----------------------------------------------------------------------------
302 // copys c with a deep copy
303 //----------------------------------------------------------------------------
304 template <typename T>
305 DenseMatrix<T>& DenseMatrix<T>::operator=(const Matrix<T> &c)
306 {
307   _copy(c);
308   return *this;
309 }
310 //----------------------------------------------------------------------------
311 // copys c with a deep copy
312 //----------------------------------------------------------------------------
313 template <typename T>
314 DenseMatrix<T>& DenseMatrix<T>::operator=(const DenseMatrix<T> &c)
315 {
316   _copy(c);
317   return *this;
318 }
319 //-----------------------------------------------------------------------------
320 // copys c with a deep copy, including zeros
321 //-----------------------------------------------------------------------------
322 template <typename T>
323 DenseMatrix<T>& DenseMatrix<T>::operator=(const SparseMatrix<T> &c)
324 {
325   _delete();
326   _create(c.nRows(), c.nCols(), true);
327   SparseMatrix<T>::compress(c);
328   for (INDEX i=0; i<c.size(); i++)
329   {
330     TRIPLET<T> x = c.triplet(i);
331     std::cout << "x.i: "<< x.i << "\nx.j: "<< x.j << "\nv.j: "<< x.v << std::endl << std::endl;
332     (*this)(x.i, x.j) =  x.v;
333   }
334   return *this;
335 }
336 
337 //* Returns the transpose of the cofactor matrix of A.
338 //* see http://en.wikipedia.org/wiki/Adjugate_matrix
339 //* symmetric flag only affects cases N>3
340 template<typename T>
adjugate(const Matrix<T> & A,bool symmetric)341 DenseMatrix<T> adjugate(const Matrix<T> &A, bool symmetric)
342 {
343   if (!A.is_square()) gerror("adjugate can only be computed for square matrices.");
344   DenseMatrix<T> C(A.nRows(), A.nRows());
345   switch (A.nRows()) {
346     case 1:
347       gerror("adjugate must be computed for matrixes of size greater than 1");
348     case 2:
349       C(0,0) = A(1,1);  C(0,1) =-A(0,1);
350       C(1,0) =-A(1,0);  C(1,1) = A(0,0);
351       break;
352     case 3:   // 3x3 case was tested vs matlab
353       C(0,0) = A(1,1)*A(2,2)-A(1,2)*A(2,1);
354       C(1,0) =-A(1,0)*A(2,2)+A(1,2)*A(2,0);   // i+j is odd (reverse sign)
355       C(2,0) = A(1,0)*A(2,1)-A(1,1)*A(2,0);
356       C(0,1) =-A(0,1)*A(2,2)+A(0,2)*A(2,1);   // i+j is odd
357       C(1,1) = A(0,0)*A(2,2)-A(0,2)*A(2,0);
358       C(2,1) =-A(0,0)*A(2,1)+A(0,1)*A(2,0);   // i+j is odd
359       C(0,2) = A(0,1)*A(1,2)-A(0,2)*A(1,1);
360       C(1,2) =-A(0,0)*A(1,2)+A(0,2)*A(1,0);   // i+j is odd
361       C(2,2) = A(0,0)*A(1,1)-A(0,1)*A(1,0);
362       break;
363     default:
364 
365       // this feature is neither tested nor optimal - use at your own risk!!!
366       DenseMatrix<T> m(A.nRows()-1, A.nRows()-1);
367       double sign[] = {1.0, -1.0};
368       for (INDEX j=0; j<A.nCols(); j++) {
369         for (INDEX i=0; i<A.nRows(); i++) {
370           for (INDEX mj=0; mj<m.nCols(); mj++) {
371             for (INDEX mi=0; mi<m.nRows(); mi++) {
372               m(mi, mj) = A(mi+(mi>=i), mj+(mj>=j));  // skip row i and col j
373             }
374           }
375           if (!symmetric) C(j,i)=det(m)*sign[(i+j)&1];
376           if (symmetric && i>=j) C(i,j)=C(j,i)=det(m)*sign[(i+j)&1];
377         }
378       }
379   }
380   return C;
381 }
382 
383 // Returns a the tensor product of two vectors
384 template<typename T>
tensor_product(const Vector<T> & a,const Vector<T> & b)385 DenseMatrix<T> tensor_product(const Vector<T> &a, const Vector<T> &b)
386 {
387   DenseMatrix<T> ab(a.size(), b.size(),false);
388   for (INDEX j=0; j<b.size(); j++)
389     for (INDEX i=0; i<a.size(); i++)
390       ab(i,j) = a[i]*b[j];
391   return ab;
392 }
393 
394 //* Returns a DenseMatrix with random values (like matlab rand(m,n)
395 template<typename T>
396 DenseMatrix<T> rand(INDEX rows, INDEX cols, int seed=1234)
397 {
398   srand(seed);
399   const double rand_max_inv = 1.0 / double(RAND_MAX);
400   DenseMatrix<T> R(rows, cols, false);
401   for (INDEX i=0; i<R.size(); i++) R[i]=double(::rand())*rand_max_inv;
402   return R;
403 }
404 
405 //-----------------------------------------------------------------------------
406 //* returns true if no value is outside of the range
407 template<typename T>
check_range(T min,T max)408 inline bool DenseMatrix<T>::check_range(T min, T max) const
409 {
410   for (INDEX i = 0; i < this->size(); i++)
411     if ( (_data[i] > max) || (_data[i] < min) ) return false;
412   return true;
413 }
414 
415 } // end namespace
416 #endif
417 
418