1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // QUESO - a library to support the Quantification of Uncertainty
5 // for Estimation, Simulation and Optimization
6 //
7 // Copyright (C) 2008-2017 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA  02110-1301  USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 #include <queso/GslMatrix.h>
26 #include <queso/GslVector.h>
27 #include <queso/Defines.h>
28 #include <queso/FilePtr.h>
29 #include <gsl/gsl_linalg.h>
30 #include <gsl/gsl_eigen.h>
31 #include <sys/time.h>
32 #include <cmath>
33 
34 namespace QUESO {
35 
GslMatrix(const BaseEnvironment & env,const Map & map,unsigned int nCols)36 GslMatrix::GslMatrix( // can be a rectangular matrix
37   const BaseEnvironment& env,
38   const Map&             map,
39   unsigned int                  nCols)
40   :
41   Matrix  (env,map),
42   m_mat          (gsl_matrix_calloc(map.NumGlobalElements(),nCols)),
43   m_LU           (NULL),
44   m_chol(),
45   m_inverse      (NULL),
46   m_svdColMap    (NULL),
47   m_svdUmat      (NULL),
48   m_svdSvec      (NULL),
49   m_svdVmat      (NULL),
50   m_svdVTmat     (NULL),
51   m_determinant  (-INFINITY),
52   m_lnDeterminant(-INFINITY),
53   m_permutation  (NULL),
54   m_signum       (0),
55   m_isSingular   (false)
56 {
57   queso_require_msg(m_mat, "null matrix generated");
58 }
59 
60 // Shaped constructor --------------------------------------------------
GslMatrix(const BaseEnvironment & env,const Map & map,double diagValue)61 GslMatrix::GslMatrix( // square matrix
62   const BaseEnvironment& env,
63   const Map&             map,
64   double                        diagValue)
65   :
66   Matrix  (env,map),
67   m_mat          (gsl_matrix_calloc(map.NumGlobalElements(),map.NumGlobalElements())),
68   m_LU           (NULL),
69   m_chol(),
70   m_inverse      (NULL),
71   m_svdColMap    (NULL),
72   m_svdUmat      (NULL),
73   m_svdSvec      (NULL),
74   m_svdVmat      (NULL),
75   m_svdVTmat     (NULL),
76   m_determinant  (-INFINITY),
77   m_lnDeterminant(-INFINITY),
78   m_permutation  (NULL),
79   m_signum       (0),
80   m_isSingular   (false)
81 {
82   queso_require_msg(m_mat, "null matrix generated");
83 
84   for (unsigned int i = 0; i < m_mat->size1; ++i) {
85     (*this)(i,i) = diagValue;
86   }
87 }
88 // Shaped constructor --------------------------------------------------
GslMatrix(const GslVector & v,double diagValue)89 GslMatrix::GslMatrix( // square matrix
90   const GslVector& v,
91   double                  diagValue)
92   :
93   Matrix  (v.env(),v.map()),
94   m_mat          (gsl_matrix_calloc(v.sizeLocal(),v.sizeLocal())),
95   m_LU           (NULL),
96   m_chol(),
97   m_inverse      (NULL),
98   m_svdColMap    (NULL),
99   m_svdUmat      (NULL),
100   m_svdSvec      (NULL),
101   m_svdVmat      (NULL),
102   m_svdVTmat     (NULL),
103   m_determinant  (-INFINITY),
104   m_lnDeterminant(-INFINITY),
105   m_permutation  (NULL),
106   m_signum       (0),
107   m_isSingular   (false)
108 {
109   queso_require_msg(m_mat, "null matrix generated");
110 
111   for (unsigned int i = 0; i < m_mat->size1; ++i) {
112     (*this)(i,i) = diagValue;
113   }
114 }
115 // Shaped constructor --------------------------------------------------
GslMatrix(const GslVector & v)116 GslMatrix::GslMatrix(const GslVector& v) // square matrix
117   :
118   Matrix  (v.env(),v.map()),
119   m_mat          (gsl_matrix_calloc(v.sizeLocal(),v.sizeLocal())),
120   m_LU           (NULL),
121   m_chol(),
122   m_inverse      (NULL),
123   m_svdColMap    (NULL),
124   m_svdUmat      (NULL),
125   m_svdSvec      (NULL),
126   m_svdVmat      (NULL),
127   m_svdVTmat     (NULL),
128   m_determinant  (-INFINITY),
129   m_lnDeterminant(-INFINITY),
130   m_permutation  (NULL),
131   m_signum       (0),
132   m_isSingular   (false)
133 {
134   queso_require_msg(m_mat, "null matrix generated");
135 
136   unsigned int dim = v.sizeLocal();
137   for (unsigned int i = 0; i < dim; ++i) {
138     (*this)(i,i) = v[i];
139   }
140 }
141 
142 // Shaped constructor --------------------------------------------------
GslMatrix(const GslMatrix & B)143 GslMatrix::GslMatrix(const GslMatrix& B) // can be a rectangular matrix
144   :
145   Matrix  (B.env(),B.map()),
146   m_mat          (gsl_matrix_calloc(B.numRowsLocal(),B.numCols())),
147   m_LU           (NULL),
148   m_chol(),
149   m_inverse      (NULL),
150   m_svdColMap    (NULL),
151   m_svdUmat      (NULL),
152   m_svdSvec      (NULL),
153   m_svdVmat      (NULL),
154   m_svdVTmat     (NULL),
155   m_determinant  (-INFINITY),
156   m_lnDeterminant(-INFINITY),
157   m_permutation  (NULL),
158   m_signum       (0),
159   m_isSingular   (false)
160 {
161   queso_require_msg(m_mat, "null vector generated");
162   this->Matrix::base_copy(B);
163   this->copy(B);
164 }
165 
166 // Destructor ----------------------------------------------------------
~GslMatrix()167 GslMatrix::~GslMatrix()
168 {
169   this->reset();
170   if (m_mat) gsl_matrix_free(m_mat);
171 }
172 
173 // Set methods (operators) ---------------------------------------------
174 GslMatrix&
175 GslMatrix::operator=(const GslMatrix& obj)
176 {
177   this->reset();
178   this->copy(obj);
179   return *this;
180 }
181 
182 GslMatrix&
183 GslMatrix::operator*=(double a)
184 {
185   this->reset();
186   int iRC;
187   iRC = gsl_matrix_scale(m_mat,a);
188   queso_require_msg(!(iRC), "scaling failed");
189   return *this;
190 }
191 
192 GslMatrix&
193 GslMatrix::operator/=(double a)
194 {
195   this->reset();
196   *this *= (1./a);
197 
198   return *this;
199 }
200 
201 GslMatrix&
202 GslMatrix::operator+=(const GslMatrix& rhs)
203 {
204   this->reset();
205   int iRC;
206   iRC = gsl_matrix_add(m_mat,rhs.m_mat);
207   queso_require_msg(!(iRC), "failed");
208 
209   return *this;
210 }
211 
212 GslMatrix&
213 GslMatrix::operator-=(const GslMatrix& rhs)
214 {
215   this->reset();
216   int iRC;
217   iRC = gsl_matrix_sub(m_mat,rhs.m_mat);
218   queso_require_msg(!(iRC), "failed");
219 
220   return *this;
221 }
222 
223 
224 
225 void
copy(const GslMatrix & src)226 GslMatrix::copy(const GslMatrix& src)
227 {
228   // FIXME - should we be calling Matrix::base_copy here? - RHS
229   this->reset();
230   int iRC;
231   iRC = gsl_matrix_memcpy(this->m_mat, src.m_mat);
232   queso_require_msg(!(iRC), "failed");
233 
234   return;
235 }
236 
237 void
reset()238 GslMatrix::reset()
239 {
240   m_chol.reset();
241   if (m_LU) {
242     gsl_matrix_free(m_LU);
243     m_LU = NULL;
244   }
245   if (m_inverse) {
246     delete m_inverse;
247     m_inverse = NULL;
248   }
249   if (m_svdColMap) {
250     delete m_svdColMap;
251     m_svdColMap = NULL;
252   }
253   if (m_svdUmat) {
254     delete m_svdUmat;
255     m_svdUmat = NULL;
256   }
257   if (m_svdSvec) {
258     delete m_svdSvec;
259     m_svdSvec = NULL;
260   }
261   if (m_svdVmat) {
262     delete m_svdVmat;
263     m_svdVmat = NULL;
264   }
265   if (m_svdVTmat) {
266     delete m_svdVTmat;
267     m_svdVTmat = NULL;
268   }
269   m_determinant   = -INFINITY;
270   m_lnDeterminant = -INFINITY;
271   if (m_permutation) {
272     gsl_permutation_free(m_permutation);
273     m_permutation = NULL;
274   }
275   m_signum = 0;
276   m_isSingular = false;
277 
278   return;
279 }
280 
281 unsigned int
numRowsLocal()282 GslMatrix::numRowsLocal() const
283 {
284   return m_mat->size1;
285 }
286 
287 unsigned int
numRowsGlobal()288 GslMatrix::numRowsGlobal() const
289 {
290   return m_mat->size1;
291 }
292 
293 unsigned int
numCols()294 GslMatrix::numCols() const
295 {
296   return m_mat->size2;
297 }
298 
299 double
normFrob()300 GslMatrix::normFrob() const
301 {
302   double value = 0.;
303 
304   unsigned int nRows = this->numRowsLocal();
305   unsigned int nCols = this->numCols();
306   double aux = 0.;
307   for (unsigned int i = 0; i < nRows; i++) {
308     for (unsigned int j = 0; j < nCols; j++) {
309       aux = (*this)(i,j);
310       value += aux*aux;
311     }
312   }
313 
314   return sqrt(value);
315 }
316 
317 double
normMax()318 GslMatrix::normMax() const
319 {
320   double value = 0.;
321 
322   unsigned int nRows = this->numRowsLocal();
323   unsigned int nCols = this->numCols();
324   double aux = 0.;
325   for (unsigned int i = 0; i < nRows; i++) {
326     for (unsigned int j = 0; j < nCols; j++) {
327       aux = fabs((*this)(i,j));
328       if (aux > value) value = aux;
329     }
330   }
331 
332   return value;
333 }
334 
335 double
max()336 GslMatrix::max() const
337 {
338   double value = -INFINITY;
339 
340   unsigned int nRows = this->numRowsLocal();
341   unsigned int nCols = this->numCols();
342   double aux = 0.;
343   for (unsigned int i = 0; i < nRows; i++) {
344     for (unsigned int j = 0; j < nCols; j++) {
345       aux = (*this)(i,j);
346       if (aux > value) value = aux;
347     }
348   }
349 
350   return value;
351 }
352 
353 void
cwSet(double value)354 GslMatrix::cwSet(double value)
355 {
356   unsigned int nRows = this->numRowsLocal();
357   unsigned int nCols = this->numCols();
358 
359   for (unsigned int row = 0; row < nRows; ++row) {
360     for (unsigned int col = 0; col < nCols; ++col) {
361       *gsl_matrix_ptr(m_mat,row,col) = value;
362     }
363   }
364 
365   return;
366 }
367 
368 void
cwSet(unsigned int initialTargetRowId,unsigned int initialTargetColId,const GslMatrix & mat)369 GslMatrix::cwSet(
370   unsigned int            initialTargetRowId,
371   unsigned int            initialTargetColId,
372   const GslMatrix& mat)
373 {
374   queso_require_less_msg(initialTargetRowId, this->numRowsLocal(), "invalid initialTargetRowId");
375 
376   queso_require_less_equal_msg((initialTargetRowId + mat.numRowsLocal()), this->numRowsLocal(), "invalid vec.numRowsLocal()");
377 
378   queso_require_less_msg(initialTargetColId, this->numCols(), "invalid initialTargetColId");
379 
380   queso_require_less_equal_msg((initialTargetColId + mat.numCols()), this->numCols(), "invalid vec.numCols()");
381 
382   for (unsigned int i = 0; i < mat.numRowsLocal(); ++i) {
383     for (unsigned int j = 0; j < mat.numCols(); ++j) {
384       (*this)(initialTargetRowId+i,initialTargetColId+j) = mat(i,j);
385     }
386   }
387 
388   return;
389 }
390 
391 void
cwExtract(unsigned int initialTargetRowId,unsigned int initialTargetColId,GslMatrix & mat)392 GslMatrix::cwExtract(
393   unsigned int      initialTargetRowId,
394   unsigned int      initialTargetColId,
395   GslMatrix& mat) const
396 {
397   queso_require_less_msg(initialTargetRowId, this->numRowsLocal(), "invalid initialTargetRowId");
398 
399   queso_require_less_equal_msg((initialTargetRowId + mat.numRowsLocal()), this->numRowsLocal(), "invalid vec.numRowsLocal()");
400 
401   queso_require_less_msg(initialTargetColId, this->numCols(), "invalid initialTargetColId");
402 
403   queso_require_less_equal_msg((initialTargetColId + mat.numCols()), this->numCols(), "invalid vec.numCols()");
404 
405   for (unsigned int i = 0; i < mat.numRowsLocal(); ++i) {
406     for (unsigned int j = 0; j < mat.numCols(); ++j) {
407       mat(i,j) = (*this)(initialTargetRowId+i,initialTargetColId+j) ;
408     }
409   }
410 
411   return;
412 }
413 
414 int
chol()415 GslMatrix::chol()
416 {
417   int iRC;
418   //std::cout << "Calling gsl_linalg_cholesky_decomp()..." << std::endl;
419   gsl_error_handler_t* oldHandler;
420   oldHandler = gsl_set_error_handler_off();
421   iRC = gsl_linalg_cholesky_decomp(m_mat);
422   if (iRC != 0) {
423     std::cerr << "In GslMatrix::chol()"
424               << ": iRC = " << iRC
425               << ", gsl error message = " << gsl_strerror(iRC)
426               << std::endl;
427     std::cerr << "Here is the offending matrix: " << std::endl;
428     std::cerr << *this << std::endl;
429   }
430   gsl_set_error_handler(oldHandler);
431   //std::cout << "Returned from gsl_linalg_cholesky_decomp() with iRC = " << iRC << std::endl;
432   UQ_RC_MACRO(iRC, // Yes, *not* a fatal check on RC
433               m_env.worldRank(),
434               "GslMatrix::chol()",
435               "matrix is not positive definite",
436               UQ_MATRIX_IS_NOT_POS_DEFINITE_RC);
437 
438   return iRC;
439 }
440 
441 void
cholSolve(const GslVector & rhs,GslVector & sol)442 GslMatrix::cholSolve(const GslVector & rhs, GslVector & sol) const
443 {
444   queso_require_equal_to_msg(this->numCols(), rhs.sizeLocal(), "matrix and rhs have incompatible sizes");
445   queso_require_equal_to_msg(sol.sizeLocal(), rhs.sizeLocal(), "solution and rhs have incompatible sizes");
446 
447   int iRC;
448   if (m_chol == NULL) {
449     gsl_error_handler_t * oldHandler;
450     oldHandler = gsl_set_error_handler_off();
451 
452     // Returns NULL if the allocation failed
453     m_chol.reset(gsl_matrix_calloc(this->numRowsLocal(), this->numCols()),
454         gsl_matrix_free);
455     if (m_chol == NULL) {
456       gsl_set_error_handler(oldHandler);
457       queso_error_msg("gsl_matrix_calloc() failed");
458     }
459 
460     iRC = gsl_matrix_memcpy(m_chol.get(), m_mat);
461     if (iRC != 0) {
462       gsl_set_error_handler(oldHandler);
463       queso_error_msg("gsl_matrix_memcpy() failed");
464     }
465 
466     iRC = gsl_linalg_cholesky_decomp(m_chol.get());
467     if (iRC != 0) {  // Clean up if the matrix isn't spd
468       gsl_set_error_handler(oldHandler);
469       queso_error_msg("gsl_linalg_chol_decomp() failed: " << gsl_strerror(iRC));
470     }
471   }
472 
473   gsl_error_handler_t * oldHandler;
474   oldHandler = gsl_set_error_handler_off();
475 
476   iRC = gsl_linalg_cholesky_solve(m_chol.get(), rhs.data(), sol.data());
477 
478   gsl_set_error_handler(oldHandler);
479 
480   queso_require_msg(!iRC, "gsl_linalg_cholesky_solve failed: " << gsl_strerror(iRC));
481 }
482 
483 int
svd(GslMatrix & matU,GslVector & vecS,GslMatrix & matVt)484 GslMatrix::svd(GslMatrix& matU, GslVector& vecS, GslMatrix& matVt) const
485 {
486   unsigned int nRows = this->numRowsLocal();
487   unsigned int nCols = this->numCols();
488 
489   queso_require_msg(!((matU.numRowsLocal() != nRows) || (matU.numCols() != nCols)), "invalid matU");
490 
491   queso_require_equal_to_msg(vecS.sizeLocal(), nCols, "invalid vecS");
492 
493   queso_require_msg(!((matVt.numRowsLocal() != nCols) || (matVt.numCols() != nCols)), "invalid matVt");
494 
495   int iRC = internalSvd();
496 
497   matU  = *m_svdUmat;
498   vecS  = *m_svdSvec;
499   matVt = *m_svdVTmat;
500 
501   return iRC;
502 }
503 
504 int
svdSolve(const GslVector & rhsVec,GslVector & solVec)505 GslMatrix::svdSolve(const GslVector& rhsVec, GslVector& solVec) const
506 {
507   unsigned int nRows = this->numRowsLocal();
508   unsigned int nCols = this->numCols();
509 
510   queso_require_equal_to_msg(rhsVec.sizeLocal(), nRows, "invalid rhsVec");
511 
512   queso_require_equal_to_msg(solVec.sizeLocal(), nCols, "invalid solVec");
513 
514   int iRC = internalSvd();
515 
516   if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 5)) {
517     *m_env.subDisplayFile() << "In GslMatrix::svdSolve():"
518                             << "\n this->numRowsLocal()      = " << this->numRowsLocal()
519                             << ", this->numCols()      = "       << this->numCols()
520                             << "\n m_svdUmat->numRowsLocal() = " << m_svdUmat->numRowsLocal()
521                             << ", m_svdUmat->numCols() = "       << m_svdUmat->numCols()
522                             << "\n m_svdVmat->numRowsLocal() = " << m_svdVmat->numRowsLocal()
523                             << ", m_svdVmat->numCols() = "       << m_svdVmat->numCols()
524                             << "\n m_svdSvec->sizeLocal()    = " << m_svdSvec->sizeLocal()
525                             << "\n rhsVec.sizeLocal()        = " << rhsVec.sizeLocal()
526                             << "\n solVec.sizeLocal()        = " << solVec.sizeLocal()
527                             << std::endl;
528   }
529 
530   if (iRC == 0) iRC = gsl_linalg_SV_solve(m_svdUmat->data(), m_svdVmat->data(), m_svdSvec->data(), rhsVec.data(), solVec.data());
531 
532   return iRC;
533 }
534 
535 int
svdSolve(const GslMatrix & rhsMat,GslMatrix & solMat)536 GslMatrix::svdSolve(const GslMatrix& rhsMat, GslMatrix& solMat) const
537 {
538   unsigned int nRows = this->numRowsLocal();
539   unsigned int nCols = this->numCols();
540 
541   queso_require_equal_to_msg(rhsMat.numRowsLocal(), nRows, "invalid rhsMat");
542 
543   queso_require_equal_to_msg(solMat.numRowsLocal(), nCols, "invalid solMat");
544 
545   queso_require_equal_to_msg(rhsMat.numCols(), solMat.numCols(), "rhsMat and solMat are not compatible");
546 
547   GslVector rhsVec(m_env,rhsMat.map());
548   GslVector solVec(m_env,solMat.map());
549   int iRC = 0;
550   for (unsigned int j = 0; j < rhsMat.numCols(); ++j) {
551     rhsVec = rhsMat.getColumn(j);
552     iRC = this->svdSolve(rhsVec, solVec);
553     if (iRC) break;
554     solMat.setColumn(j,solVec);
555   }
556 
557   return iRC;
558 }
559 
560 const GslMatrix&
svdMatU()561 GslMatrix::svdMatU() const
562 {
563   int iRC = 0;
564   iRC = internalSvd();
565   if (iRC) {}; // just to remove compiler warning
566 
567   return *m_svdUmat;
568 }
569 
570 const GslMatrix&
svdMatV()571 GslMatrix::svdMatV() const
572 {
573   int iRC = 0;
574   iRC = internalSvd();
575   if (iRC) {}; // just to remove compiler warning
576 
577   return *m_svdVmat;
578 }
579 
580 int
internalSvd()581 GslMatrix::internalSvd() const
582 {
583   int iRC = 0;
584 
585   if (m_svdColMap == NULL) {
586     unsigned int nRows = this->numRowsLocal();
587     unsigned int nCols = this->numCols();
588     queso_require_greater_equal_msg(nRows, nCols, "GSL only supports cases where nRows >= nCols");
589 
590     m_svdColMap = new Map(this->numCols(),0,this->map().Comm()); // see 'VectorSpace<.,.>::newMap()' in src/basic/src/GslVectorSpace.C
591     m_svdUmat   = new GslMatrix(*this); // Yes, 'this'
592     m_svdSvec   = new GslVector(m_env,*m_svdColMap);
593     m_svdVmat   = new GslMatrix(*m_svdSvec);
594     m_svdVTmat  = new GslMatrix(*m_svdSvec);
595 
596     //std::cout << "In GslMatrix::internalSvd()"
597     //          << ", calling gsl_linalg_SV_decomp_jacobi()..."
598     //          << ": nRows = " << nRows
599     //          << ", nCols = " << nCols
600     //          << std::endl;
601     struct timeval timevalBegin;
602     gettimeofday(&timevalBegin, NULL);
603     gsl_error_handler_t* oldHandler;
604     oldHandler = gsl_set_error_handler_off();
605 #if 1
606     iRC = gsl_linalg_SV_decomp_jacobi(m_svdUmat->data(), m_svdVmat->data(), m_svdSvec->data());
607 #else
608     GslVector vecWork(*m_svdSvec );
609     iRC = gsl_linalg_SV_decomp(m_svdUmat->data(), m_svdVmat->data(), m_svdSvec->data(), vecWork.data());
610 #endif
611     if (iRC != 0) {
612       std::cerr << "In GslMatrix::internalSvd()"
613                 << ": iRC = " << iRC
614                 << ", gsl error message = " << gsl_strerror(iRC)
615                 << std::endl;
616     }
617     gsl_set_error_handler(oldHandler);
618 
619     struct timeval timevalNow;
620     gettimeofday(&timevalNow, NULL);
621     //std::cout << "In GslMatrix::internalSvd()"
622     //          << ": returned from gsl_linalg_SV_decomp_jacobi() with iRC = " << iRC
623     //          << " after " << timevalNow.tv_sec - timevalBegin.tv_sec
624     //          << " seconds"
625     //          << std::endl;
626     UQ_RC_MACRO(iRC, // Yes, *not* a fatal check on RC
627                 m_env.worldRank(),
628                 "GslMatrix::internalSvd()",
629                 "matrix svd failed",
630                 UQ_MATRIX_SVD_FAILED_RC);
631     *m_svdVTmat = m_svdVmat->transpose();
632   }
633 
634   return iRC;
635 }
636 
637 
638 
639 void
zeroLower(bool includeDiagonal)640 GslMatrix::zeroLower(bool includeDiagonal)
641 {
642   unsigned int nRows = this->numRowsLocal();
643   unsigned int nCols = this->numCols();
644 
645   queso_require_equal_to_msg(nRows, nCols, "routine works only for square matrices");
646 
647   this->reset();
648 
649   if (includeDiagonal) {
650     for (unsigned int i = 0; i < nRows; i++) {
651       for (unsigned int j = 0; j <= i; j++) {
652         (*this)(i,j) = 0.;
653       }
654     }
655   }
656   else {
657     for (unsigned int i = 0; i < nRows; i++) {
658       for (unsigned int j = 0; j < i; j++) {
659         (*this)(i,j) = 0.;
660       }
661     }
662   }
663 
664   return;
665 }
666 
667 void
zeroUpper(bool includeDiagonal)668 GslMatrix::zeroUpper(bool includeDiagonal)
669 {
670   unsigned int nRows = this->numRowsLocal();
671   unsigned int nCols = this->numCols();
672 
673   queso_require_equal_to_msg(nRows, nCols, "routine works only for square matrices");
674 
675   this->reset();
676 
677   if (includeDiagonal) {
678     for (unsigned int i = 0; i < nRows; i++) {
679       for (unsigned int j = i; j < nCols; j++) {
680         (*this)(i,j) = 0.;
681       }
682     }
683   }
684   else {
685     for (unsigned int i = 0; i < nRows; i++) {
686       for (unsigned int j = (i+1); j < nCols; j++) {
687         (*this)(i,j) = 0.;
688       }
689     }
690   }
691 
692   return;
693 }
694 
695 void
filterSmallValues(double thresholdValue)696 GslMatrix::filterSmallValues(double thresholdValue)
697 {
698   unsigned int nRows = this->numRowsLocal();
699   unsigned int nCols = this->numCols();
700   for (unsigned int i = 0; i < nRows; ++i) {
701     for (unsigned int j = 0; j < nCols; ++j) {
702       double aux = (*this)(i,j);
703       // If 'thresholdValue' is negative, no values will be filtered
704       if ((aux             < 0. ) &&
705           (-thresholdValue < aux)) {
706         (*this)(i,j) = 0.;
707       }
708       if ((aux            > 0. ) &&
709           (thresholdValue > aux)) {
710         (*this)(i,j) = 0.;
711       }
712     }
713   }
714 
715   return;
716 }
717 
718 void
filterLargeValues(double thresholdValue)719 GslMatrix::filterLargeValues(double thresholdValue)
720 {
721   unsigned int nRows = this->numRowsLocal();
722   unsigned int nCols = this->numCols();
723   for (unsigned int i = 0; i < nRows; ++i) {
724     for (unsigned int j = 0; j < nCols; ++j) {
725       double aux = (*this)(i,j);
726       // If 'thresholdValue' is negative, no values will be filtered
727       if ((aux             < 0. ) &&
728           (-thresholdValue > aux)) {
729         (*this)(i,j) = 0.;
730       }
731       if ((aux            > 0. ) &&
732           (thresholdValue < aux)) {
733         (*this)(i,j) = 0.;
734       }
735     }
736   }
737 
738   return;
739 }
740 
741 GslMatrix
transpose()742 GslMatrix::transpose() const
743 {
744   unsigned int nRows = this->numRowsGlobal();
745   unsigned int nCols = this->numCols();
746 
747   const MpiComm & comm = this->map().Comm();
748   Map serial_map(nCols, 0, comm);
749 
750   GslMatrix mat(m_env,serial_map,nRows);
751 
752   for (unsigned int row = 0; row < nRows; ++row) {
753     for (unsigned int col = 0; col < nCols; ++col) {
754       mat(col,row) = (*this)(row,col);
755     }
756   }
757 
758   return mat;
759 }
760 
761 GslMatrix
inverse()762 GslMatrix::inverse() const
763 {
764   unsigned int nRows = this->numRowsLocal();
765   unsigned int nCols = this->numCols();
766 
767   queso_require_equal_to_msg(nRows, nCols, "matrix is not square");
768 
769   if (m_inverse == NULL) {
770     m_inverse = new GslMatrix(m_env,m_map,nCols);
771     GslVector unitVector(m_env,m_map);
772     unitVector.cwSet(0.);
773     GslVector multVector(m_env,m_map);
774     for (unsigned int j = 0; j < nCols; ++j) {
775       if (j > 0) unitVector[j-1] = 0.;
776       unitVector[j] = 1.;
777       this->invertMultiply(unitVector, multVector);
778       for (unsigned int i = 0; i < nRows; ++i) {
779         (*m_inverse)(i,j) = multVector[i];
780       }
781     }
782   }
783   if (m_env.checkingLevel() >= 1) {
784     *m_env.subDisplayFile() << "CHECKING In GslMatrix::inverse()"
785                             << ": M.lnDet = "      << this->lnDeterminant()
786                             << ", M^{-1}.lnDet = " << m_inverse->lnDeterminant()
787                             << std::endl;
788   }
789   if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 5)) {
790     *m_env.subDisplayFile() << "In GslMatrix::inverse():"
791                             << "\n M = "        << *this
792                             << "\n M^{-1} = "   << *m_inverse
793                             << "\n M*M^{-1} = " << (*this)*(*m_inverse)
794                             << "\n M^{-1}*M = " << (*m_inverse)*(*this)
795                             << std::endl;
796   }
797 
798   return *m_inverse;
799 }
800 
801 void
fillWithBlocksDiagonally(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<const GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)802 GslMatrix::fillWithBlocksDiagonally(
803   unsigned int                                 initialTargetRowId,
804   unsigned int                                 initialTargetColId,
805   const std::vector<const GslMatrix* >& matrices,
806   bool                                         checkForExactNumRowsMatching,
807   bool                                         checkForExactNumColsMatching)
808 {
809   unsigned int sumNumRowsLocals = 0;
810   unsigned int sumNumCols       = 0;
811   for (unsigned int i = 0; i < matrices.size(); ++i) {
812     sumNumRowsLocals += matrices[i]->numRowsLocal();
813     sumNumCols       += matrices[i]->numCols();
814   }
815   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRowsLocals), "too big number of rows");
816   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRowsLocals), "inconsistent number of rows");
817   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + sumNumCols), "too big number of cols");
818   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + sumNumCols), "inconsistent number of cols");
819 
820   unsigned int cumulativeRowId = 0;
821   unsigned int cumulativeColId = 0;
822   for (unsigned int i = 0; i < matrices.size(); ++i) {
823     unsigned int nRows = matrices[i]->numRowsLocal();
824     unsigned int nCols = matrices[i]->numCols();
825     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
826       for (unsigned int colId = 0; colId < nCols; ++colId) {
827         (*this)(initialTargetRowId + cumulativeRowId + rowId, initialTargetColId + cumulativeColId + colId) = (*(matrices[i]))(rowId,colId);
828       }
829     }
830     cumulativeRowId += nRows;
831     cumulativeColId += nCols;
832   }
833 
834   return;
835 }
836 
837 void
fillWithBlocksDiagonally(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)838 GslMatrix::fillWithBlocksDiagonally(
839   unsigned int                           initialTargetRowId,
840   unsigned int                           initialTargetColId,
841   const std::vector<GslMatrix* >& matrices,
842   bool                                   checkForExactNumRowsMatching,
843   bool                                   checkForExactNumColsMatching)
844 {
845   unsigned int sumNumRowsLocals = 0;
846   unsigned int sumNumCols       = 0;
847   for (unsigned int i = 0; i < matrices.size(); ++i) {
848     sumNumRowsLocals += matrices[i]->numRowsLocal();
849     sumNumCols       += matrices[i]->numCols();
850   }
851   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRowsLocals), "too big number of rows");
852   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRowsLocals), "inconsistent number of rows");
853   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + sumNumCols), "too big number of cols");
854   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + sumNumCols), "inconsistent number of cols");
855 
856   unsigned int cumulativeRowId = 0;
857   unsigned int cumulativeColId = 0;
858   for (unsigned int i = 0; i < matrices.size(); ++i) {
859     unsigned int nRows = matrices[i]->numRowsLocal();
860     unsigned int nCols = matrices[i]->numCols();
861     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
862       for (unsigned int colId = 0; colId < nCols; ++colId) {
863         (*this)(initialTargetRowId + cumulativeRowId + rowId, initialTargetColId + cumulativeColId + colId) = (*(matrices[i]))(rowId,colId);
864       }
865     }
866     cumulativeRowId += nRows;
867     cumulativeColId += nCols;
868   }
869 
870   return;
871 }
872 
873 void
fillWithBlocksHorizontally(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<const GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)874 GslMatrix::fillWithBlocksHorizontally(
875   unsigned int                                 initialTargetRowId,
876   unsigned int                                 initialTargetColId,
877   const std::vector<const GslMatrix* >& matrices,
878   bool                                         checkForExactNumRowsMatching,
879   bool                                         checkForExactNumColsMatching)
880 {
881   unsigned int sumNumCols = 0;
882   for (unsigned int i = 0; i < matrices.size(); ++i) {
883     queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + matrices[i]->numRowsLocal()), "too big number of rows");
884     if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + matrices[i]->numRowsLocal()), "inconsistent number of rows");
885     sumNumCols += matrices[i]->numCols();
886   }
887   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + sumNumCols), "too big number of cols");
888   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + sumNumCols), "inconsistent number of cols");
889 
890   unsigned int cumulativeColId = 0;
891   for (unsigned int i = 0; i < matrices.size(); ++i) {
892     unsigned int nRows = matrices[i]->numRowsLocal();
893     unsigned int nCols = matrices[i]->numCols();
894     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
895       for (unsigned int colId = 0; colId < nCols; ++colId) {
896         (*this)(initialTargetRowId + rowId, initialTargetColId + cumulativeColId + colId) = (*(matrices[i]))(rowId,colId);
897       }
898     }
899     cumulativeColId += nCols;
900   }
901 
902   return;
903 }
904 
905 void
fillWithBlocksHorizontally(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)906 GslMatrix::fillWithBlocksHorizontally(
907   unsigned int                           initialTargetRowId,
908   unsigned int                           initialTargetColId,
909   const std::vector<GslMatrix* >& matrices,
910   bool                                   checkForExactNumRowsMatching,
911   bool                                   checkForExactNumColsMatching)
912 {
913   unsigned int sumNumCols = 0;
914   for (unsigned int i = 0; i < matrices.size(); ++i) {
915     queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + matrices[i]->numRowsLocal()), "too big number of rows");
916     if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + matrices[i]->numRowsLocal()), "inconsistent number of rows");
917     sumNumCols += matrices[i]->numCols();
918   }
919   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + sumNumCols), "too big number of cols");
920   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + sumNumCols), "inconsistent number of cols");
921 
922   unsigned int cumulativeColId = 0;
923   for (unsigned int i = 0; i < matrices.size(); ++i) {
924     unsigned int nRows = matrices[i]->numRowsLocal();
925     unsigned int nCols = matrices[i]->numCols();
926     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
927       for (unsigned int colId = 0; colId < nCols; ++colId) {
928         (*this)(initialTargetRowId + rowId, initialTargetColId + cumulativeColId + colId) = (*(matrices[i]))(rowId,colId);
929       }
930     }
931     cumulativeColId += nCols;
932   }
933 
934   return;
935 }
936 
937 void
fillWithBlocksVertically(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<const GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)938 GslMatrix::fillWithBlocksVertically( // checar
939   unsigned int                                 initialTargetRowId,
940   unsigned int                                 initialTargetColId,
941   const std::vector<const GslMatrix* >& matrices,
942   bool                                         checkForExactNumRowsMatching,
943   bool                                         checkForExactNumColsMatching)
944 {
945   unsigned int sumNumRows = 0;
946   for (unsigned int i = 0; i < matrices.size(); ++i) {
947     queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + matrices[i]->numCols()), "too big number of cols");
948     if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + matrices[i]->numCols()), "inconsistent number of cols");
949     sumNumRows += matrices[i]->numRowsLocal();
950   }
951   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRows), "too big number of rows");
952   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRows), "inconsistent number of rows");
953 
954   unsigned int cumulativeRowId = 0;
955   for (unsigned int i = 0; i < matrices.size(); ++i) {
956     unsigned int nRows = matrices[i]->numRowsLocal();
957     unsigned int nCols = matrices[i]->numCols();
958     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
959       for (unsigned int colId = 0; colId < nCols; ++colId) {
960         (*this)(initialTargetRowId + cumulativeRowId + rowId, initialTargetColId + colId) = (*(matrices[i]))(rowId,colId);
961       }
962     }
963     cumulativeRowId += nRows;
964   }
965 
966   return;
967 }
968 
969 void
fillWithBlocksVertically(unsigned int initialTargetRowId,unsigned int initialTargetColId,const std::vector<GslMatrix * > & matrices,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)970 GslMatrix::fillWithBlocksVertically( // checar
971   unsigned int                           initialTargetRowId,
972   unsigned int                           initialTargetColId,
973   const std::vector<GslMatrix* >& matrices,
974   bool                                   checkForExactNumRowsMatching,
975   bool                                   checkForExactNumColsMatching)
976 {
977   unsigned int sumNumRows = 0;
978   for (unsigned int i = 0; i < matrices.size(); ++i) {
979     queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + matrices[i]->numCols()), "too big number of cols");
980     if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + matrices[i]->numCols()), "inconsistent number of cols");
981     sumNumRows += matrices[i]->numRowsLocal();
982   }
983   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRows), "too big number of rows");
984   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + sumNumRows), "inconsistent number of rows");
985 
986   unsigned int cumulativeRowId = 0;
987   for (unsigned int i = 0; i < matrices.size(); ++i) {
988     unsigned int nRows = matrices[i]->numRowsLocal();
989     unsigned int nCols = matrices[i]->numCols();
990     for (unsigned int rowId = 0; rowId < nRows; ++rowId) {
991       for (unsigned int colId = 0; colId < nCols; ++colId) {
992         (*this)(initialTargetRowId + cumulativeRowId + rowId, initialTargetColId + colId) = (*(matrices[i]))(rowId,colId);
993       }
994     }
995     cumulativeRowId += nRows;
996   }
997 
998   return;
999 }
1000 
1001 void
fillWithTensorProduct(unsigned int initialTargetRowId,unsigned int initialTargetColId,const GslMatrix & mat1,const GslMatrix & mat2,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)1002 GslMatrix::fillWithTensorProduct(
1003   unsigned int            initialTargetRowId,
1004   unsigned int            initialTargetColId,
1005   const GslMatrix& mat1,
1006   const GslMatrix& mat2,
1007   bool                    checkForExactNumRowsMatching,
1008   bool                    checkForExactNumColsMatching)
1009 {
1010   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + (mat1.numRowsLocal() * mat2.numRowsLocal())), "too big number of rows");
1011   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + (mat1.numRowsLocal() * mat2.numRowsLocal())), "inconsistent number of rows");
1012   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + (mat1.numCols() * mat2.numCols())), "too big number of columns");
1013   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + (mat1.numCols() * mat2.numCols())), "inconsistent number of columns");
1014 
1015   for (unsigned int rowId1 = 0; rowId1 < mat1.numRowsLocal(); ++rowId1) {
1016     for (unsigned int colId1 = 0; colId1 < mat1.numCols(); ++colId1) {
1017       double multiplicativeFactor = mat1(rowId1,colId1);
1018       unsigned int targetRowId = rowId1 * mat2.numRowsLocal();
1019       unsigned int targetColId = colId1 * mat2.numCols();
1020       for (unsigned int rowId2 = 0; rowId2 < mat2.numRowsLocal(); ++rowId2) {
1021         for (unsigned int colId2 = 0; colId2 < mat2.numCols(); ++colId2) {
1022           (*this)(initialTargetRowId + targetRowId + rowId2, initialTargetColId + targetColId + colId2) = multiplicativeFactor * mat2(rowId2,colId2);
1023         }
1024       }
1025     }
1026   }
1027 
1028   return;
1029 }
1030 
1031 void
fillWithTensorProduct(unsigned int initialTargetRowId,unsigned int initialTargetColId,const GslMatrix & mat1,const GslVector & vec2,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)1032 GslMatrix::fillWithTensorProduct(
1033   unsigned int            initialTargetRowId,
1034   unsigned int            initialTargetColId,
1035   const GslMatrix& mat1,
1036   const GslVector& vec2,
1037   bool                    checkForExactNumRowsMatching,
1038   bool                    checkForExactNumColsMatching)
1039 {
1040   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + (mat1.numRowsLocal() * vec2.sizeLocal())), "too big number of rows");
1041   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + (mat1.numRowsLocal() * vec2.sizeLocal())), "inconsistent number of rows");
1042   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + (mat1.numCols() * 1)), "too big number of columns");
1043   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + (mat1.numCols() * 1)), "inconsistent number of columns");
1044 
1045   for (unsigned int rowId1 = 0; rowId1 < mat1.numRowsLocal(); ++rowId1) {
1046     for (unsigned int colId1 = 0; colId1 < mat1.numCols(); ++colId1) {
1047       double multiplicativeFactor = mat1(rowId1,colId1);
1048       unsigned int targetRowId = rowId1 * vec2.sizeLocal();
1049       unsigned int targetColId = colId1 * 1;
1050       for (unsigned int rowId2 = 0; rowId2 < vec2.sizeLocal(); ++rowId2) {
1051         for (unsigned int colId2 = 0; colId2 < 1; ++colId2) {
1052           (*this)(initialTargetRowId + targetRowId + rowId2, initialTargetColId + targetColId + colId2) = multiplicativeFactor * vec2[rowId2];
1053         }
1054       }
1055     }
1056   }
1057 
1058 
1059   return;
1060 }
1061 
1062 void
fillWithTranspose(unsigned int initialTargetRowId,unsigned int initialTargetColId,const GslMatrix & mat,bool checkForExactNumRowsMatching,bool checkForExactNumColsMatching)1063 GslMatrix::fillWithTranspose(
1064   unsigned int            initialTargetRowId,
1065   unsigned int            initialTargetColId,
1066   const GslMatrix& mat,
1067   bool                    checkForExactNumRowsMatching,
1068   bool                    checkForExactNumColsMatching)
1069 {
1070   unsigned int nRows = mat.numRowsLocal();
1071   unsigned int nCols = mat.numCols();
1072   queso_require_greater_equal_msg(this->numRowsLocal(), (initialTargetRowId + nCols), "too big number of rows");
1073   if (checkForExactNumRowsMatching) queso_require_equal_to_msg(this->numRowsLocal(), (initialTargetRowId + nCols), "inconsistent number of rows");
1074   queso_require_greater_equal_msg(this->numCols(), (initialTargetColId + nRows), "too big number of cols");
1075   if (checkForExactNumColsMatching) queso_require_equal_to_msg(this->numCols(), (initialTargetColId + nRows), "inconsistent number of cols");
1076 
1077   for (unsigned int row = 0; row < nRows; ++row) {
1078     for (unsigned int col = 0; col < nCols; ++col) {
1079       (*this)(initialTargetRowId + col, initialTargetColId + row) = mat(row,col);
1080     }
1081   }
1082 
1083   return;
1084 }
1085 
1086 double
determinant()1087 GslMatrix::determinant() const
1088 {
1089   if (m_determinant == -INFINITY) {
1090     if (m_LU == NULL) {
1091       GslVector tmpB(m_env,m_map);
1092       GslVector tmpX(m_env,m_map);
1093       if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1094         *m_env.subDisplayFile() << "In GslMatrix::determinant()"
1095                                 << ": before 'this->invertMultiply()'"
1096                                 << std::endl;
1097       }
1098       this->invertMultiply(tmpB,tmpX);
1099       if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1100         *m_env.subDisplayFile() << "In GslMatrix::determinant()"
1101                                 << ": after 'this->invertMultiply()'"
1102                                 << std::endl;
1103       }
1104     }
1105     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1106       *m_env.subDisplayFile() << "In GslMatrix::determinant()"
1107                               << ": before 'gsl_linalg_LU_det()'"
1108                               << std::endl;
1109     }
1110     m_determinant   = gsl_linalg_LU_det(m_LU,m_signum);
1111     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1112       *m_env.subDisplayFile() << "In GslMatrix::determinant()"
1113                               << ": after 'gsl_linalg_LU_det()'"
1114                               << std::endl;
1115     }
1116     m_lnDeterminant = gsl_linalg_LU_lndet(m_LU);
1117     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1118       *m_env.subDisplayFile() << "In GslMatrix::determinant()"
1119                               << ": after 'gsl_linalg_LU_lndet()'"
1120                               << std::endl;
1121     }
1122   }
1123 
1124   return m_determinant;
1125 }
1126 
1127 double
lnDeterminant()1128 GslMatrix::lnDeterminant() const
1129 {
1130   if (m_lnDeterminant == -INFINITY) {
1131     if (m_LU == NULL) {
1132       GslVector tmpB(m_env,m_map);
1133       GslVector tmpX(m_env,m_map);
1134       if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1135         *m_env.subDisplayFile() << "In GslMatrix::lnDeterminant()"
1136                                 << ": before 'this->invertMultiply()'"
1137                                 << std::endl;
1138       }
1139       this->invertMultiply(tmpB,tmpX);
1140       if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1141         *m_env.subDisplayFile() << "In GslMatrix::lnDeterminant()"
1142                                 << ": after 'this->invertMultiply()'"
1143                                 << std::endl;
1144       }
1145     }
1146     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1147       *m_env.subDisplayFile() << "In GslMatrix::lnDeterminant()"
1148                               << ": before 'gsl_linalg_LU_det()'"
1149                               << std::endl;
1150     }
1151     m_determinant   = gsl_linalg_LU_det(m_LU,m_signum);
1152     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1153       *m_env.subDisplayFile() << "In GslMatrix::lnDeterminant()"
1154                               << ": after 'gsl_linalg_LU_det()'"
1155                               << std::endl;
1156     }
1157     m_lnDeterminant = gsl_linalg_LU_lndet(m_LU);
1158     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1159       *m_env.subDisplayFile() << "In GslMatrix::lnDeterminant()"
1160                               << ": before 'gsl_linalg_LU_lndet()'"
1161                               << std::endl;
1162     }
1163   }
1164 
1165   return m_lnDeterminant;
1166 }
1167 
1168 unsigned int
rank(double absoluteZeroThreshold,double relativeZeroThreshold)1169 GslMatrix::rank(double absoluteZeroThreshold, double relativeZeroThreshold) const
1170 {
1171   int iRC = 0;
1172   iRC = internalSvd();
1173   if (iRC) {}; // just to remove compiler warning
1174 
1175   GslVector relativeVec(*m_svdSvec);
1176   if (relativeVec[0] > 0.) {
1177     relativeVec = (1./relativeVec[0])*relativeVec;
1178   }
1179 
1180   unsigned int rankValue = 0;
1181   for (unsigned int i = 0; i < relativeVec.sizeLocal(); ++i) {
1182     if (( (*m_svdSvec)[i] >= absoluteZeroThreshold ) &&
1183         ( relativeVec [i] >= relativeZeroThreshold )) {
1184        rankValue += 1;
1185     }
1186   }
1187 
1188   if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 3)) {
1189     *m_env.subDisplayFile() << "In GslMatrix::rank()"
1190                             << ": this->numRowsLocal() = "  << this->numRowsLocal()
1191                             << ", this->numCols() = "       << this->numCols()
1192                             << ", absoluteZeroThreshold = " << absoluteZeroThreshold
1193                             << ", relativeZeroThreshold = " << relativeZeroThreshold
1194                             << ", rankValue = "             << rankValue
1195                             << ", m_svdSvec = "             << *m_svdSvec
1196                             << ", relativeVec = "           << relativeVec
1197                             << std::endl;
1198   }
1199 
1200   return rankValue;
1201 }
1202 
1203 GslVector
multiply(const GslVector & x)1204 GslMatrix::multiply(
1205   const GslVector& x) const
1206 {
1207   queso_require_equal_to_msg(this->numCols(), x.sizeLocal(), "matrix and vector have incompatible sizes");
1208 
1209   GslVector y(m_env,m_map);
1210   this->multiply(x,y);
1211 
1212   return y;
1213 }
1214 
1215 void
multiply(const GslVector & x,GslVector & y)1216 GslMatrix::multiply(
1217   const GslVector& x,
1218         GslVector& y) const
1219 {
1220   queso_require_equal_to_msg(this->numCols(), x.sizeLocal(), "matrix and x have incompatible sizes");
1221 
1222   queso_require_equal_to_msg(this->numRowsLocal(), y.sizeLocal(), "matrix and y have incompatible sizes");
1223 
1224   unsigned int sizeX = this->numCols();
1225   unsigned int sizeY = this->numRowsLocal();
1226   for (unsigned int i = 0; i < sizeY; ++i) {
1227     double value = 0.;
1228     for (unsigned int j = 0; j < sizeX; ++j) {
1229       value += (*this)(i,j)*x[j];
1230     }
1231     y[i] = value;
1232   }
1233 
1234   return;
1235 }
1236 
1237 GslMatrix
multiply(const GslMatrix & X)1238 GslMatrix::multiply(
1239   const GslMatrix & X) const
1240 {
1241   GslMatrix Y(m_env,m_map,X.numCols());
1242   this->multiply(X,Y);
1243 
1244   return Y;
1245 }
1246 
1247 
1248 
1249 void
multiply(const GslMatrix & X,GslMatrix & Y)1250 GslMatrix::multiply(
1251   const GslMatrix & X,
1252         GslMatrix & Y) const
1253 {
1254   queso_require_equal_to_msg(this->numCols(), X.numRowsGlobal(), "matrix and X have incompatible sizes");
1255   queso_require_equal_to_msg(this->numRowsGlobal(), Y.numRowsGlobal(), "matrix and Y have incompatible sizes");
1256   queso_require_equal_to_msg(X.numCols(), Y.numCols(), "X and Y have incompatible sizes");
1257 
1258   const unsigned int m_s = this->numRowsGlobal();
1259   const unsigned int p_s = this->numCols();
1260   const unsigned int n_s = X.numCols();
1261 
1262   for (unsigned int k=0; k<p_s; k++)
1263     for (unsigned int j=0; j<n_s; j++)
1264       if (X(k,j) != 0.)
1265         for (unsigned int i=0; i<m_s; i++)
1266           Y(i,j) += (*this)(i,k) * X(k,j);
1267 }
1268 
1269 
1270 GslVector
invertMultiply(const GslVector & b)1271 GslMatrix::invertMultiply(
1272   const GslVector& b) const
1273 {
1274   queso_require_equal_to_msg(this->numCols(), b.sizeLocal(), "matrix and rhs have incompatible sizes");
1275 
1276   GslVector x(m_env,m_map);
1277   this->invertMultiply(b,x);
1278 
1279   return x;
1280 }
1281 
1282 void
invertMultiply(const GslVector & b,GslVector & x)1283 GslMatrix::invertMultiply(
1284   const GslVector& b,
1285         GslVector& x) const
1286 {
1287   queso_require_equal_to_msg(this->numCols(), b.sizeLocal(), "matrix and rhs have incompatible sizes");
1288 
1289   queso_require_equal_to_msg(x.sizeLocal(), b.sizeLocal(), "solution and rhs have incompatible sizes");
1290 
1291   int iRC;
1292   if (m_LU == NULL) {
1293     queso_require_msg(!(m_permutation), "m_permutation should be NULL");
1294 
1295     m_LU = gsl_matrix_calloc(this->numRowsLocal(),this->numCols());
1296     queso_require_msg(m_LU, "gsl_matrix_calloc() failed");
1297 
1298     iRC = gsl_matrix_memcpy(m_LU, m_mat);
1299     queso_require_msg(!(iRC), "gsl_matrix_memcpy() failed");
1300 
1301     m_permutation = gsl_permutation_calloc(numCols());
1302     queso_require_msg(m_permutation, "gsl_permutation_calloc() failed");
1303 
1304     if (m_inDebugMode) {
1305       std::cout << "In GslMatrix::invertMultiply()"
1306                 << ": before LU decomposition, m_LU = ";
1307       gsl_matrix_fprintf(stdout, m_LU, "%f");
1308       std::cout << std::endl;
1309     }
1310 
1311     gsl_error_handler_t* oldHandler;
1312     oldHandler = gsl_set_error_handler_off();
1313     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1314       *m_env.subDisplayFile() << "In GslMatrix::invertMultiply()"
1315                               << ": before 'gsl_linalg_LU_decomp()'"
1316                               << std::endl;
1317     }
1318     iRC = gsl_linalg_LU_decomp(m_LU,m_permutation,&m_signum);
1319     if (iRC != 0) {
1320       std::cerr << "In GslMatrix::invertMultiply()"
1321                 << ", after gsl_linalg_LU_decomp()"
1322                 << ": iRC = " << iRC
1323                 << ", gsl error message = " << gsl_strerror(iRC)
1324                 << std::endl;
1325     }
1326     gsl_set_error_handler(oldHandler);
1327     if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1328       *m_env.subDisplayFile() << "In GslMatrix::invertMultiply()"
1329                               << ": after 'gsl_linalg_LU_decomp()'"
1330                               << ", IRC = " << iRC
1331                               << std::endl;
1332     }
1333     queso_require_msg(!(iRC), "gsl_linalg_LU_decomp() failed");
1334 
1335     if (m_inDebugMode) {
1336       std::cout << "In GslMatrix::invertMultiply()"
1337                 << ": after LU decomposition, m_LU = ";
1338       gsl_matrix_fprintf(stdout, m_LU, "%f");
1339       std::cout << std::endl;
1340     }
1341   }
1342 
1343   gsl_error_handler_t* oldHandler;
1344   oldHandler = gsl_set_error_handler_off();
1345   if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1346     *m_env.subDisplayFile() << "In GslMatrix::invertMultiply()"
1347                             << ": before 'gsl_linalg_LU_solve()'"
1348                             << std::endl;
1349   }
1350   iRC = gsl_linalg_LU_solve(m_LU,m_permutation,b.data(),x.data());
1351   if (iRC != 0) {
1352     m_isSingular = true;
1353     std::cerr << "In GslMatrix::invertMultiply()"
1354               << ", after gsl_linalg_LU_solve()"
1355               << ": iRC = " << iRC
1356               << ", gsl error message = " << gsl_strerror(iRC)
1357               << std::endl;
1358   }
1359   gsl_set_error_handler(oldHandler);
1360   if ((m_env.subDisplayFile()) && (m_env.displayVerbosity() >= 99)) {
1361     *m_env.subDisplayFile() << "In GslMatrix::invertMultiply()"
1362                             << ": after 'gsl_linalg_LU_solve()'"
1363                             << ", IRC = " << iRC
1364                             << std::endl;
1365   }
1366 
1367 
1368   //                  m_env.worldRank(),
1369   //                  "GslMatrix::invertMultiply()",
1370   //                  "gsl_linalg_LU_solve() failed");
1371 
1372   if (m_inDebugMode) {
1373     GslVector tmpVec(b - (*this)*x);
1374     std::cout << "In GslMatrix::invertMultiply()"
1375               << ": ||b - Ax||_2 = "         << tmpVec.norm2()
1376               << ": ||b - Ax||_2/||b||_2 = " << tmpVec.norm2()/b.norm2()
1377               << std::endl;
1378   }
1379 
1380   return;
1381 }
1382 
1383 GslMatrix
invertMultiply(const GslMatrix & B)1384 GslMatrix::invertMultiply(const GslMatrix& B) const
1385 {
1386   GslMatrix X(m_env,m_map,B.numCols());
1387   this->invertMultiply(B,X);
1388 
1389   return X;
1390 }
1391 
1392 void
invertMultiply(const GslMatrix & B,GslMatrix & X)1393 GslMatrix::invertMultiply(const GslMatrix& B, GslMatrix& X) const
1394 {
1395   // Sanity Checks
1396   queso_require_equal_to_msg(B.numRowsLocal(), X.numRowsLocal(),
1397 		             "Matrices B and X are incompatible");
1398   queso_require_equal_to_msg(B.numCols(),      X.numCols(),
1399 		             "Matrices B and X are incompatible");
1400   queso_require_equal_to_msg(this->numRowsLocal(), X.numRowsLocal(),
1401                              "This and X matrices are incompatible");
1402 
1403   // Some local variables used within the loop.
1404   GslVector b(m_env, m_map);
1405   GslVector x(m_env, m_map);
1406 
1407   for( unsigned int j = 0; j < B.numCols(); ++j )
1408     {
1409       b = B.getColumn( j );
1410 
1411       //invertMultiply will only do the LU once and store it. So we don't
1412       //need to worry about it doing LU multiple times.
1413       x = this->invertMultiply( b );
1414 
1415       X.setColumn( j, x );
1416     }
1417 
1418   return;
1419 }
1420 
1421 GslVector
invertMultiplyForceLU(const GslVector & b)1422 GslMatrix::invertMultiplyForceLU(
1423   const GslVector& b) const
1424 {
1425   queso_require_equal_to_msg(this->numCols(), b.sizeLocal(), "matrix and rhs have incompatible sizes");
1426 
1427   GslVector x(m_env,m_map);
1428   this->invertMultiplyForceLU(b,x);
1429 
1430   return x;
1431 }
1432 
1433 void
invertMultiplyForceLU(const GslVector & b,GslVector & x)1434 GslMatrix::invertMultiplyForceLU(
1435   const GslVector& b,
1436         GslVector& x) const
1437 {
1438   queso_require_equal_to_msg(this->numCols(), b.sizeLocal(), "matrix and rhs have incompatible sizes");
1439 
1440   queso_require_equal_to_msg(x.sizeLocal(), b.sizeLocal(), "solution and rhs have incompatible sizes");
1441 
1442   int iRC;
1443 
1444   if ( m_LU == NULL ) {
1445     queso_require_msg(!(m_permutation), "m_permutation should be NULL");
1446     m_LU = gsl_matrix_calloc(this->numRowsLocal(),this->numCols());
1447   }
1448   queso_require_msg(m_LU, "gsl_matrix_calloc() failed");
1449 
1450   iRC = gsl_matrix_memcpy(m_LU, m_mat);
1451   queso_require_msg(!(iRC), "gsl_matrix_memcpy() failed");
1452 
1453   if( m_permutation == NULL ) m_permutation = gsl_permutation_calloc(numCols());
1454   queso_require_msg(m_permutation, "gsl_permutation_calloc() failed");
1455 
1456   iRC = gsl_linalg_LU_decomp(m_LU,m_permutation,&m_signum);
1457   queso_require_msg(!(iRC), "gsl_linalg_LU_decomp() failed");
1458 
1459   iRC = gsl_linalg_LU_solve(m_LU,m_permutation,b.data(),x.data());
1460   if (iRC != 0) {
1461     m_isSingular = true;
1462   }
1463   queso_require_msg(!(iRC), "gsl_linalg_LU_solve() failed");
1464 
1465   return;
1466 }
1467 
1468 void
eigen(GslVector & eigenValues,GslMatrix * eigenVectors)1469 GslMatrix::eigen(GslVector& eigenValues, GslMatrix* eigenVectors) const
1470 {
1471   unsigned int n = eigenValues.sizeLocal();
1472 
1473   queso_require_not_equal_to_msg(n, 0, "invalid input vector size");
1474 
1475   if (eigenVectors) {
1476     queso_require_equal_to_msg(eigenValues.sizeLocal(), eigenVectors->numRowsLocal(), "different input vector sizes");
1477   }
1478 
1479   if (eigenVectors == NULL) {
1480     gsl_eigen_symm_workspace* w = gsl_eigen_symm_alloc((size_t) n);
1481     gsl_eigen_symm(m_mat,eigenValues.data(),w);
1482     gsl_eigen_symm_free(w);
1483   }
1484   else {
1485     gsl_eigen_symmv_workspace* w = gsl_eigen_symmv_alloc((size_t) n);
1486     gsl_eigen_symmv(m_mat,eigenValues.data(),eigenVectors->m_mat,w);
1487     gsl_eigen_symmv_sort(eigenValues.data(),eigenVectors->m_mat,GSL_EIGEN_SORT_VAL_ASC);
1488     gsl_eigen_symmv_free(w);
1489   }
1490 
1491   return;
1492 }
1493 
1494 void
largestEigen(double & eigenValue,GslVector & eigenVector)1495 GslMatrix::largestEigen(double& eigenValue, GslVector& eigenVector) const
1496 {
1497 
1498   // Sanity Checks
1499   unsigned int n = eigenVector.sizeLocal();
1500 
1501   queso_require_not_equal_to_msg(n, 0, "invalid input vector size");
1502 
1503   /* The following notation is used:
1504      z = vector used in iteration that ends up being the eigenvector corresponding to the
1505          largest eigenvalue
1506      w = vector used in iteration that we extract the largest eigenvalue from.  */
1507 
1508   // Some parameters associated with the algorithm
1509   // TODO: Do we want to add the ability to have these set by the user?
1510   const unsigned int max_num_iterations = 10000;
1511   const double tolerance = 1.0e-13;
1512 
1513   // Create temporary working vectors.
1514   // TODO: We shouldn't have to use these - we ought to be able to work directly
1515   // TODO: with eigenValue and eigenVector. Optimize this once we have regression
1516   // TODO: tests.
1517   GslVector z(m_env, m_map, 1.0 ); // Needs to be initialized to 1.0
1518   GslVector w(m_env, m_map);
1519 
1520   // Some variables we use inside the loop.
1521   int index;
1522   double residual;
1523   double lambda;
1524 
1525   for( unsigned int k = 0; k < max_num_iterations; ++k )
1526     {
1527       w = (*this) * z;
1528 
1529       // For this algorithm, it's crucial to get the maximum in
1530       // absolute value, but then to normalize by the actual value
1531       // and *not* the absolute value.
1532       index = (w.abs()).getMaxValueIndex();
1533 
1534       lambda = w[index];
1535 
1536       z = (1.0/lambda) * w;
1537 
1538       // Here we use the norm of the residual as our convergence check:
1539       // norm( A*x - \lambda*x )
1540       residual = ( (*this)*z - lambda*z ).norm2();
1541 
1542       if( residual < tolerance )
1543 	{
1544 	  eigenValue = lambda;
1545 
1546 	  // TODO: Do we want to normalize this so eigenVector.norm2() = 1?
1547 	  eigenVector = z;
1548 	  return;
1549 	}
1550 
1551     }
1552 
1553   // If we reach this point, then we didn't converge. Print error message
1554   // to this effect.
1555   // TODO: We know we failed at this point - need a way to not need a test
1556   // TODO: Just specify the error.
1557   queso_require_less_msg(residual, tolerance, "Maximum num iterations exceeded");
1558 
1559 
1560   return;
1561 }
1562 
1563 void
smallestEigen(double & eigenValue,GslVector & eigenVector)1564 GslMatrix::smallestEigen(double& eigenValue, GslVector& eigenVector) const
1565 {
1566   // Sanity Checks
1567   unsigned int n = eigenVector.sizeLocal();
1568 
1569   queso_require_not_equal_to_msg(n, 0, "invalid input vector size");
1570 
1571   /* The following notation is used:
1572      z = vector used in iteration that ends up being the eigenvector corresponding to the
1573          largest eigenvalue
1574      w = vector used in iteration that we extract the largest eigenvalue from.  */
1575 
1576   // Some parameters associated with the algorithm
1577   // TODO: Do we want to add the ability to have these set by the user?
1578   const unsigned int max_num_iterations = 1000;
1579   const double tolerance = 1.0e-13;
1580 
1581   // Create temporary working vectors.
1582   // TODO: We shouldn't have to use these - we ought to be able to work directly
1583   // TODO: with eigenValue and eigenVector. Optimize this once we have regression
1584   // TODO: tests.
1585   GslVector z(m_env, m_map, 1.0 ); // Needs to be initialized to 1.0
1586   GslVector w(m_env, m_map);
1587 
1588   // Some variables we use inside the loop.
1589   int index;
1590   double residual;
1591   double one_over_lambda;
1592   double lambda;
1593 
1594   for( unsigned int k = 0; k < max_num_iterations; ++k )
1595     {
1596       w = (*this).invertMultiplyForceLU( z );
1597 
1598       // For this algorithm, it's crucial to get the maximum in
1599       // absolute value, but then to normalize by the actual value
1600       // and *not* the absolute value.
1601       index = (w.abs()).getMaxValueIndex();
1602 
1603       // Remember: Inverse power method solves for max 1/lambda ==> lambda smallest
1604       one_over_lambda = w[index];
1605 
1606       lambda = 1.0/one_over_lambda;
1607 
1608       z = lambda * w;
1609 
1610       // Here we use the norm of the residual as our convergence check:
1611       // norm( A*x - \lambda*x )
1612       residual = ( (*this)*z - lambda*z ).norm2();
1613 
1614       if( residual < tolerance )
1615 	{
1616 	  eigenValue = lambda;
1617 
1618 	  // TODO: Do we want to normalize this so eigenVector.norm2() = 1?
1619 	  eigenVector = z;
1620 	  return;
1621 	}
1622 
1623     }
1624 
1625   // If we reach this point, then we didn't converge. Print error message
1626   // to this effect.
1627   // TODO: We know we failed at this point - need a way to not need a test
1628   // TODO: Just specify the error.
1629   queso_require_less_msg(residual, tolerance, "Maximum num iterations exceeded");
1630 
1631   return;
1632 }
1633 
1634 void
getColumn(unsigned int column_num,GslVector & column)1635 GslMatrix::getColumn(unsigned int column_num, GslVector& column) const
1636 {
1637   // Sanity checks
1638   queso_require_less_msg(column_num, this->numCols(), "Specified row number not within range");
1639 
1640   queso_require_equal_to_msg(column.sizeLocal(), this->numRowsLocal(), "column vector not same size as this matrix");
1641 
1642   // Temporary working vector
1643   gsl_vector* gsl_column = gsl_vector_alloc( column.sizeLocal() );
1644 
1645   int error_code = gsl_matrix_get_col( gsl_column, m_mat, column_num );
1646   queso_require_equal_to_msg(error_code, 0, "gsl_matrix_get_col failed");
1647 
1648   // Copy column from gsl matrix into our GslVector object
1649   for( unsigned int i = 0; i < column.sizeLocal(); ++i )
1650     {
1651       column[i] = gsl_vector_get( gsl_column, i );
1652     }
1653 
1654   // Clean up gsl temporaries
1655   gsl_vector_free( gsl_column );
1656 
1657   return;
1658 }
1659 
1660 void
getRow(unsigned int row_num,GslVector & row)1661 GslMatrix::getRow(unsigned int row_num, GslVector& row) const
1662 {
1663   // Sanity checks
1664   queso_require_less_msg(row_num, this->numRowsLocal(), "Specified row number not within range");
1665 
1666   queso_require_equal_to_msg(row.sizeLocal(), this->numCols(), "row vector not same size as this matrix");
1667 
1668   // Temporary working vector
1669   gsl_vector* gsl_row = gsl_vector_alloc( row.sizeLocal() );
1670 
1671   int error_code = gsl_matrix_get_row( gsl_row, m_mat, row_num );
1672   queso_require_equal_to_msg(error_code, 0, "gsl_matrix_get_row failed");
1673 
1674   // Copy row from gsl matrix into our GslVector object
1675   for( unsigned int i = 0; i < row.sizeLocal(); ++i )
1676     {
1677       row[i] = gsl_vector_get( gsl_row, i );
1678     }
1679 
1680   // Clean up gsl temporaries
1681   gsl_vector_free( gsl_row );
1682 
1683   return;
1684 }
1685 
1686 GslVector
getRow(unsigned int row_num)1687 GslMatrix::getRow(unsigned int row_num ) const
1688 {
1689   // We rely on the void getRow's to do sanity checks
1690   // So we don't do them here.
1691 
1692   GslVector row(m_env, m_map);
1693 
1694   this->getRow( row_num, row );
1695 
1696   return row;
1697 }
1698 
1699 GslVector
getColumn(unsigned int column_num)1700 GslMatrix::getColumn(unsigned int column_num ) const
1701 {
1702   // We rely on the void getRow's to do sanity checks
1703   // So we don't do them here.
1704 
1705   GslVector column(m_env, m_map);
1706 
1707   this->getColumn( column_num, column );
1708 
1709   return column;
1710 }
1711 
1712 void
setRow(unsigned int row_num,const GslVector & row)1713 GslMatrix::setRow(unsigned int row_num, const GslVector& row)
1714 {
1715   this->reset();
1716   // Sanity checks
1717   queso_require_less_msg(row_num, this->numRowsLocal(), "Specified row number not within range");
1718 
1719   queso_require_equal_to_msg(row.sizeLocal(), this->numCols(), "row vector not same size as this matrix");
1720 
1721   gsl_vector* gsl_row = row.data();
1722 
1723   int error_code = gsl_matrix_set_row( m_mat, row_num, gsl_row );
1724   queso_require_equal_to_msg(error_code, 0, "gsl_matrix_set_row failed");
1725 
1726   return;
1727 }
1728 
1729 void
setColumn(unsigned int column_num,const GslVector & column)1730 GslMatrix::setColumn(unsigned int column_num, const GslVector& column)
1731 {
1732   this->reset();
1733   // Sanity checks
1734   queso_require_less_msg(column_num, this->numCols(), "Specified column number not within range");
1735 
1736   queso_require_equal_to_msg(column.sizeLocal(), this->numRowsLocal(), "column vector not same size as this matrix");
1737 
1738   gsl_vector* gsl_column = column.data();
1739 
1740   int error_code = gsl_matrix_set_col( m_mat, column_num, gsl_column );
1741   queso_require_equal_to_msg(error_code, 0, "gsl_matrix_set_col failed");
1742 
1743   return;
1744 }
1745 
1746 void
mpiSum(const MpiComm & comm,GslMatrix & M_global)1747 GslMatrix::mpiSum( const MpiComm& comm, GslMatrix& M_global ) const
1748 {
1749   // Sanity Checks
1750   UQ_FATAL_RC_MACRO(((this->numRowsLocal() != M_global.numRowsLocal()) ||
1751                      (this->numCols()      != M_global.numCols()     )),
1752 		    env().fullRank(),
1753 		    "GslMatrix::mpiSum()",
1754 		    "local and global matrices incompatible");
1755 
1756   /* TODO: Probably a better way to handle this unpacking/packing of data */
1757   int size = M_global.numRowsLocal()*M_global.numCols();
1758   std::vector<double> local( size, 0.0 );
1759   std::vector<double> global( size, 0.0 );
1760 
1761   int k;
1762   for( unsigned int i = 0; i < this->numRowsLocal(); i++ )
1763     {
1764       for( unsigned int j = 0; j < this->numCols(); j++ )
1765 	{
1766 	  k = i + j*M_global.numCols();
1767 
1768 	  local[k] = (*this)(i,j);
1769 	}
1770     }
1771 
1772   comm.Allreduce<double>(&local[0], &global[0], size, RawValue_MPI_SUM,
1773                  "GslMatrix::mpiSum()",
1774                  "failed MPI.Allreduce()");
1775 
1776   for( unsigned int i = 0; i < this->numRowsLocal(); i++ )
1777     {
1778       for( unsigned int j = 0; j < this->numCols(); j++ )
1779 	{
1780 	  k = i + j*M_global.numCols();
1781 
1782 	  M_global(i,j) = global[k];
1783 	}
1784     }
1785 
1786   return;
1787 }
1788 
1789 void
matlabLinearInterpExtrap(const GslVector & x1Vec,const GslMatrix & y1Mat,const GslVector & x2Vec)1790 GslMatrix::matlabLinearInterpExtrap(
1791   const GslVector& x1Vec,
1792   const GslMatrix& y1Mat,
1793   const GslVector& x2Vec)
1794 {
1795   queso_require_greater_msg(x1Vec.sizeLocal(), 1, "invalid 'x1' size");
1796 
1797   queso_require_equal_to_msg(x1Vec.sizeLocal(), y1Mat.numRowsLocal(), "invalid 'x1' and 'y1' sizes");
1798 
1799   queso_require_equal_to_msg(x2Vec.sizeLocal(), this->numRowsLocal(), "invalid 'x2' and 'this' sizes");
1800 
1801   queso_require_equal_to_msg(y1Mat.numCols(), this->numCols(), "invalid 'y1' and 'this' sizes");
1802 
1803   GslVector y1Vec(x1Vec);
1804   GslVector y2Vec(x2Vec);
1805   for (unsigned int colId = 0; colId < y1Mat.numCols(); ++colId) {
1806     y1Mat.getColumn(colId,y1Vec);
1807     y2Vec.matlabLinearInterpExtrap(x1Vec,y1Vec,x2Vec);
1808     this->setColumn(colId,y2Vec);
1809   }
1810 
1811   return;
1812 }
1813 
1814 gsl_matrix*
data()1815 GslMatrix::data()
1816 {
1817   return m_mat;
1818 }
1819 
1820 void
print(std::ostream & os)1821 GslMatrix::print(std::ostream& os) const
1822 {
1823   unsigned int nRows = this->numRowsLocal();
1824   unsigned int nCols = this->numCols();
1825 
1826   if (m_printHorizontally) {
1827     for (unsigned int i = 0; i < nRows; ++i) {
1828       for (unsigned int j = 0; j < nCols; ++j) {
1829         os << (*this)(i,j)
1830            << " ";
1831       }
1832       if (i != (nRows-1)) os << "; ";
1833     }
1834     //os << std::endl;
1835   }
1836   else {
1837     for (unsigned int i = 0; i < nRows; ++i) {
1838       for (unsigned int j = 0; j < nCols; ++j) {
1839         os << (*this)(i,j)
1840            << " ";
1841       }
1842       os << std::endl;
1843     }
1844   }
1845 
1846   return;
1847 }
1848 
1849 void
subWriteContents(const std::string & varNamePrefix,const std::string & fileName,const std::string & fileType,const std::set<unsigned int> & allowedSubEnvIds)1850 GslMatrix::subWriteContents(
1851   const std::string&            varNamePrefix,
1852   const std::string&            fileName,
1853   const std::string&            fileType,
1854   const std::set<unsigned int>& allowedSubEnvIds) const
1855 {
1856   queso_require_greater_equal_msg(m_env.subRank(), 0, "unexpected subRank");
1857 
1858   queso_require_less_equal_msg(this->numOfProcsForStorage(), 1, "implemented just for sequential vectors for now");
1859 
1860   FilePtrSetStruct filePtrSet;
1861   if (m_env.openOutputFile(fileName,
1862                            fileType, // "m or hdf"
1863                            allowedSubEnvIds,
1864                            false,
1865                            filePtrSet)) {
1866     unsigned int nRows = this->numRowsLocal();
1867     unsigned int nCols = this->numCols();
1868     *filePtrSet.ofsVar << varNamePrefix << "_sub" << m_env.subIdString() << " = zeros(" << nRows
1869                        << ","                                                           << nCols
1870                        << ");"
1871                        << std::endl;
1872     *filePtrSet.ofsVar << varNamePrefix << "_sub" << m_env.subIdString() << " = [";
1873 
1874     for (unsigned int i = 0; i < nRows; ++i) {
1875       for (unsigned int j = 0; j < nCols; ++j) {
1876         *filePtrSet.ofsVar << (*this)(i,j)
1877                 << " ";
1878       }
1879       *filePtrSet.ofsVar << "\n";
1880     }
1881     *filePtrSet.ofsVar << "];\n";
1882 
1883     m_env.closeFile(filePtrSet,fileType);
1884   }
1885 
1886   return;
1887 }
1888 
1889 void
subReadContents(const std::string & fileName,const std::string & fileType,const std::set<unsigned int> & allowedSubEnvIds)1890 GslMatrix::subReadContents(
1891   const std::string&            fileName,
1892   const std::string&            fileType,
1893   const std::set<unsigned int>& allowedSubEnvIds)
1894 {
1895   queso_require_greater_equal_msg(m_env.subRank(), 0, "unexpected subRank");
1896 
1897   queso_require_less_equal_msg(this->numOfProcsForStorage(), 1, "implemented just for sequential vectors for now");
1898 
1899   FilePtrSetStruct filePtrSet;
1900   if (m_env.openInputFile(fileName,
1901                           fileType, // "m or hdf"
1902                           allowedSubEnvIds,
1903                           filePtrSet)) {
1904 
1905     // palms
1906     unsigned int nRowsLocal = this->numRowsLocal();
1907 
1908     // In the logic below, the id of a line' begins with value 0 (zero)
1909     unsigned int idOfMyFirstLine = 1;
1910     unsigned int idOfMyLastLine = nRowsLocal;
1911     unsigned int nCols = this->numCols();
1912 
1913     // Read number of matrix rows in the file by taking care of the first line,
1914     // which resembles something like 'variable_name = zeros(n_rows,n_cols);'
1915     std::string tmpString;
1916 
1917     // Read 'variable name' string
1918     *filePtrSet.ifsVar >> tmpString;
1919     //std::cout << "Just read '" << tmpString << "'" << std::endl;
1920 
1921     // Read '=' sign
1922     *filePtrSet.ifsVar >> tmpString;
1923     //std::cout << "Just read '" << tmpString << "'" << std::endl;
1924     queso_require_equal_to_msg(tmpString, std::string("="), std::string("string should be the '=' sign"));
1925 
1926     // Read 'zeros(n_rows,n_cols)' string
1927     *filePtrSet.ifsVar >> tmpString;
1928     //std::cout << "Just read '" << tmpString << "'" << std::endl;
1929     unsigned int posInTmpString = 6;
1930 
1931     // Isolate 'n_rows' in a string
1932     std::string nRowsString(tmpString.size()-posInTmpString+1, ' ');
1933     unsigned int posInRowsString = 0;
1934     do {
1935       queso_require_less_msg(posInTmpString, tmpString.size(), "symbol ',' not found in first line of file");
1936       nRowsString[posInRowsString++] = tmpString[posInTmpString++];
1937     } while (tmpString[posInTmpString] != ',');
1938     nRowsString[posInRowsString] = '\0';
1939 
1940     // Isolate 'n_cols' in a string
1941     posInTmpString++; // Avoid reading ',' char
1942     std::string nColsString(tmpString.size()-posInTmpString+1, ' ');
1943     unsigned int posInColsString = 0;
1944     do {
1945       queso_require_less_msg(posInTmpString, tmpString.size(), "symbol ')' not found in first line of file");
1946       nColsString[posInColsString++] = tmpString[posInTmpString++];
1947     } while (tmpString[posInTmpString] != ')');
1948     nColsString[posInColsString] = '\0';
1949 
1950     // Convert 'n_rows' and 'n_cols' strings to numbers
1951     unsigned int numRowsInFile = (unsigned int) strtod(nRowsString.c_str(),NULL);
1952     unsigned int numColsInFile = (unsigned int) strtod(nColsString.c_str(),NULL);
1953     if (m_env.subDisplayFile()) {
1954       *m_env.subDisplayFile() << "In GslMatrix::subReadContents()"
1955                               << ": fullRank "        << m_env.fullRank()
1956                               << ", numRowsInFile = " << numRowsInFile
1957                               << ", numColsInFile = " << numColsInFile
1958                               << ", nRowsLocal = "    << nRowsLocal
1959                               << ", nCols = "         << nCols
1960                               << std::endl;
1961     }
1962 
1963     // Check if [num of rows in file] == [requested matrix row size]
1964     queso_require_equal_to_msg(numRowsInFile, nRowsLocal, "size of vec in file is not big enough");
1965 
1966     // Check if [num of cols in file] == [num cols in current matrix]
1967     queso_require_equal_to_msg(numColsInFile, nCols, "number of parameters of vec in file is different than number of parameters in this vec object");
1968 
1969     // Code common to any core in a communicator
1970     unsigned int maxCharsPerLine = 64*nCols; // Up to about 60 characters to represent each parameter value
1971 
1972     unsigned int lineId = 0;
1973     while (lineId < idOfMyFirstLine) {
1974       filePtrSet.ifsVar->ignore(maxCharsPerLine,'\n');
1975       lineId++;
1976     };
1977 
1978     if (m_env.subDisplayFile()) {
1979       *m_env.subDisplayFile() << "In GslMatrix::subReadContents()"
1980                               << ": beginning to read input actual data"
1981                               << std::endl;
1982     }
1983 
1984     // Take care of initial part of the first data line,
1985     // which resembles something like 'variable_name = [value1 value2 ...'
1986     // Read 'variable name' string
1987     *filePtrSet.ifsVar >> tmpString;
1988     //std::cout << "Core 0 just read '" << tmpString << "'" << std::endl;
1989 
1990     // Read '=' sign
1991     *filePtrSet.ifsVar >> tmpString;
1992     //std::cout << "Core 0 just read '" << tmpString << "'" << std::endl;
1993     queso_require_equal_to_msg(tmpString, std::string("="), std::string("in core 0, string should be the '=' sign"));
1994 
1995     // Take into account the ' [' portion
1996     std::streampos tmpPos = filePtrSet.ifsVar->tellg();
1997     filePtrSet.ifsVar->seekg(tmpPos+(std::streampos)2);
1998 
1999     if (m_env.subDisplayFile()) {
2000       *m_env.subDisplayFile() << "In GslMatrix::subReadContents()"
2001                               << ": beginning to read lines with numbers only"
2002                               << ", lineId = "          << lineId
2003                               << ", idOfMyFirstLine = " << idOfMyFirstLine
2004                               << ", idOfMyLastLine = "  << idOfMyLastLine
2005                               << std::endl;
2006     }
2007 
2008     double tmpRead;
2009     while (lineId <= idOfMyLastLine) {
2010       for (unsigned int j = 0; j < nCols; ++j) {
2011         *filePtrSet.ifsVar >> tmpRead;
2012         (*this)(lineId-idOfMyFirstLine,j) = tmpRead;
2013       }
2014       lineId++;
2015     };
2016 
2017     m_env.closeFile(filePtrSet,fileType);
2018   }
2019 
2020   return;
2021 }
2022 
2023 std::ostream&
2024 operator<<(std::ostream& os, const GslMatrix& obj)
2025 {
2026   obj.print(os);
2027 
2028   return os;
2029 }
2030 
2031 GslMatrix operator*(double a, const GslMatrix& mat)
2032 {
2033   GslMatrix answer(mat);
2034   answer *= a;
2035   return answer;
2036 }
2037 
2038 GslVector operator*(const GslMatrix& mat, const GslVector& vec)
2039 {
2040   return mat.multiply(vec);
2041 }
2042 
2043 GslMatrix operator*(const GslMatrix& m1, const GslMatrix& m2)
2044 {
2045   unsigned int m1Rows = m1.numRowsLocal();
2046   unsigned int m1Cols = m1.numCols();
2047   unsigned int m2Rows = m2.numRowsLocal();
2048   unsigned int m2Cols = m2.numCols();
2049 
2050   queso_require_equal_to_msg(m1Cols, m2Rows, "different sizes m1Cols and m2Rows");
2051 
2052   GslMatrix mat(m1.env(),m1.map(),m2Cols);
2053 
2054   //std::cout << "In GslMatrix(mat * mat): m1Cols = " << m1Cols << std::endl;
2055 
2056   unsigned int commonSize = m1Cols;
2057   for (unsigned int row1 = 0; row1 < m1Rows; ++row1) {
2058     for (unsigned int col2 = 0; col2 < m2Cols; ++col2) {
2059       double result = 0.;
2060       for (unsigned int k = 0; k < commonSize; ++k) {
2061         result += m1(row1,k)*m2(k,col2);
2062       }
2063       mat(row1,col2) = result;
2064     }
2065     //std::cout << "In GslMatrix(mat * mat): ended row " << row1 << std::endl;
2066   }
2067 
2068   return mat;
2069 }
2070 
2071 GslMatrix operator+(const GslMatrix& m1, const GslMatrix& m2)
2072 {
2073   GslMatrix answer(m1);
2074   answer += m2;
2075   return answer;
2076 }
2077 
2078 GslMatrix operator-(const GslMatrix& m1, const GslMatrix& m2)
2079 {
2080   GslMatrix answer(m1);
2081   answer -= m2;
2082   return answer;
2083 }
2084 
matrixProduct(const GslVector & v1,const GslVector & v2)2085 GslMatrix matrixProduct(const GslVector& v1, const GslVector& v2)
2086 {
2087   unsigned int nRows = v1.sizeLocal();
2088   unsigned int nCols = v2.sizeLocal();
2089   GslMatrix answer(v1.env(),v1.map(),nCols);
2090 
2091   for (unsigned int i = 0; i < nRows; ++i) {
2092     double value1 = v1[i];
2093     for (unsigned int j = 0; j < nCols; ++j) {
2094       answer(i,j) = value1*v2[j];
2095     }
2096   }
2097 
2098   return answer;
2099 }
2100 
leftDiagScaling(const GslVector & vec,const GslMatrix & mat)2101 GslMatrix leftDiagScaling(const GslVector& vec, const GslMatrix& mat)
2102 {
2103   unsigned int vSize = vec.sizeLocal();
2104   unsigned int mRows = mat.numRowsLocal();
2105   unsigned int mCols = mat.numCols();
2106 
2107   queso_require_equal_to_msg(vSize, mRows, "size of vector is different from the number of rows in matrix");
2108 
2109   queso_require_equal_to_msg(mCols, mRows, "routine currently works for square matrices only");
2110 
2111   GslMatrix answer(mat);
2112   for (unsigned int i = 0; i < mRows; ++i) {
2113     double vecValue = vec[i];
2114     for (unsigned int j = 0; j < mCols; ++j) {
2115       answer(i,j) *= vecValue;
2116     }
2117   }
2118 
2119   return answer;
2120 }
2121 
rightDiagScaling(const GslMatrix & mat,const GslVector & vec)2122 GslMatrix rightDiagScaling(const GslMatrix& mat, const GslVector& vec)
2123 {
2124   unsigned int vSize = vec.sizeLocal();
2125   unsigned int mRows = mat.numRowsLocal();
2126   unsigned int mCols = mat.numCols();
2127 
2128   queso_require_equal_to_msg(vSize, mCols, "size of vector is different from the number of cols in matrix");
2129 
2130   queso_require_equal_to_msg(mCols, mRows, "routine currently works for square matrices only");
2131 
2132   GslMatrix answer(mat);
2133   for (unsigned int j = 0; j < mCols; ++j) {
2134     double vecValue = vec[j];
2135     for (unsigned int i = 0; i < mRows; ++i) {
2136       answer(i,j) *= vecValue;
2137     }
2138   }
2139 
2140   return answer;
2141 }
2142 
2143 }  // End namespace QUESO
2144