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