1 /*
2 XLiFE++ issue an extended library of finite elements written in C++
3   Copyright (C) 2014  Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4 
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13   You should have received a copy of the GNU General Public License
14   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 /*!
18   \file LargeMatrix.hpp
19   \author E. Lunéville, M.-H. Nguyen
20   \since 24 jun 2012
21   \date 6 Juin 2014
22 
23   \brief Definition of the xlifepp::LargeMatrix class
24 
25   Class to deal with large matrices. This class mainly handles a vector of values
26   and a pointer to a storage (see storage classes). Algorithms are defined in storage classes
27   The class is templated by the type of the values real/complex scalar/vector/matrix
28 
29   IMPORTANT NOTE : by convenience, the first adress of values_ vector (say values_[0]) always exists and contains the 0 value of type T
30   the actual matrix values begins at adress 1
31 */
32 
33 #ifndef LARGE_MATRIX_HPP
34 #define LARGE_MATRIX_HPP
35 
36 #include "config.h"
37 #ifdef XLIFEPP_WITH_UMFPACK
38 #include "umfpackSupport.h"
39 #endif
40 #include "MatrixStorage.hpp"
41 #include "denseStorage/DenseStorage.hpp"
42 #include "denseStorage/ColDenseStorage.hpp"
43 #include "denseStorage/RowDenseStorage.hpp"
44 #include "denseStorage/DualDenseStorage.hpp"
45 #include "denseStorage/SymDenseStorage.hpp"
46 #include "csStorage/CsStorage.hpp"
47 #include "csStorage/ColCsStorage.hpp"
48 #include "csStorage/RowCsStorage.hpp"
49 #include "csStorage/DualCsStorage.hpp"
50 #include "csStorage/SymCsStorage.hpp"
51 #include "skylineStorage/DualSkylineStorage.hpp"
52 #include "skylineStorage/SymSkylineStorage.hpp"
53 #include "eigenSolvers.h"
54 #include "eigenSparseInterface/LargeMatrixAdapter.hpp"
55 #include "eigenSparseInterface/LargeMatrixAdapterInverse.hpp"
56 #include "eigenSparseInterface/LargeMatrixAdapterInverseGeneralized.hpp"
57 #include "eigenSparseInterface/MultiVectorAdapter.hpp"
58 #include "../arpackppSupport/arpackSolve.hpp"
59 #include "utils.h"
60 
61 namespace xlifepp
62 {
63 
64 /*!
65   \struct LargeMatrixTrait
66   A small struct to deal with type of scalar (real, complex) of LargeMatrix
67 */
68 template<typename K>
69 struct LargeMatrixTrait
70 {};
71 
72 #ifndef DOXYGEN_SHOULD_SKIP_THIS
73 
74 template<>
75 struct LargeMatrixTrait<real_t>
76 {
77   typedef real_t ScalarType;
78 };
79 
80 template<>
81 struct LargeMatrixTrait<complex_t>
82 {
83   typedef complex_t ScalarType;
84 };
85 
86 template<>
87 struct LargeMatrixTrait<Matrix<real_t> >
88 {
89   typedef real_t ScalarType;
90 };
91 
92 template<>
93 struct LargeMatrixTrait<Matrix<complex_t> >
94 {
95   typedef complex_t ScalarType;
96 };
97 
98 #endif
99 
100 //-----------------------------------------------------------------------------------------
101 /*!
102    \class LargeMatrix
103    templated class to deal with large matrices,
104    it handles a vector of values (non zero coefficients) and a pointer to a MatrixStorage
105  */
106 //-----------------------------------------------------------------------------------------
107 template <typename T>
108 class LargeMatrix
109 {
110 public:
111   ValueType valueType_;     //!< type of values (real, complex)
112   StrucType strucType;      //!< struc of values (scalar, vector, matrix)
113   number_t nbRows;          //!< number of rows counted in T
114   number_t nbCols;          //!< number of columns counted in T
115   SymType sym;              //!< type of symmetry
116   dimen_t nbRowsSub;        //!< number of rows of submatrices (1 if scalar values)
117   dimen_t nbColsSub;        //!< number of columns cof submatrices (1 if scalar values)
118   string_t name;            //!< optionnal name, useful for documentation
119 
120   //for factorized form
121   FactorizationType factorization_;     //!< one of _noFactorization, _lu, _ldlt, _ldlstar, _llt, _llstar, _qr, _umfpack
122   std::vector<number_t> rowPermutation_;//!< row permutation given by some factorizations (LU in row dense storage for instance)
123   std::vector<number_t> colPermutation_;//!< col permutation given by some factorizations (LU in col dense storage for instance)
124 #ifdef XLIFEPP_WITH_UMFPACK
125   UmfPackLU<LargeMatrix<T> >* umfLU_p;  //!< pointer to store LU factors built by UmfPack
126 #endif
127 
128   typedef typename LargeMatrixTrait<T>::ScalarType ScalarType; //!< useful typedef for LargeMatrix class
129 
130 protected:
131   std::vector<T> values_;   //!< list of values ordered along storage choice
132   MatrixStorage* storage_p; //!< pointer to the matrix storage
133   void allocateStorage(StorageType sto, AccessType at, const T& val = T());  //!< allocate storage if not exists
134   void setType(const T&);                                                    //!< initialize type of matrix elements
135 
136 public:
137   // constructors, destructor
138   LargeMatrix();                                                             //!< default constructor
139   LargeMatrix(ValueType vt,StrucType st, number_t nbr, number_t nbc, SymType sy,
140               dimen_t nbrs, dimen_t nbcs, const T& val, const string_t& na, MatrixStorage* sp=0);  //!< explicit constructor
141   //LargeMatrix(const LargeMatrix<T>&);                                      //!< copy constructor (shadow copy)
142   LargeMatrix(const LargeMatrix<T>&, bool storageCopy = false);              //!< copy constructor (shadow copy), with option to copy or not the storage
143   template<typename K> LargeMatrix(const LargeMatrix<K>&, bool storageCopy = false); //!< generalized copy constructor (shallow copy), with option to copy or not the storage
144 
145   LargeMatrix(MatrixStorage*, const T& val = T(0), SymType sy = _noSymmetry);//!< construct matrix from storage and constant value
146   LargeMatrix(MatrixStorage* ms, dimPair dims, SymType sy = _noSymmetry);    //!< construct matrix from storage and symmetry type (matrix values)
147   LargeMatrix(MatrixStorage*, SymType);                                      //!< construct matrix from storage and symmetry type (scalar values assumed)
148   ~LargeMatrix();                                                            //!< destructor
149   //! construct matrix from dimensions, storage type and a constant value
150   LargeMatrix(number_t nr, number_t nc, StorageType sto = _dense, AccessType at = _row, const T& val = T());
151   //! construct "symmetric" matrix from dimensions, storage type, symmetry type a constant value
152   LargeMatrix(number_t nr, number_t nc, StorageType sto = _dense, SymType = _symmetric, const T& val = T());
153   //! construct matrix from file
154   LargeMatrix(const string_t& fn, StorageType fst, number_t nr, number_t nc, StorageType sto = _dense, AccessType at = _row, number_t nsr = 1, number_t nsc = 1);
155   //! construct "symmetric" matrix from file
156   LargeMatrix(const string_t& fn, StorageType fst, number_t nr, StorageType sto = _dense, SymType sy = _symmetric, number_t nsr = 1);
157   //! construct Special matrix (diagonal)
158   LargeMatrix(SpecialMatrix sp, StorageType st, AccessType at, number_t nbr, number_t nbc, const T v);
159 
160   void init(MatrixStorage* ms, const T& val, SymType sy); //!< initialize matrix from storage
161   void clearall();         //!< clear values and storage pointer (not the attributes)
clear()162   void clear()             //! deallocate memory used by matrix values, storage is not deallocated!
163   {
164     if(Trace::traceMemory)
165       {
166         thePrintStream<<"LargeMatrix::clear de-allocates a large matrix : "<<&values_<<", "
167                       <<values_.size()<<" non zeros coefficients "<<dimValues();
168         if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
169         thePrintStream<<eol<<std::flush;
170       }
171     std::vector<T> empty;
172     values_.swap(empty);
173   }
174 
175   LargeMatrix<T>& operator=(const LargeMatrix<T>&); //!< assign operator
176   template<typename K> LargeMatrix<T>& operator=(const LargeMatrix<K>&); //!< generalized assign operator
177 
178   // various utilities
valueType() const179   ValueType valueType() const                //! return type of values (real, complex)
180   {
181     return valueType_;
182   }
183 
values()184   std::vector<T>& values()                   //! access to values
185   {
186     return values_;
187   }
188 
values() const189   const std::vector<T>& values() const       //! access to values (const)
190   {
191     return values_;
192   }
193 
numberOfRows() const194   number_t numberOfRows() const              //! return number of rows counted in T
195   {
196     return nbRows;
197   }
198 
numberOfCols() const199   number_t numberOfCols() const              //! return number of columns counted in T
200   {
201     return nbCols;
202   }
203 
symmetry() const204   SymType symmetry() const                   //! return kind of symmetry
205   {
206     return sym;
207   }
208 
dimValues() const209   dimPair dimValues() const                  //! return dimensions of values, (1,1) when scalar
210   {
211     return dimPair(nbRowsSub, nbColsSub);
212   }
213 
storageType() const214   StorageType storageType() const            //! return the storage type
215   {
216     return storage_p->storageType();
217   }
218 
accessType() const219   AccessType accessType() const              //! return the access type
220   {
221     return storage_p->accessType();
222   }
223 
storagep() const224   MatrixStorage* storagep() const            //! return the storage pointer (const)
225   {
226     return storage_p;
227   }
228 
storagep()229   MatrixStorage*& storagep()                 //! return the storage pointer
230   {
231     return storage_p;
232   }
233 
nbNonZero() const234   number_t nbNonZero() const                 //! number of non zero coefficients stored (given by storage)
235   {
236     return values_.size() - 1;
237   }
238 
resetZero()239   void resetZero()                           //! reset first value to 0
240   {
241     values_[0] *= 0.;
242   }
243 
244   //access to values or addresses of values
operator ()(number_t i,number_t j) const245   T operator()(number_t i, number_t j) const //! access to entry (i,j) (do not use in heavy computation)
246   {
247     return get(i,j);
248   }
249 
get(number_t i,number_t j) const250   T get(number_t i, number_t j) const //! access to entry (i,j) (do not use in heavy computation)
251   {
252     if(sym!=_noSymmetry && storage_p->accessType()==_sym)
253       switch(sym)
254         {
255         case _skewSymmetric :
256           return -values_[storage_p->pos(i, j, sym)];
257           break;
258         case _selfAdjoint   :
259           return conj(values_[storage_p->pos(i, j, sym)]);
260           break;
261         case _skewAdjoint   :
262           return -conj(values_[storage_p->pos(i, j, sym)]);
263           break;
264         default :
265           return values_[storage_p->pos(i, j, sym)];
266         }
267     return values_[storage_p->pos(i, j, sym)];
268   }
269 
operator ()(number_t i,number_t j,bool errorOn=false)270   T& operator()(number_t i, number_t j, bool errorOn=false) //! access to entry (i,j) with check (do not use in heavy computation)
271   {
272     number_t posij = storage_p->pos(i, j, sym);
273     if(errorOn)
274       if(posij == 0 || (sym!=_noSymmetry && storage_p->accessType()==_sym && j>i))
275         {
276           error("largematrix_indicesout", name, i, j);
277         }
278     return values_[posij];
279   }
280 
pos(number_t i,number_t j) const281   number_t pos(number_t i, number_t j) const
282   {
283     return storage_p->pos(i, j, sym);
284   }
285 
getCol(number_t c,number_t r1=1,number_t r2=0) const286   std::vector<std::pair<number_t, number_t> > getCol(number_t c, number_t r1=1, number_t r2=0) const //! get (row indices, adresses) of col c in set [r1,r2] (r2=0 means nbOfRows)
287   {
288     return storage_p->getCol(sym,c,r1,r2);
289   }
290 
getRow(number_t r,number_t c1=1,number_t c2=0) const291   std::vector<std::pair<number_t, number_t> > getRow(number_t r, number_t c1=1, number_t c2=0) const //! /! get (col indices, adresses) of row r in set [c1,c2] (c2=0 means nbOfCols)
292   {
293     return storage_p->getRow(sym,r,c1,c2);
294   }
295 
296   std::vector<T> col(number_t c) const;       //!< get col c (>=1) as vector
297   std::vector<T> row(number_t r) const;       //!< get row r (>=1) as vector
298 
operator ()(number_t adr) const299   T operator()(number_t adr) const              //! access to entry at adress adr
300   {
301     return values_[adr];
302   }
303 
operator ()(number_t adr)304   T& operator()(number_t adr)                   //! access to entry at adress adr
305   {
306     return values_[adr];
307   }
308 
at(number_t i,number_t j)309   typename std::vector<T>::iterator at(number_t i, number_t j)
310   {
311     number_t p=pos(i,j);
312     if(p>0) return values_.begin()+ p;
313     else return values_.end();
314   }
315 
at(number_t i,number_t j) const316   typename std::vector<T>::const_iterator at(number_t i, number_t j) const
317   {
318     number_t p=pos(i,j);
319     if(p>0) return values_.begin()+ p;
320     else return values_.end();
321   }
322 
323   // give the positions in storage of a submatrix given by its row and column index
324   // the matrix of positions (adrs) are returned in a vector (row matrix storage)
325   // as xlifepp::Matrix inherits from std::vector, it can be used as input argument
326   // if errorOn is true, indices out of storage raises an error
positions(const std::vector<number_t> & rows,const std::vector<number_t> & cols,std::vector<number_t> & adrs,bool errorOn=false) const327   void positions(const std::vector<number_t>& rows, const std::vector<number_t>& cols,
328                  std::vector<number_t>& adrs, bool errorOn=false) const //! positions in storage of a submatrix
329   {
330     storage_p->positions(rows, cols, adrs, errorOn, sym);
331   }
332 
333   //removing operation
334   void deleteRows(number_t, number_t);             //!< delete rows r1,..., r2 (may be expansive for some storage)
335   void deleteCols(number_t, number_t);             //!< delete cols c1,..., c2 (may be expansive for some storage)
336   void setColToZero(number_t c1=0, number_t c2=0); //!< set to 0 cols c1,..., c2 (index start from 1), no col deletion
337   void setRowToZero(number_t r1=0, number_t r2=0); //!< set to 0 rows r1,..., r2 (index start from 1), no row deletion
338 
339   //storage conversion
340   void toSkyline();                         //!< convert current matrix storage to skyline storage
341   void toStorage(MatrixStorage*);           //!< convert current matrix storage to an other matrix storage
342   template<typename K>
343   LargeMatrix<K>* toScalar(K);              //!< create new scalar matrix entry from non scalar matrix entry
344   template <typename K>
345   void toScalarEntries(const std::vector<Matrix<K> >&, std::vector<K>&, const MatrixStorage&); //!< copy matrix values to scalar values
346   void toUnsymmetric(AccessType at=_sym);      //!< convert current matrix to unsymmetric representation if it has a symmetric one
347   bool isDiagonal() const;                     //!< true if matrix is in fact diagonal
348   bool isId(const double & tol=0.) const;      //!< true if matrix is in fact id with a tolerance
349   void roundToZero(real_t aszero=10*theEpsilon); //!< round to 0 all coefficients smaller (in norm) than a aszero, storage is not modified
350   LargeMatrix<T>& toConj();                      //!< conjugate matrix
351 
352   void extract2UmfPack(std::vector<int_t>& colPointer, std::vector<int_t>& rowIndex, std::vector<T>& matA) const;   //!< extract and convert largeMatrix (and its storage) to Umfpack
353   bool getCsColUmfPack(std::vector<int_t>& colPointer, std::vector<int_t>& rowIndex, const T*& matA) const;         //!< get largeMatrix and its storage to Umfpack (only for cs col)
354 
355   LargeMatrix<T>* extract(const std::vector<number_t>& rowIndex,
356                           const std::vector<number_t>& colIndex) const;              //!< extract LargeMatrix from current LargeMatrix (return a pointer to LargeMatrix)
357   LargeMatrix<T>* extract(number_t r1, number_t r2, number_t c1, number_t c2) const; //!< extract LargeMatrix from current LargeMatrix (return a pointer to LargeMatrix)
358 
359   // algebraic utilities
360   template<typename iterator>
361   LargeMatrix<T>& add(iterator&,iterator&);                            //!< add values given by iterator from beginning
362   LargeMatrix<T>& add(const std::vector<T>&, const std::vector<number_t>&,
363                       const std::vector<number_t>&);                     //!< add a matrix at ranks (rows, cols)
364   LargeMatrix<T>& add(const T& c, const std::vector<number_t>& rows,
365                       const std::vector<number_t>& cols);                //!< add a constant to submatrix given by its ranks (rows, cols)
366   template <typename K, typename C>
367   LargeMatrix<T>& add(const LargeMatrix<K>&,
368                       const std::vector<number_t>&,
369                       const std::vector<number_t>&, C);                  //!< add scaled LargeMatrix at ranks (rows, cols) of current LargeMatrix
370   void addColToCol(number_t c1, number_t c2, complex_t a, bool updateStorage=false); //!< combine cols of matrix : c2 = c2 + a *c1 (indices start from 1) with update storage option
371   void addRowToRow(number_t r1, number_t r2, complex_t a, bool updateStorage=false); //!< combine rows of matrix : r2 = r2 + a *r1 (indices start from 1) with update storage option
372   void copyVal(const LargeMatrix<T>&, const std::vector<number_t>&,
373                const std::vector<number_t>&);                                    //!< copy in current matrix values of mat located at mat_adrs at position cur_adrs
374   template <typename K>
375   LargeMatrix<T>& assign(const LargeMatrix<K>&, const std::vector<number_t>&, const std::vector<number_t>&); //!< assign LargeMatrix at ranks (rows, cols) to current LargeMatrix
376 
377   template<typename K> LargeMatrix<T>& operator*=(const K&);           //!< LargeMatrix<T> *= v
378   template<typename K> LargeMatrix<T>& operator/=(const K&);           //!< LargeMatrix<T> /= v
379   LargeMatrix<T>& operator+=(const LargeMatrix<T>&);                   //!< LargeMatrix<T> += LargeMatrix<T>
380   LargeMatrix<T>& operator-=(const LargeMatrix<T>&);                   //!< LargeMatrix<T> -= LargeMatrix<T>
381 
382   real_t norm2() const;                                                //!< Frobenius norm of a LargeMatrix
383   real_t norminfty() const;                                            //!< infinite norm of a LargeMatrix
384   real_t partialNormOfCol(number_t c, number_t r1, number_t r2) const; //!< partial norm of column c, only components in range [r1,r2]
squaredNorm() const385   real_t squaredNorm() const                                           //! square of Frobenius norm of a LargeMatrix
386   {
387     real_t n=norm2();
388     return n*n;
389   }
390 
391   void ldltFactorize();                        //!< Factorization LDLt
392   void ldlstarFactorize();                     //!< Factorization LDL*
393   void luFactorize(bool withPermutation=true); //!< Factorization LU
394   void iluFactorize();                         //!< Incomplete Factorization LU
395   void ildltFactorize();                       //!< Incomplete Factorization LDLt
396   void illtFactorize();                        //!< Incomplete Factorization LLt
397   void ildlstarFactorize();                    //!< Incomplete Factorization LDL*
398   void illstarFactorize();                     //!< Incomplete Factorization LL*
399   void umfpackFactorize();                     //!< Factorization using umfpack
400 
401   void multMatrixCol(T* pM, T* pR, number_t p) const;     //!< product LargeMatrix * dense col matrix passed as pointer
402   void multLeftMatrixCol(T* pM, T* pR, number_t p) const; //!< product dense col matrix * LargeMatrix passed as pointer
403   void multMatrixRow(T* pM, T* pR, number_t p) const;     //!< product LargeMatrix * dense row matrix passed as pointer
404   void multLeftMatrixRow(T* pM, T* pR, number_t p) const; //!< product dense row matrix * LargeMatrix passed as pointer
405 
406   // extern templated product matrix*vector and "specializations" real_t/complex_t and Scalar/Vector/Matrix
407   template <typename S, typename V, typename R>
408   friend void multMatrixVector(const LargeMatrix<S>& mat, V*, R*);
409   template <typename S>
410   friend void multMatrixVector(const LargeMatrix<S>& mat, const std::vector<S>& vec, std::vector<S>& res);
411   template <typename S>
412   friend void multMatrixVector(const LargeMatrix<Matrix<S> >& mat, const std::vector<Vector<S> >& vec, std::vector<Vector<S> >& res);
413   friend void multMatrixVector(const LargeMatrix<complex_t>& mat, const std::vector<real_t>& vec, std::vector<complex_t>& res);
414   friend void multMatrixVector(const LargeMatrix<real_t>& mat, const std::vector<complex_t>& vec, std::vector<complex_t>& res);
415   template <typename S>
416   friend void multMatrixVector(const LargeMatrix<Matrix<S> >& mat, const std::vector<Vector<S> >& vec, std::vector<Vector<S> >& res);
417   friend void multMatrixVector(const LargeMatrix<Matrix<complex_t> >& mat, const std::vector<Vector<real_t> >& vec, std::vector<Vector<complex_t> >& res);
418   friend void multMatrixVector(const LargeMatrix<Matrix<real_t> >& mat, const std::vector<Vector<complex_t> >& vec, std::vector<Vector<complex_t> >& res);
419 
420   // extern templated product vector*matrix and "specializations" real_t/complex_t and Scalar/Vector/Matrix
421   template <typename S, typename V, typename R>
422   friend void multVectorMatrix(V*, const LargeMatrix<S>& mat, R*);
423   template <typename S>
424   friend void multVectorMatrix(const std::vector<S>& vec, const LargeMatrix<S>& mat, std::vector<S>& res);
425   friend void multVectorMatrix(const std::vector<real_t>& vec, const LargeMatrix<complex_t>& mat, std::vector<complex_t>& res);
426   friend void multVectorMatrix(const std::vector<complex_t>& vec, const LargeMatrix<real_t>& mat, std::vector<complex_t>& res);
427   template <typename S>
428   friend void multVectorMatrix(const std::vector<Vector<S> >& vec, const LargeMatrix<Matrix<S> >& mat, std::vector<Vector<S> >& res);
429   friend void multVectorMatrix(const std::vector<Vector<real_t> >& vec, const LargeMatrix<Matrix<complex_t> >& mat, std::vector<Vector<complex_t> >& res);
430   friend void multVectorMatrix(const std::vector<Vector<complex_t> >& vec, const LargeMatrix<Matrix<real_t> >& mat, std::vector<Vector<complex_t> >& res);
431   template <typename S, typename V, typename R>
432   friend void multVectorMatrix(const LargeMatrix<S>& mat, V*, R*);
433   template <typename S>
434   friend void multVectorMatrix(const LargeMatrix<S>& mat, const std::vector<S>& vec, std::vector<S>& res);
435   friend void multVectorMatrix(const LargeMatrix<complex_t>& mat, const std::vector<real_t>& vec, std::vector<complex_t>& res);
436   friend void multVectorMatrix(const LargeMatrix<real_t>& mat, const std::vector<complex_t>& vec, std::vector<complex_t>& res);
437   template <typename S>
438   friend void multVectorMatrix(const LargeMatrix<Matrix<S> >& mat, const std::vector<Vector<S> >& vec, std::vector<Vector<S> >& res);
439   friend void multVectorMatrix(const LargeMatrix<Matrix<complex_t> >& mat, const std::vector<Vector<real_t> >& vec, std::vector<Vector<complex_t> >& res);
440   friend void multVectorMatrix(const LargeMatrix<Matrix<real_t> >& mat, const std::vector<Vector<complex_t> >& vec, std::vector<Vector<complex_t> >& res);
441 
442   // LargeMatrix MUST be FACTORIZED before being used
443   template <typename S1, typename S2, typename S3>
444   friend void multFactMatrixVector(const LargeMatrix<S1>& mat, const std::vector<S2>& vec, std::vector<S3>& res);
445   template <typename S1, typename S2, typename S3>
446   friend void multVectorFactMatrix(const LargeMatrix<S1>& mat, const std::vector<S2>& vec, std::vector<S3>& res);
447   template<typename S1, typename S2>
448   friend void multInverMatrixVector(const LargeMatrix<S1>& mat, const std::vector<S2>& vec,
449                                     std::vector<typename Conditional<NumTraits<S1>::IsComplex, S1, S2>::type>& res,
450                                     FactorizationType fac);
451 
452   // extern template product matrix*matrix and "specializations" real_t/complex_t and Scalar/Matrix
453   template <typename SA, typename SB, typename SR>
454   friend void multMatrixMatrix(const LargeMatrix<SA>&, const LargeMatrix<SB>&, LargeMatrix<SR>&);
455   template <typename SA, typename SB, typename SR>
456   friend void multMatrixMatrix(const LargeMatrix<SA>&, const std::vector<SB>&, LargeMatrix<SR>&);
457   template <typename SA, typename SB, typename SR>
458   friend void multMatrixMatrix(const std::vector<SA>&, const LargeMatrix<SB>&, LargeMatrix<SR>&);
459 
460   //! templated factorization LDLt solver
461   template<typename S1, typename S2>
462   void ldltSolve(std::vector<S1>& vec, std::vector<S2>& res) const;
463   //! templated factorization LDL* solver
464   template<typename S>
465   void ldlstarSolve(std::vector<S>& vec, std::vector<T>& res) const;
466   //! templated factorization LLt solver
467   template<typename S1, typename S2>
468   void lltSolve(std::vector<S1>& vec, std::vector<S2>& res) const;
469   //! templated factorization LU solver
470   template<typename S1, typename S2>
471   void luSolve(std::vector<S1>& vec, std::vector<S2>& res) const;
472   //! templated factorization LU solver (UmfPack)
473   template<typename S1, typename S2>
474   void umfluSolve(std::vector<S1>& vec, std::vector<S2>& res) const;
475   //! templated factorization SOR lower part solver
476   template<typename S1, typename S2>
477   void sorLowerMatrixVector(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
478   //! templated factorization SOR diagonal solver
479   template<typename S1, typename S2>
480   void sorDiagonalMatrixVector(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
481   //! templated factorization SOR upper part solver
482   template<typename S1, typename S2>
483   void sorUpperMatrixVector(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
484   //! templated factorization SOR lower part solver
485   template<typename S1, typename S2>
486   void sorLowerSolve(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
487   //! templated factorization SOR diagonal solver
488   template<typename S1, typename S2>
489   void sorDiagonalSolve(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
490   //! templated factorization SOR upper part solver
491   template<typename S1, typename S2>
492   void sorUpperSolve(const std::vector<S1>& vec, std::vector<S2>& res, const real_t w) const;
493 
494   // extern templated eigen Davidson solver
495   template<typename K>
496   friend number_t eigenDavidsonSolve(const LargeMatrix<K>* pA, const LargeMatrix<K>* pB, std::vector<std::pair<complex_t,Vector<complex_t> > >& res,
497                                      number_t nev, real_t tol, string_t which, bool isInverted, FactorizationType fac, bool isShift);
498   // extern templated eigen Krylov-Schur solver
499   template<typename K>
500   friend number_t eigenKrylovSchurSolve(const LargeMatrix<K>* pA, const LargeMatrix<K>* pB, std::vector<std::pair<complex_t,Vector<complex_t> > >& res,
501                                         number_t nev, real_t tol, string_t which, bool isInverted, FactorizationType fac, bool isShift);
502 
503   //@{
504   //! templated UMFPACK solver
505   template<typename S>
506   real_t umfpackSolve(const std::vector<S>& vec,
507                       std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType, S>::type>& res,
508                       bool soa=true);    //!< solve linear system using umfpack
509   template<typename S>
510   real_t umfpackSolve(const std::vector<std::vector<S>*>& bs,
511                       std::vector<std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType,S>::type>* >& xs,
512                       bool soa=true);   //!< solve linear system using umfpack, multiple rhs
513   template<typename S>
514   real_t umfpackSolve(const std::vector<int_t>& colPointer, const std::vector<int_t>& rowIndex,
515                       const std::vector<T>& values, const std::vector<S>& vec,
516                       std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType, S>::type>& res,
517                       bool soa=true); //!< solve linear system using umfpack
518   //@}
519 
520   //@{
521   //! lower and upper solvers on vector : LD1^{-1}*b, U^{-1}*b, b*LD1^{-1}, b*U^{-1}, b may be modified
522   std::vector<T>& lowerD1Solve(std::vector<T>& b, std::vector<T>& x) const;
523   std::vector<T>& upperSolve(std::vector<T>& b, std::vector<T>& x) const;
524   std::vector<T>& lowerD1LeftSolve(std::vector<T>& b, std::vector<T>& x) const;
525   std::vector<T>& upperLeftSolve(std::vector<T>& b, std::vector<T>& x) const;
526   //@}
527 
528   //@{
529   //! lower and upper solvers on LargeMatrix : LD1^{-1}*M, U^{-1}*M, M*LD1^{-1}, M*U^{-1}, result is stored as col dense
530   LargeMatrix<T>& lowerD1Solve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const;
531   LargeMatrix<T>& upperSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const;
532   LargeMatrix<T>& lowerD1LeftSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const;
533   LargeMatrix<T>& upperLeftSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const;
534   //@}
535 
536   // external template addition two matrices A+B=C, all of them have the same type of storage
537   template<typename S>
538   friend void addMatrixMatrix(const LargeMatrix<S>& matA, const LargeMatrix<S>& matB, LargeMatrix<S>& matC);
539 #ifndef DOXYGEN_SHOULD_SKIP_THIS
540   friend void addMatrixMatrix(const LargeMatrix<complex_t>& matA, const LargeMatrix<real_t>& matB, LargeMatrix<complex_t>& matC);
541   friend void addMatrixMatrix(const LargeMatrix<real_t>& matA, const LargeMatrix<complex_t>& matB, LargeMatrix<complex_t>& matC);
542 #endif
543 
544   // Scale a largeMatrix with a scalar
545   template<typename S>
546   friend LargeMatrix<S> multMatrixScalar(const LargeMatrix<S>&, const S);
547 #ifndef DOXYGEN_SHOULD_SKIP_THIS
548   friend LargeMatrix<complex_t> multMatrixScalar(const LargeMatrix<complex_t>&, const real_t);
549   friend LargeMatrix<complex_t> multMatrixScalar(const LargeMatrix<real_t>&, const complex_t);
550 #endif
551 
552   // Construct a diagonalMatrix from a Matrix
553   template<typename S>
554   friend LargeMatrix<S> diagonalMatrix(const LargeMatrix<S>&, const S);
555 
556   // Construct a identity matrix from a Matrix
557   template<typename S>
558   friend LargeMatrix<S> identityMatrix(const LargeMatrix<S>&);
559 
560   // print utilities
561   void print(std::ostream&) const;                                       //!< print on output stream
print(PrintStream & os) const562   void print(PrintStream& os) const
563   { print(os.currentStream()); }
564   void viewStorage(std::ostream&) const;                                 //!< visualize storage on output stream
viewStorage(PrintStream & os) const565   void viewStorage(PrintStream& os) const
566   { viewStorage(os.currentStream()); }
567   template <typename S>
568   friend std::ostream& operator<<(std::ostream&, const LargeMatrix<S>&);
569 
570   // save to file utilities
571   void saveToFile(const string_t&, StorageType, bool encode = false) const; //!< save matrix to a file along different format
572   void saveToFile(const char*, StorageType, bool encode = false) const;   //!< save matrix to a file along different format
573   void loadFromFile(const string_t&, StorageType);                          //!< load matrix from file
574   string_t encodeFileName(const string_t&, StorageType) const;                //!< encode file name with additional matrix informations
575 };
576 
577 // utilities
578 //std::pair<dimen_t, dimen_t> dimsOf(const real_t&);
579 //std::pair<dimen_t, dimen_t> dimsOf(const complex_t&);
580 //std::pair<dimen_t, dimen_t> dimsOf(const Matrix<real_t>&);
581 //std::pair<dimen_t, dimen_t> dimsOf(const Matrix<complex_t>&);
582 
583 // external template addition of two matrix A+B=C, they need not share a same storage
584 // This function return a non-null pointer whose referenced memory should be MANAGEd after being called.
585 template<typename S>
586 LargeMatrix<S>* addMatrixMatrixSkyline(const LargeMatrix<S>& matA, const LargeMatrix<S>& matB);
587 
588 /*---------------------------------------------------------------------------------------------------
589   LargeMatrix<T> constructors, destructor
590 ---------------------------------------------------------------------------------------------------*/
591 //default constructor (no storage)
592 template <typename T>
LargeMatrix()593 LargeMatrix<T>::LargeMatrix()
594   : valueType_(_real), strucType(_scalar), nbRows(0), nbCols(0), sym(_noSymmetry), nbRowsSub(1), nbColsSub(1)
595 {
596   setType(T());
597   storage_p = 0;
598 #ifdef XLIFEPP_WITH_UMFPACK
599   umfLU_p=0;
600 #endif
601   factorization_=_noFactorization;
602   values_.resize(1, T());
603 }
604 //explicit constructor
605 template <typename T>
LargeMatrix(ValueType vt,StrucType st,number_t nbr,number_t nbc,SymType sy,dimen_t nbrs,dimen_t nbcs,const T & val,const string_t & na,MatrixStorage * sp)606 LargeMatrix<T>::LargeMatrix(ValueType vt,StrucType st, number_t nbr, number_t nbc, SymType sy,
607                             dimen_t nbrs, dimen_t nbcs, const T& val, const string_t& na,  MatrixStorage* sp)
608   : valueType_(vt),strucType(st),nbRows(nbr),nbCols(nbc),sym(sy),nbRowsSub(nbrs),nbColsSub(nbcs), name(na), storage_p(sp)
609 {
610   if(sp!=0) init(sp,val,sy);
611 #ifdef XLIFEPP_WITH_UMFPACK
612   umfLU_p=0;
613 #endif
614   factorization_=_noFactorization;
615 }
616 
617 template <typename T>
LargeMatrix(const LargeMatrix<T> & mat,bool storageCopy)618 LargeMatrix<T>::LargeMatrix(const LargeMatrix<T>& mat, bool storageCopy)
619   : valueType_(mat.valueType_), strucType(mat.strucType), nbRows(mat.nbRows), nbCols(mat.nbCols), sym(mat.sym),
620     nbRowsSub(mat.nbRowsSub), nbColsSub(mat.nbColsSub), name("shallow copy of" + mat.name)
621 {
622   setType(T());
623   nbRowsSub=mat.nbRowsSub;  //redo because setType reset to 1
624   nbColsSub=mat.nbColsSub;  //redo because setType reset to 1
625 
626   if (Trace::traceMemory)
627     {
628       thePrintStream << "LargeMatrix::copy_constructor allocates a new large matrix : " << &values_ << ", "
629                      << mat.values_.size() << " non zeros coefficients " << dimValues();
630       if(mat.storage_p != 0) thePrintStream << ", storage " << mat.storage_p->name();
631       thePrintStream << eol << std::flush;
632     }
633 
634   values_ = mat.values_;
635   storage_p = mat.storage_p;
636   if (storage_p == 0) return;
637   if (storageCopy) storage_p=mat.storage_p->clone();               // copy storage
638   storage_p->objectPlus();
639   factorization_=mat.factorization_;
640   #ifdef XLIFEPP_WITH_UMFPACK
641   umfLU_p=0;
642   if (mat.umfLU_p != 0)
643     {
644         warning("free_warning","LargeMatrix copy, does not copy the umfpackLU object, redo factorisation if required");
645         factorization_=_noFactorization;
646     }
647   #endif
648 }
649 
650 template <typename T>
operator =(const LargeMatrix<T> & mat)651 LargeMatrix<T>& LargeMatrix<T>::operator=(const LargeMatrix<T>& mat)
652 {
653   if (this != &mat)
654     {
655       clearall();
656       valueType_=mat.valueType_;
657       strucType=mat.strucType;
658       nbRows=mat.nbRows;
659       nbCols=mat.nbCols;
660       sym=mat.sym;
661       nbRowsSub=mat.nbRowsSub;
662       nbColsSub=mat.nbColsSub;
663       name="shallow copy of" + mat.name;
664       setType(T());
665       nbRowsSub=mat.nbRowsSub;  //redo because setType reset to 1
666       nbColsSub=mat.nbColsSub;  //redo because setType reset to 1
667 
668       if (Trace::traceMemory)
669         {
670           thePrintStream << "LargeMatrix::copy_constructor allocates a new large matrix : " << &values_ << ", "
671                          << mat.values_.size() << " non zeros coefficients " << dimValues();
672           if (mat.storage_p != 0) thePrintStream << ", storage " << mat.storage_p->name();
673           thePrintStream << eol << std::flush;
674         }
675 
676       values_ = mat.values_;
677       storage_p = mat.storage_p;
678       if (storage_p == 0) return *this;
679       storage_p->objectPlus();
680       factorization_=mat.factorization_;
681       #ifdef XLIFEPP_WITH_UMFPACK
682       umfLU_p=0;
683       if (mat.umfLU_p != 0)
684        {
685         warning("free_warning","LargeMatrix copy, does not copy the umfpackLU object, redo factorisation if required");
686         factorization_=_noFactorization;
687        }
688       #endif
689     }
690   return *this;
691 }
692 
693 template <typename T>
694 template <typename K>
LargeMatrix(const LargeMatrix<K> & mat,bool storageCopy)695 LargeMatrix<T>::LargeMatrix(const LargeMatrix<K>& mat, bool storageCopy)
696   : valueType_(mat.valueType_), strucType(mat.strucType), nbRows(mat.nbRows), nbCols(mat.nbCols), sym(mat.sym),
697     nbRowsSub(mat.nbRowsSub), nbColsSub(mat.nbColsSub), name("shallow copy of" + mat.name)
698 {
699   setType(T());
700   nbRowsSub=mat.nbRowsSub;  //redo because setType reset to 1
701   nbColsSub=mat.nbColsSub;  //redo because setType reset to 1
702 
703   if (Trace::traceMemory)
704     {
705       thePrintStream << "LargeMatrix::copy_constructor allocates a new large matrix : " << &values_ << ", "
706                      << mat.values().size() << " non zeros coefficients " << dimValues();
707       if (mat.storagep() != 0) thePrintStream << ", storage " << mat.storagep()->name();
708       thePrintStream << eol << std::flush;
709     }
710 
711   values_.resize(mat.values().size());
712   typename std::vector<T>::iterator it = values_.begin();
713   typename std::vector<K>::const_iterator itm = mat.values().begin();
714   for (; it != values_.end(); it++, itm++) *it = *itm;
715   storage_p = mat.storagep();
716   if (storage_p == 0) return;
717   if (storageCopy) storage_p=mat.storagep()->clone();               //storage copy
718   storage_p->objectPlus();
719   factorization_=mat.factorization_;
720   #ifdef XLIFEPP_WITH_UMFPACK
721   umfLU_p=0;
722   if (mat.umfLU_p != 0)
723     {
724         warning("free_warning","LargeMatrix copy, does not copy the umfpackLU object, redo factorisation if required");
725         factorization_=_noFactorization;
726     }
727   #endif
728 }
729 
730 template <typename T>
731 template <typename K>
operator =(const LargeMatrix<K> & mat)732 LargeMatrix<T>& LargeMatrix<T>::operator=(const LargeMatrix<K>& mat)
733 {
734   if (this != &mat)
735     {
736       clearall();
737       valueType_=mat.valueType_;
738       strucType=mat.strucType;
739       nbRows=mat.nbRows;
740       nbCols=mat.nbCols;
741       sym=mat.sym;
742       nbRowsSub=mat.nbRowsSub;
743       nbColsSub=mat.nbColsSub;
744       name="shallow copy of" + mat.name;
745       setType(T());
746       nbRowsSub=mat.nbRowsSub;  //redo because setType reset to 1
747       nbColsSub=mat.nbColsSub;   //redo because setType reset to 1
748 
749       if (Trace::traceMemory)
750         {
751           thePrintStream << "LargeMatrix::copy_constructor allocates a new large matrix : " << &values_ << ", "
752                          << mat.values().size() << " non zeros coefficients " << dimValues();
753           if (mat.storagep() != 0) thePrintStream << ", storage " << mat.storagep()->name();
754           thePrintStream << eol << std::flush;
755         }
756 
757       values_.resize(mat.values().size());
758       typename std::vector<T>::iterator it = values_.begin();
759       typename std::vector<K>::const_iterator itm = mat.values().begin();
760       for (; it != values_.end(); it++, itm++) *it = *itm;
761       storage_p = mat.storagep();
762       if (storage_p == 0) return *this;
763       storage_p->objectPlus();
764       factorization_=mat.factorization_;
765       #ifdef XLIFEPP_WITH_UMFPACK
766       umfLU_p=0;
767       if (mat.umfLU_p != 0)
768       {
769         warning("free_warning","LargeMatrix copy, does not copy the umfpackLU object, redo factorisation if required");
770         factorization_=_noFactorization;
771       }
772       #endif
773     }
774   return *this;
775 }
776 
777 //constructor from a given storage and a constant value, sy tells if the matrix has symmetry
778 template <typename T>
LargeMatrix(MatrixStorage * ms,const T & val,SymType sy)779 LargeMatrix<T>::LargeMatrix(MatrixStorage* ms, const T& val, SymType sy)
780   : valueType_(_none), strucType(_scalar), nbRows(0), nbCols(0), sym(sy), nbRowsSub(1), nbColsSub(1)
781 {
782   setType(val);
783   init(ms, val, sy);
784 #ifdef XLIFEPP_WITH_UMFPACK
785   umfLU_p=0;
786 #endif
787   factorization_=_noFactorization;
788 }
789 
790 template <typename T>
LargeMatrix(MatrixStorage * ms,SymType sy)791 LargeMatrix<T>::LargeMatrix(MatrixStorage* ms, SymType sy)
792   : valueType_(_none), strucType(_scalar), nbRows(0), nbCols(0), sym(sy), nbRowsSub(1), nbColsSub(1)
793 {
794   T val = T(0);
795   setType(val);
796   init(ms, val, sy);
797 #ifdef XLIFEPP_WITH_UMFPACK
798   umfLU_p=0;
799 #endif
800   factorization_=_noFactorization;
801 }
802 
803 //use this constructor for matrix of matrix, dims are the dimensions of matrix values
804 template <typename T>
LargeMatrix(MatrixStorage * ms,dimPair dims,SymType sy)805 LargeMatrix<T>::LargeMatrix(MatrixStorage* ms, dimPair dims, SymType sy)
806   : valueType_(_none), strucType(_scalar), nbRows(0), nbCols(0), sym(sy), nbRowsSub(1), nbColsSub(1)
807 {
808   T val = T();
809   resize(val, dims.first, dims.second);
810   setType(val);
811   init(ms, val, sy);
812 #ifdef XLIFEPP_WITH_UMFPACK
813   umfLU_p=0;
814 #endif
815   factorization_=_noFactorization;
816 
817 }
818 
819 //construct particular matrix such as constant diagonal matrix
820 template <typename T>
LargeMatrix(SpecialMatrix sp,StorageType st,AccessType at,number_t nbr,number_t nbc,const T v)821 LargeMatrix<T>::LargeMatrix(SpecialMatrix sp, StorageType st, AccessType at, number_t nbr, number_t nbc, const T v)
822 {
823   sym=_noSymmetry;
824   factorization_=_noFactorization;
825 #ifdef XLIFEPP_WITH_UMFPACK
826   umfLU_p=0;
827 #endif
828   if(sp==_idMatrix)
829     {
830       if(at==_sym) sym=_symmetric;
831       number_t m=std::min(nbr,nbc);
832       std::vector<std::vector<number_t> > indices(m);  // vector of column indices for each row
833       std::vector<std::vector<number_t> >::iterator iti=indices.begin();
834       for(number_t k=1; k<=m; k++, iti++) *iti = std::vector<number_t>(1,k);
835       MatrixStorage* diagst = createMatrixStorage(st, at, nbr, nbc, indices,"");
836       setType(v);
837       init(diagst,v,sym);
838     }
839   else
840     {
841       where("LargeMatrix<T>::LargeMatrix(SpecialMatrix, StorageType, AccessType, Number, Number, T)");
842       error("special_matrix_unexpected", words("matrix", _idMatrix), words("matrix", sp));
843     }
844 }
845 
846 // destructor : the storage pointer is deleted if no other object shares it
847 template <typename T>
~LargeMatrix()848 LargeMatrix<T>::~LargeMatrix()
849 {
850   clearall();
851 }
852 
853 // clear values and storage pointer if not shared
854 template <typename T>
clearall()855 void LargeMatrix<T>::clearall()
856 {
857 #ifdef XLIFEPP_WITH_UMFPACK
858   if(umfLU_p!=0) delete umfLU_p;
859 #endif
860   clear();
861   if(storage_p != 0)
862     {
863       if(storage_p->numberOfObjects() > 0) storage_p->objectMinus();
864       if(storage_p->numberOfObjects() == 0) delete storage_p;
865       storage_p =0;
866     }
867 }
868 
869 //functions to resize matrix or vector values (perhaps to be defined elsewhere)
870 template <typename T>
resize(T & v,dimen_t m,dimen_t n)871 void resize(T& v, dimen_t m, dimen_t n)
872 {
873   return;
874 }
875 template <typename T>
resize(std::vector<T> & v,dimen_t m,dimen_t n)876 void resize(std::vector<T>& v, dimen_t m, dimen_t n)
877 {
878   v.resize(m);
879   return;
880 }
881 template <typename T>
resize(Matrix<T> & v,dimen_t m,dimen_t n)882 void resize(Matrix<T>& v, dimen_t m, dimen_t n)
883 {
884   v.resize(m * n);
885   return;
886 }
887 
888 //initialize type of matrix element
889 template <typename T>
setType(const T & v)890 void LargeMatrix<T>::setType(const T& v)
891 {
892   structPair sp = Value::typeOf(v);
893   valueType_ = sp.first;
894   strucType = sp.second;
895   dimPair ds = dimsOf(v);
896   nbRowsSub = ds.first;
897   nbColsSub = ds.second;
898   if(nbRowsSub>1 || nbColsSub>1) strucType=_matrix;
899 }
900 
901 // initialize LargeMatrix from a given storage and a constant value, sy tells if the matrix has symmetry
902 template <typename T>
init(MatrixStorage * ms,const T & val,SymType sy)903 void  LargeMatrix<T>::init(MatrixStorage* ms, const T& val, SymType sy)
904 {
905   storage_p = ms;
906   if(ms == 0) return;       // void storage, allocation delayed
907 
908   nbRows = storage_p->nbOfRows();
909   nbCols = storage_p->nbOfColumns();
910   number_t s = storage_p->size() + 1;
911   if(storage_p->accessType() == _sym && sy == _noSymmetry) s+= storage_p->upperPartSize();   // symmetric storage for non symmetric matrix
912   if(Trace::traceMemory)
913     {
914       thePrintStream<<"LargeMatrix::init allocates a new large matrix : "<<&values_<<", "
915                     <<s<<" non zeros coefficients "<<dimValues();
916       if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
917       thePrintStream<<eol<<std::flush;
918     }
919   values_.resize(s, val);
920   values_[0] = 0 * val;       // set first to zero (matrix begins at adress 1!)
921   storage_p->objectPlus();
922 }
923 
924 // constructor with matrix dimensions, storage type and a constant value
925 // storage pointer is allocated but for other storages than dense storage is not set
926 template <typename T>
LargeMatrix(number_t nr,number_t nc,StorageType sto,AccessType at,const T & val)927 LargeMatrix<T>::LargeMatrix(number_t nr, number_t nc, StorageType sto, AccessType at, const T& val)
928   : valueType_(_none), strucType(_scalar), nbRows(nr), nbCols(nc), sym(_noSymmetry)
929 {
930   factorization_=_noFactorization;
931 #ifdef XLIFEPP_WITH_UMFPACK
932   umfLU_p=0;
933 #endif
934   setType(val);
935   allocateStorage(sto, at, val);
936   if(at == _sym && sym == _noSymmetry) //force matrix to be symmetric
937     {
938       warning("largematrix_forcesymmetry");
939       sym = _symmetric;
940     }
941 }
942 
943 // construct "symmetric" matrix from dimensions, storage type, symmetry type and a constant value
944 // acces type is _sym in that case
945 template <typename T>
LargeMatrix(number_t nr,number_t nc,StorageType sto,SymType sy,const T & val)946 LargeMatrix<T>::LargeMatrix(number_t nr, number_t nc, StorageType sto, SymType sy, const T& val)
947   : valueType_(_none), strucType(_scalar), nbRows(nr), nbCols(nc), sym(sy)
948 {
949   factorization_=_noFactorization;
950 #ifdef XLIFEPP_WITH_UMFPACK
951   umfLU_p=0;
952 #endif
953   setType(val);
954   allocateStorage(sto, _sym, val);
955   // for skewsymetric matrix, force diagonal to be zero
956   if(sy == _skewSymmetric)
957     {
958       T zero = 0 * val;
959       typename std::vector<T>::iterator itb = values_.begin() + 1, it;
960       for(it = itb; it < itb + nbRows; it++)
961         {
962           *it = zero;
963         }
964     }
965   // for skewadjoint matrix, force diagonal to have zero real part
966   if(sy == _skewAdjoint)
967     {
968       T img = (val - conj(val)) / 2.;
969       typename std::vector<T>::iterator itb = values_.begin() + 1, it;
970       for(it = itb; it < itb + nbRows; it++)
971         {
972           *it = img;
973         }
974     }
975 }
976 
977 /* construct matrix from file and storage type; matrix in file is either
978    in dense format (fst=_dense) :
979     A11 A12  ...                            Re(A11) Im(A11) Re(A12) IM(A12) ....
980     A21 A22  ...    or if complex matrix    Re(A21) Im(A21) Re(A22) IM(A22) ....
981     ...                                     ...
982    or in coordinate sparse storage format (fst=_coo) :
983     i j Aij         or if complex values    i j Re(Aij) Im(Aij)
984    does not work for matrix of matrices!
985 */
986 template <typename T>
LargeMatrix(const string_t & fn,StorageType fst,number_t nr,number_t nc,StorageType sto,AccessType at,number_t nsr,number_t nsc)987 LargeMatrix<T>::LargeMatrix(const string_t& fn, StorageType fst, number_t nr, number_t nc,
988                             StorageType sto, AccessType at, number_t nsr, number_t nsc)
989   : valueType_(_none), strucType(_scalar), nbRows(nr), nbCols(nc), sym(_noSymmetry), nbRowsSub(nsr), nbColsSub(nsc)
990 {
991   factorization_=_noFactorization;
992 #ifdef XLIFEPP_WITH_UMFPACK
993   umfLU_p=0;
994 #endif
995   setType(T());
996   nbRowsSub = nsr;
997   nbColsSub = nsc;
998   allocateStorage(sto, at);
999   if(nsr > 1 || nsc > 1)
1000     {
1001       error("largematrix_noloadmatrixofmatrix");
1002     }
1003   loadFromFile(fn, fst);
1004 }
1005 
1006 // construct "symmetric" matrix from file and storage type
1007 template <typename T>
LargeMatrix(const string_t & fn,StorageType fst,number_t nr,StorageType sto,SymType sy,number_t nsr)1008 LargeMatrix<T>::LargeMatrix(const string_t& fn, StorageType fst, number_t nr, StorageType sto,
1009                             SymType sy, number_t nsr)
1010   : valueType_(_none), strucType(_scalar), nbRows(nr), nbCols(nr), sym(sy), nbRowsSub(nsr), nbColsSub(nsr)
1011 {
1012   factorization_=_noFactorization;
1013 #ifdef XLIFEPP_WITH_UMFPACK
1014   umfLU_p=0;
1015 #endif
1016   setType(T());
1017   nbRowsSub = nsr;
1018   nbColsSub = nsr;
1019   if(nsr > 1)
1020     {
1021       error("largematrix_noloadmatrixofmatrix");
1022     }
1023   allocateStorage(sto, _sym);
1024   loadFromFile(fn, fst);
1025 }
1026 
1027 // allocate storage pointer by creating storage object according to storage type and storage access
1028 // if possible (dense storage), the values_ vector is sized
1029 template <typename T>
allocateStorage(StorageType sto,AccessType at,const T & val)1030 void LargeMatrix<T>::allocateStorage(StorageType sto, AccessType at, const T& val)
1031 {
1032   switch(sto)
1033     {
1034     case _dense   :
1035       switch(at)
1036         {
1037         case _dual :
1038           storage_p = new DualDenseStorage(nbRows, nbCols);
1039           break;
1040         case _row  :
1041           storage_p = new RowDenseStorage(nbRows, nbCols);
1042           break;
1043         case _col  :
1044           storage_p = new ColDenseStorage(nbRows, nbCols);
1045           break;
1046         case _sym  :
1047           storage_p = new SymDenseStorage(nbRows);
1048           break;
1049         default    :
1050           error("storage_bad_access", words("access type",at), words("storage type",_dense));
1051         }
1052       if(Trace::traceMemory)
1053         {
1054           thePrintStream<<"LargeMatrix::allocateStorage allocates a new large matrix : "<<&values_<<", "
1055                         <<storage_p->size() + 1<<" non zeros coefficients "<<dimValues();
1056           if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
1057           thePrintStream<<eol<<std::flush;
1058         }
1059       values_.resize(storage_p->size() + 1, val); // allocate values vector
1060       break;
1061     case _skyline :
1062       switch(at)
1063         {
1064         case _dual :
1065           storage_p = new DualSkylineStorage(nbRows, nbCols);
1066           break;
1067         case _sym  :
1068           storage_p = new SymSkylineStorage(nbRows);
1069           break;
1070         case _row  :
1071         case _col  :
1072         default    :
1073           error("storage_bad_access", words("access type",at), words("storage type",_skyline));
1074         }
1075       break;
1076     case _cs      :
1077       switch(at)
1078         {
1079         case _dual :
1080           storage_p = new DualCsStorage(nbRows, nbCols);
1081           break;
1082         case _row  :
1083           storage_p = new RowCsStorage(nbRows, nbCols);
1084           break;
1085         case _col  :
1086           storage_p = new ColCsStorage(nbRows, nbCols);
1087           break;
1088         case _sym  :
1089           storage_p = new SymCsStorage(nbRows);
1090           break;
1091         default    :
1092           error("storage_bad_access", words("access type",at), words("storage type",_cs));
1093         }
1094       break;
1095     default :
1096       where("LargeMatrix<T>::allocateStorage");
1097       error("storage_not_handled", words("storage type",sto), words("access type",at));
1098     }
1099   storage_p->objectPlus();
1100 }
1101 
1102 /*---------------------------------------------------------------------------------------------------
1103   LargeMatrix<T> various utilities
1104 ---------------------------------------------------------------------------------------------------*/
1105 
1106 
1107 
1108 //convert matrix storage to skyline storage
1109 template <typename T>
toSkyline()1110 void LargeMatrix<T>::toSkyline()
1111 {
1112   if(storage_p == 0) error("matrix_nostorage");
1113   StorageType st = storage_p->storageType();
1114   if(st == _skyline) return; //matrix is already stored as skyline
1115 
1116   trace_p->push("LargeMatrix<T>::toSkyline");
1117 
1118   //find if storage is already defined
1119   AccessType at = _dual;
1120   if(sym != _noSymmetry) at = _sym;
1121   MatrixStorage*  skysto = 0;
1122   // MatrixStorage*  skysto = findMatrixStorage(storage_p->stringId, _skyline, at);
1123   // if(skysto != 0 && (nbRows!=skysto->nbOfRows() || nbCols!=skysto->nbOfColumns())) skysto=0;   //not the same sizes
1124   // if(skysto == 0)  //construct newskyline storage  ### deactivate by Eric, because re-using existing storage may be hazardous
1125   // {
1126   std::vector<number_t> skyrowpointer(storage_p->skylineRowPointer());
1127   if(at == _sym) skysto = static_cast< MatrixStorage* >(new SymSkylineStorage(skyrowpointer, storage_p->stringId));
1128   else
1129     {
1130       std::vector<number_t> skycolpointer(storage_p->skylineColPointer());
1131       skysto = static_cast< MatrixStorage* >(new DualSkylineStorage(skyrowpointer, skycolpointer, storage_p->stringId));
1132     }
1133   // }
1134   // skysto->visual(thePrintStream);
1135 
1136   //update values (Note : test memory in future)
1137   std::vector<T> oldvalues = values_;
1138   values_.assign(skysto->size() + 1, 0.*oldvalues[0]);
1139   storage_p->fillSkylineValues(oldvalues, values_, sym); //does not require new skyline storage !!!
1140   storage_p->objectMinus();
1141   //Eric's note : we enforce the destruction of the original storage_p object if it is no longer used by other matrix
1142   if(storage_p->numberOfObjects()==0) delete storage_p;
1143   storage_p = skysto;
1144   storage_p->objectPlus();
1145   trace_p->pop();
1146 }
1147 
1148 // Extract and convert matrix storage to UmfPack storage (similar to CSC storage, differ only in the offset of values)
1149 // Only can this function convert from CS storage to UmfPack
1150 template <typename T>
extract2UmfPack(std::vector<int_t> & colPointer,std::vector<int_t> & rowIndex,std::vector<T> & matA) const1151 void LargeMatrix<T>::extract2UmfPack(std::vector<int_t>& colPointer, std::vector<int_t>& rowIndex, std::vector<T>& matA) const
1152 {
1153   trace_p->push("LargeMatrix<T>::extract2UmfPack()");
1154   if(storage_p==0) error("matrix_nostorage");
1155   storage_p->toUmfPack(values_, colPointer, rowIndex, matA, sym);
1156   trace_p->pop();
1157 }
1158 
1159 // Get cs col storage pointer and pointer to first value of matrix
1160 //   only available for LargeMatrix  stored as cs col, move before
1161 //   return false if not a cs col largematrix
1162 template <typename T>
getCsColUmfPack(std::vector<int_t> & colPointer,std::vector<int_t> & rowIndex,const T * & matA) const1163 bool LargeMatrix<T>::getCsColUmfPack(std::vector<int_t>& colPointer, std::vector<int_t>& rowIndex, const T*& matA) const
1164 {
1165   trace_p->push("LargeMatrix<T>::getCsColUmfPack");
1166   if(storage_p==0) error("matrix_nostorage");
1167   if(storage_p->storageType()!=_cs || storage_p->accessType()!=_col)
1168     {
1169       trace_p->pop();  //use extract2Umfpack
1170       return false;
1171     }
1172 
1173   ColCsStorage* csto = reinterpret_cast<ColCsStorage*>(storage_p);  //downcast to ColCsStorage
1174   //move indices from number_t to int_t
1175   if(csto->size() > number_t(theIntMax))  //check if the last index goes over the int max
1176     error("conversion_overflow","Number", "Int", theIntMax);
1177   colPointer.resize(csto->colPointer().size());
1178   std::vector<number_t>::iterator itn = csto->colPointer().begin();
1179   std::vector<int_t>::iterator iti=colPointer.begin();
1180   for(; itn!=csto->colPointer().end(); ++itn, ++iti) *iti = int_t(*itn);
1181   rowIndex.resize(csto->rowIndex().size());
1182   itn=csto->rowIndex().begin();
1183   iti=rowIndex.begin();
1184   for(; itn!=csto->rowIndex().end(); ++itn, ++iti) *iti = int_t(*itn);
1185 
1186   //get first address of matrix with 1-shift to be compliant with umfpack which starts at 0
1187   matA = &(values_.at(1));
1188   trace_p->pop();
1189   return true;
1190 }
1191 
1192 //convert matrix storage to matrix storage ms, general algorithm to be improved
1193 template <typename T>
toStorage(MatrixStorage * ms)1194 void LargeMatrix<T>::toStorage(MatrixStorage* ms)
1195 {
1196   trace_p->push("LargeMatrix<T>::toStorage");
1197   if(storage_p == 0) error("matrix_nostorage");
1198   if(ms == 0) error("matrix_nostorage");
1199   if(storage_p==ms)
1200     {
1201       trace_p->pop();  //same storage, nothing to do
1202       return;
1203     }
1204   if(storage_p->accessType()!=_sym && ms->accessType()==_sym) error("nonsym_to_sym", "conversion");
1205 
1206   std::vector<T> oldvalues = values_;        //copy values
1207   if(Trace::traceMemory)
1208     {
1209       thePrintStream<<"LargeMatrix::toStorage re-allocates a large matrix : "<<&values_<<", "
1210                     <<ms->size()<<" non zero coefficients "<<dimValues();
1211       if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
1212       thePrintStream<<eol<<std::flush;
1213     }
1214   try
1215     {
1216       values_.assign(ms->size() + 1, 0.*oldvalues[0]);      //reallocate values_ vector regarding new storage
1217     }
1218   catch(std::exception& e)
1219     {
1220       std::cout << e.what() << " in LargeMatrix<T>::toStorage : "<<std::endl;
1221       std::cout << "try to allocate a vector of size "<< ms->size() + 1;
1222       std::cout << " requiring "<< ((ms->size() + 1)/(1024*1024))*sizeof(T)<<" Mo";
1223       abort();
1224     }
1225 
1226   std::vector<number_t> row(1), cols(nbCols), pos, newpos;
1227   for(number_t c=0; c<nbCols; c++) cols[c]=c+1;
1228   for(number_t r=1; r<=nbRows; r++)            //travel matrix rows
1229     {
1230       row[0]=r;
1231       storage_p->positions(row, cols, pos, false, sym);
1232       ms->positions(row, cols, newpos, false, sym);
1233       std::vector<number_t>::iterator itp=pos.begin(),itnp=newpos.begin();
1234       if(sym==_noSymmetry || (storage_p->accessType()!=_sym && ms->accessType()!=_sym))  //matrix has no symmetry property or storages are both non symmetric        {
1235         {
1236           for(; itp!=pos.end(); itp++, itnp++)           //travel columns
1237             if(*itp!=0 && *itnp!=0) values_[*itnp]=oldvalues[*itp];
1238         }
1239       else //matrix with symmetry
1240         {
1241           //copy lower part
1242           for(number_t c=1; c<=r; itp++, itnp++, c++)           //travel columns
1243             if(*itp!=0 && *itnp!=0) values_[*itnp]=oldvalues[*itp];
1244           //copy upper part
1245           if(storage_p->accessType()==_sym && ms->accessType()!=_sym)
1246             switch(sym)
1247               {
1248               default :
1249               case _symmetric :
1250               {
1251                 for(; itp!=pos.end(); itp++, itnp++)           //travel columns
1252                   if(*itp!=0 && *itnp!=0) values_[*itnp]=oldvalues[*itp];
1253                 break;
1254               }
1255               case _selfAdjoint :
1256               {
1257                 for(; itp!=pos.end(); itp++, itnp++)           //travel columns
1258                   if(*itp!=0 && *itnp!=0) values_[*itnp]=conj(oldvalues[*itp]);
1259                 break;
1260               }
1261               case _skewSymmetric :
1262               {
1263                 for(; itp!=pos.end(); itp++, itnp++)           //travel columns
1264                   if(*itp!=0 && *itnp!=0) values_[*itnp]=-oldvalues[*itp];
1265                 break;
1266               }
1267               case _skewAdjoint :
1268               {
1269                 for(; itp!=pos.end(); itp++, itnp++)           //travel columns
1270                   if(*itp!=0 && *itnp!=0) values_[*itnp]=-conj(oldvalues[*itp]);
1271                 break;
1272               }
1273               }
1274         }
1275     }
1276   storage_p->objectMinus();
1277   if(storage_p->numberOfObjects()<=0) delete storage_p;
1278   ms->objectPlus();
1279   storage_p=ms;
1280   trace_p->pop();
1281 }
1282 
1283 // change coefficients to their conjugates
1284 template <typename T>
toConj()1285 LargeMatrix<T>& LargeMatrix<T>::toConj()
1286 {
1287   if(valueType_==_complex)
1288     {
1289       typename std::vector<T>::iterator itv=values_.begin();
1290       for(; itv!=values_.end(); itv++)  *itv = conj(*itv);
1291     }
1292   return *this;
1293 }
1294 
1295 // create new scalar matrix entry from non scalar matrix entry
1296 template <typename T>
1297 template <typename K>
toScalar(K bid)1298 LargeMatrix<K>* LargeMatrix<T>::toScalar(K bid)
1299 {
1300   trace_p->push("LargeMatrix<T>::toScalar");
1301   LargeMatrix<K>* mat= 0;
1302   if(strucType == _scalar) error("vector_or_matrix");
1303   MatrixStorage* nsto = storage_p->toScalar(nbRowsSub,nbColsSub);  //create scalar storage from storage
1304   mat= new LargeMatrix<K>(nsto, sym);  //create matrix
1305   toScalarEntries(values_,mat->values(),*nsto);  //copy values
1306   trace_p->pop();
1307   return mat;
1308 }
1309 
1310 /*! copy matrix values to scalar values, generic algorithm using getrow or getcol
1311   K is the valueType of both matrices, sto is the matrixstorage of the scalar matrix
1312 */
1313 template <typename T>
1314 template <typename K>
toScalarEntries(const std::vector<Matrix<K>> & val,std::vector<K> & sval,const MatrixStorage & scalsto)1315 void LargeMatrix<T>::toScalarEntries(const std::vector<Matrix<K> >& val, std::vector<K>& sval, const MatrixStorage& scalsto)
1316 {
1317   trace_p->push("LargeMatrix<T>::toScalarEntries");
1318 
1319   AccessType acty=accessType();
1320   number_t rmax = nbRows, cmax = nbCols, srmax = nbRowsSub*nbRows, scmax=nbColsSub*nbCols;
1321 
1322   if(acty !=_col)  //case _row (all matrix),  _sym and _dual (lower part)
1323     {
1324       for(number_t r=0; r<nbRows; r++)
1325         {
1326           if(acty !=_row) cmax=r+1;
1327           std::vector<std::pair<number_t, number_t> > colind=getRow(r+1, 1, cmax);
1328           std::vector<std::pair<number_t, number_t> >::const_iterator itc;
1329           for(dimen_t rs=1; rs<=nbRowsSub; rs++)
1330             {
1331               number_t rss=r*nbRowsSub+rs;
1332               if(acty !=_row) scmax=rss;
1333               std::vector<std::pair<number_t, number_t> > scalcolind = scalsto.getRow(sym,rss,1,scmax);
1334               std::vector<std::pair<number_t, number_t> >::iterator itsc=scalcolind.begin();
1335               for(itc=colind.begin(); itc!=colind.end(); itc++)
1336                 for(dimen_t cs=1; cs<=nbColsSub && itsc<scalcolind.end(); cs++, itsc++)
1337                   sval[itsc->second] = val[itc->second](rs,cs);
1338             }
1339         }
1340     }
1341 
1342   if(acty ==_col || acty ==_dual || (acty==_sym && sym==_noSymmetry))  //case _col (all matrix) and _dual (strict upper part part)
1343     {
1344       for(number_t c=0; c<nbCols; c++)
1345         {
1346           if(acty != _col) rmax=c+1;
1347           std::vector<std::pair<number_t, number_t> > rowind=getCol(c+1, 1, rmax);
1348           std::vector<std::pair<number_t, number_t> >::const_iterator itr;
1349           for(dimen_t cs=1; cs<=nbColsSub; cs++)
1350             {
1351               number_t css=c*nbColsSub+cs;
1352               if(acty !=_col) srmax=css;
1353               std::vector<std::pair<number_t, number_t> > scalrowind = scalsto.getCol(sym, css, 1, srmax);
1354               std::vector<std::pair<number_t, number_t> >::iterator itsr=scalrowind.begin();
1355               for(itr=rowind.begin(); itr!=rowind.end(); itr++)
1356                 for(dimen_t rs=1; rs<=nbRowsSub && itsr<scalrowind.end(); rs++, itsr++)
1357                   sval[itsr->second] = val[itr->second](rs,cs);
1358             }
1359         }
1360     }
1361   trace_p->pop();
1362 }
1363 
1364 /*! convert current matrix to unsymmetric representation if it has a symmetric one
1365   convert only matrix using a symmetric access storage,
1366     if at = _sym  symmetric storage is not changed  (default behaviour)
1367     if at = _dual we moved to a dual storage
1368   values vector is extended to store upper part
1369 */
1370 template <typename T>
toUnsymmetric(AccessType at)1371 void LargeMatrix<T>::toUnsymmetric(AccessType at)
1372 {
1373   if(storage_p->accessType() != _sym || sym==_noSymmetry) return;  //no conversion
1374   if(at!=_sym && at!=_dual)
1375     error("access_unexpected", words("access type",_sym)+" "+words("or")+" "+words("access type", _dual), words("access type", at));
1376   if(at == _dual)
1377     {
1378       MatrixStorage* ms = storage_p->toDual();    //new dual storage from sym storage
1379       storage_p->objectMinus();
1380       if(storage_p->numberOfObjects()<=0) delete storage_p;
1381       ms->objectPlus();
1382       storage_p = ms;
1383     }
1384   //extend values_ vector size
1385   number_t ls=storage_p->lowerPartSize()+ storage_p->diagonalSize(), as=ls+storage_p->lowerPartSize();
1386   if(Trace::traceMemory)
1387     {
1388       thePrintStream<<"LargeMatrix::toUnsymmetric allocates a new large matrix : "<<&values_<<", "
1389                     <<as + 1<<" non zeros coefficients "<<dimValues();
1390       if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
1391       thePrintStream<<eol<<std::flush;
1392     }
1393   values_.resize(as+1);
1394   //"copy" lower part to upper part
1395   typename std::vector<T>::iterator itlow=values_.begin()+storage_p->diagonalSize()+1,
1396                                     itup=values_.begin()+ls+1;
1397   switch(sym)
1398     {
1399     case _symmetric     :
1400       for(; itup!=values_.end(); itup++, itlow++) *itup = *itlow;
1401       break;
1402     case _selfAdjoint   :
1403       for(; itup!=values_.end(); itup++, itlow++) *itup = conj(*itlow);
1404       break;
1405     case _skewSymmetric :
1406       for(; itup!=values_.end(); itup++, itlow++) *itup = - *itlow;
1407       break;
1408     case _skewAdjoint   :
1409       for(; itup!=values_.end(); itup++, itlow++) *itup = -conj(*itlow);
1410       break;
1411     default :
1412       error("not_handled","LargeMatrix<T>::toUnsymmetric()");
1413     }
1414   sym=_noSymmetry;
1415 }
1416 
1417 // test if the matrix is in fact a diagonal one (true if all non diagonal coefficients vanish)
1418 template<typename T>
isDiagonal() const1419 bool LargeMatrix<T>::isDiagonal() const
1420 {
1421   typename std::vector<T>::const_iterator itv1=values_.begin(), itv2, itv;
1422   if(storage_p->accessType()==_sym || storage_p->accessType()==_dual)
1423     {
1424       for(itv=itv1+storage_p->diagonalSize()+1; itv!=values_.end(); itv++)
1425         if(xlifepp::norm2(*itv)!=0) return false;
1426       return true;
1427     }
1428 
1429   std::vector<number_t> diagpos=storage_p->getDiag(); //get diagonal positions
1430   std::vector<number_t>::iterator itd=diagpos.begin();
1431   for(; itd!=diagpos.end(); itd++)
1432     {
1433       itv2=values_.begin()+*itd;
1434       for(itv=itv1+1; itv<itv2; itv++)
1435         if(xlifepp::norm2(*itv)!=0) return false; //a non diagonal coefficient is not equal to zero
1436       itv1=itv2;
1437     }
1438   itv=itv1+1;
1439   if(itv != values_.end())
1440     {
1441       for(; itv!=values_.end(); itv++)
1442         if(xlifepp::norm2(*itv)!=0) return false;    //a non diagonal coefficient is not equal to zero
1443     }
1444   return true;
1445 }
1446 
1447 // test if the matrix is in fact the identity (true if all non diagonal coefficients vanish and diagonal coefficients = 1)
1448 template<typename T>
isId(const double & tol) const1449 bool LargeMatrix<T>::isId(const double & tol) const
1450 {
1451   if(!isDiagonal()) return false;
1452   std::vector<number_t> diagpos=storage_p->getDiag(); //get diagonal positions
1453   std::vector<number_t>::iterator it=diagpos.begin();
1454   for(; it!=diagpos.end(); ++it)
1455     if(xlifepp::norm2(values_[*it]-1.)>tol) return false;
1456   return true;
1457 }
1458 
1459 //round to 0 all coefficients smaller (in norm) than a tolerance (aszero), storage is not modified
1460 template<typename T>
roundToZero(real_t aszero)1461 void LargeMatrix<T>::roundToZero(real_t aszero)
1462 {
1463   typename std::vector<T>::iterator itv=values_.begin()+1;
1464   for(; itv!=values_.end(); itv++)
1465     if(xlifepp::norm2(*itv)<aszero) *itv=T(0);
1466 }
1467 
1468 /*! assign to current LargeMatrix a LargeMatrix mat (submatrix) given by its ranks (rows, cols) in current matrix
1469   a void rows or cols  means that the numbering of mat is the same as current matrix
1470   in that case, if the storage of mat and current matrix are the same, direct summation is used
1471   else more expansive method is used : use positions function
1472   !!! target storage has to be update  and T = K has to be available NO CHECK!!!
1473 */
1474 template <typename T>
1475 template <typename K>
assign(const LargeMatrix<K> & mat,const std::vector<number_t> & rows,const std::vector<number_t> & cols)1476 LargeMatrix<T>& LargeMatrix<T>::assign(const LargeMatrix<K>& mat, const std::vector<number_t>& rows, const std::vector<number_t>& cols)
1477 {
1478   if(strucType != mat.strucType) error("largematrix_mismatch_structure");
1479   if(dimValues() != mat.dimValues()) error("largematrix_mismatch_size");
1480   if(sym != _noSymmetry && mat.sym == _noSymmetry) error("nonsym_to_sym", "assign");
1481   if(sym != _noSymmetry && mat.sym != _noSymmetry && sym != mat.sym) error("largematrix_diff_sym");
1482 
1483   //simple case : same storage and same symmetry
1484   if(rows.size() == 0 && cols.size() == 0 && storage_p == mat.storagep())
1485     {
1486       typename std::vector<T>::iterator itv = values_.begin();
1487       typename std::vector<K>::const_iterator itm = mat.values().begin();
1488       if(sym == mat.sym) // same symmetry property, assign all entries
1489         {
1490           for(; itv != values_.end(); itv++, itm++) *itv = *itm;
1491           return *this;
1492         }
1493     }
1494 
1495   //general case
1496   //   use getrow for lower parts and getcol for upper parts when mat is sym or dual access
1497   //   use getrow when mat is row access ang getcol when mat is col access
1498   //   no analysis of storage access of target matrix, in some cases it may be slow (for instance col storage in row storage)
1499   number_t shr=0, shc=0, nbc=mat.nbCols, nbr=mat.nbRows, m, c, r, p;
1500   if(rows.size()==1) shr=rows[0];
1501   if(cols.size()==1) shc=cols[0];
1502   AccessType msat=mat.accessType();
1503   std::vector<std::pair<number_t, number_t> >::iterator itr, its, itse;
1504   std::map<number_t,number_t>::iterator itv;
1505   const std::vector<K>& valmat=mat.values();
1506 
1507   if(msat==_row || msat==_dual || msat==_sym)  //row in row, lower part of mat
1508     {
1509       m = nbc;
1510       for(number_t k=1; k<=nbr; ++k)
1511         {
1512           if(rows.size()>1) r=rows[k-1];
1513           else r=k+shr;
1514           if(msat!=_row) m=std::min(k, nbc);   //restrict to lower part
1515           std::vector<std::pair<number_t, number_t> > coladrs=mat.getRow(k,1,m);    // retry col indices of row k in mat storage
1516           p=coladrs.size();
1517           if(p>0)
1518             {
1519               std::map<number_t,number_t> colmap;   //reorder column indices : index->adress
1520               if(cols.size()>1)  //implicit col mapping
1521                 for(itr=coladrs.begin(); itr!=coladrs.end(); ++itr) colmap[cols[itr->first-1]]=itr->second;
1522               else //explicit col mapping
1523                 for(itr=coladrs.begin(); itr!=coladrs.end(); ++itr) colmap[itr->first+shc]=itr->second;
1524               number_t minc=colmap.begin()->first, maxc=colmap.rbegin()->first;
1525               std::vector<std::pair<number_t, number_t> > coladrsG=getRow(r,minc,maxc);
1526               its=coladrsG.begin();
1527               itse=coladrsG.end();
1528               for(itv=colmap.begin(); itv!=colmap.end(); ++itv) //assuming valmat is in the same order as values_
1529                 {
1530                   c=itv->first;
1531                   while(its->first != c && its != itse) ++its;
1532                   if(its != itse && its->first == c) values_[its->second] = valmat[itv->second];
1533                 }
1534             }
1535         }
1536     }
1537   //if(sym == _noSymmetry && (msat==_col || msat==_dual || msat==_sym))   //col in row, strict upper part of mat
1538   if(accessType() != _sym && (msat==_col || msat==_dual || msat==_sym))   //col in row, strict upper part of mat
1539     {
1540       m = nbr;
1541       number_t d=2;
1542       if(msat==_col) d=1;
1543       for(number_t k=d; k<=nbc; ++k)
1544         {
1545           if(cols.size()>1) c=cols[k-1];
1546           else c=k+shc;
1547           if(msat!=_col) m=std::min(k-1, nbr);   //restrict to strict upper part
1548           std::vector<std::pair<number_t, number_t> > rowadrs=mat.getCol(k,1,m);    // retry col indices of row k in mat storage
1549           p=rowadrs.size();
1550           if(p>0)
1551             {
1552               std::map<number_t,number_t> rowmap;
1553               if(rows.size()>1)  //implicit row mapping
1554                 for(itr=rowadrs.begin(); itr!=rowadrs.end(); ++itr) rowmap[rows[itr->first-1]]=itr->second;
1555               else //explicit row mapping
1556                 for(itr=rowadrs.begin(); itr!=rowadrs.end(); ++itr) rowmap[itr->first+shr]=itr->second;
1557               number_t minr=rowmap.begin()->first, maxr=rowmap.rbegin()->first;
1558               std::vector<std::pair<number_t, number_t> > rowadrsG= getCol(c,minr,maxr);
1559               its=rowadrsG.begin();
1560               itse=rowadrsG.end();
1561               switch(mat.sym)
1562                 {
1563                 case _selfAdjoint :
1564                 {
1565                   for(itv=rowmap.begin(); itv!=rowmap.end(); ++itv) //assuming valmat is in the same order as values_
1566                     {
1567                       r=itv->first;
1568                       while(its->first != r && its != itse) ++its;
1569                       if(its != itse && its->first == r) values_[its->second] = conj(valmat[itv->second]);
1570                     }
1571                   break;
1572                 }
1573                 case _skewAdjoint:
1574                 {
1575                   for(itv=rowmap.begin(); itv!=rowmap.end(); ++itv) //assuming valmat is in the same order as values_
1576                     {
1577                       r=itv->first;
1578                       while(its->first != r && its != itse) ++its;
1579                       if(its != itse && its->first == r) values_[its->second] = -conj(valmat[itv->second]);
1580                     }
1581                   break;
1582                 }
1583                 case _skewSymmetric :
1584                 {
1585                   for(itv=rowmap.begin(); itv!=rowmap.end(); ++itv) //assuming valmat is in the same order as values_
1586                     {
1587                       r=itv->first;
1588                       while(its->first != r && its != itse) ++its;
1589                       if(its != itse && its->first == r) values_[its->second] = -valmat[itv->second];
1590                     }
1591                   break;
1592                 }
1593                 default : //symmetric or non symmetric
1594                 {
1595                   for(itv=rowmap.begin(); itv!=rowmap.end(); ++itv) //assuming valmat is in the same order as values_
1596                     {
1597                       r=itv->first;
1598                       while(its->first != r && its != itse) ++its;
1599                       if(its != itse &&  its->first == r) values_[its->second] = valmat[itv->second];
1600                     }
1601                 }
1602                 }
1603             }
1604         }
1605     }
1606   return *this;
1607 }
1608 
1609 /*! extract sub matrix of current LargeMatrix and return it as a LargeMatrix
1610     rowIndex : row indices to be extracted (starts from 1)
1611     colIndex : col indices to be extracted (starts from 1)
1612     return a pointer to extracted LargeMatrix in the same storage type of current LargeMatrix
1613 */
1614 template <typename T>
extract(const std::vector<number_t> & rowIndex,const std::vector<number_t> & colIndex) const1615 LargeMatrix<T>* LargeMatrix<T>::extract(const std::vector<number_t>& rowIndex, const std::vector<number_t>& colIndex) const
1616 {
1617   //create new storage
1618   MatrixStorage* sto=storage_p->extract(rowIndex, colIndex);
1619   LargeMatrix<T>* lmsub=new LargeMatrix<T>(sto,sym);
1620   //fill in lmsub using general non optimal algorithm
1621   number_t nbr=rowIndex.size(), nbc=colIndex.size();
1622   Vector<number_t> row = trivialNumbering<number_t>(1, nbr), col=trivialNumbering<number_t>(1, nbc);
1623   std::vector<number_t> adrsub, adrmat;
1624   sto->positions(row, col, adrsub);
1625   storage_p->positions(rowIndex, colIndex, adrmat);
1626   std::vector<number_t>::iterator its=adrsub.begin(), itm=adrmat.begin();
1627   for(; its!=adrsub.end(); ++its, ++itm) lmsub->values_[*its] = values_[*itm];
1628   return lmsub;
1629 }
1630 
1631 /*! extract block matrix [r1,r2]x[c1,c2] of current LargeMatrix and return it as a LargeMatrix
1632     return a pointer to extracted LargeMatrix in the same storage type of current LargeMatrix
1633     r1<=r2,c1<=c2 indices starting from 1
1634 */
1635 template <typename T>
extract(number_t r1,number_t r2,number_t c1,number_t c2) const1636 LargeMatrix<T>* LargeMatrix<T>::extract(number_t r1, number_t r2, number_t c1, number_t c2) const
1637 {
1638   if (r1 == 0)
1639   {
1640     where("LargeMatrix::extract(...)");
1641     error("is_null", "r1");
1642   }
1643   if (r2 < r1)
1644   {
1645     where("LargeMatrix::extract(...)");
1646     error("is_lesser", r2, r1);
1647   }
1648   if (r2 > storage_p->nbOfRows())
1649   {
1650     where("LargeMatrix::extract(...)");
1651     error("is_greater", r2, storage_p->nbOfRows());
1652   }
1653   if (c1 == 0)
1654   {
1655     where("LargeMatrix::extract(...)");
1656     error("is_null", "c1");
1657   }
1658   if (c2 < c1)
1659   {
1660     where("LargeMatrix::extract(...)");
1661     error("is_lesser", c2, c1);
1662   }
1663   if (c2 > storage_p->nbOfColumns())
1664   {
1665     where("LargeMatrix::extract(...)");
1666     error("is_greater", c2, storage_p->nbOfColumns());
1667   }
1668 
1669   StorageType st=storage_p->storageType();
1670   AccessType at=storage_p->accessType();
1671   if(st==_dense && (at==_row || at==_col))  //fast method for row or col dense
1672     {
1673       number_t nbr=r2-r1+1, nbc=c2-c1+1;
1674       std::vector<std::vector<number_t> > indices;//fake indices vector
1675       string_t id = storage_p->stringId+"_"+tostring(r1)+"_"+tostring(r2)+"_"+tostring(c1)+"_"+tostring(c2);
1676       MatrixStorage* sto=createMatrixStorage(st,at, nbr, nbc, indices,id);
1677       LargeMatrix<T>* lmsub(sto,sym);
1678       //fill in lmsub matrix
1679       if(at==_row)
1680         {
1681           typename std::vector<T>::iterator its=lmsub->values_.begin()+1;
1682           typename std::vector<T>::const_iterator itm;
1683           for(number_t r=r1; r<=r2; ++r)
1684             {
1685               itm=values_.begin()+(r-1)*nbCols+c1;
1686               for(number_t c=c1; c<=c2; ++c, ++its, ++itm) *its=*itm;
1687             }
1688           return lmsub;
1689         }
1690       if(at==_col)
1691         {
1692           typename std::vector<T>::iterator its=lmsub->values_.begin()+1;
1693           typename std::vector<T>::const_iterator itm;
1694           for(number_t c=c1; c<=c2; ++c)
1695             {
1696               itm=values_.begin()+(c-1)*nbRows+r1;
1697               for(number_t r=r1; r<=r2; ++r, ++its, ++itm) *its=*itm;
1698             }
1699           return lmsub;
1700         }
1701     }
1702   // call general method
1703   std::vector<number_t> rowIndex=trivialNumbering(r1,r2), colIndex=trivialNumbering(c1,c2);
1704   return extract(rowIndex, colIndex);
1705 }
1706 
1707 
1708 /*---------------------------------------------------------------------------------------------------
1709   LargeMatrix<T> addition utilities
1710 ---------------------------------------------------------------------------------------------------*/
1711 //add LargeMatrix of same type with same storage
1712 template<typename T>
operator +=(const LargeMatrix<T> & mat)1713 LargeMatrix<T>& LargeMatrix<T>::operator+=(const LargeMatrix<T>& mat)
1714 {
1715   //if(storage_p != mat.storage_p) error("largematrix_mismatch_storage");
1716   if(!sameStorage(*storage_p,*mat.storage_p)) error("largematrix_mismatch_storage");
1717   typename std::vector<T>::iterator it = values_.begin() + 1;
1718   typename std::vector<T>::const_iterator itm = mat.values_.begin() + 1;
1719   if(storage_p->accessType() != _sym || sym == mat.sym) //add values
1720     {
1721       for(; it != values_.end(); it++, itm++) *it += *itm;
1722       return *this;
1723     }
1724   //case of symmetric storage but the symmetry properties are different, the result has no symmetry
1725   typename std::vector<T>::iterator itu, ite;
1726   if(sym != _noSymmetry) //values_ vector has to be extended
1727     {
1728       number_t s = values_.size() + storage_p->lowerPartSize();
1729       if(Trace::traceMemory)
1730         {
1731           thePrintStream<<"LargeMatrix::+= re-allocates a large matrix : "<<&values_<<", "
1732                         <<s<<" non zeros coefficients "<<dimValues();
1733           if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
1734           thePrintStream<<eol<<std::flush;
1735         }
1736       values_.resize(s);           //extend values to lowerPartSize
1737       it = values_.begin() + 1;
1738       itu = values_.begin() + 1 + storage_p->diagonalSize() + storage_p->lowerPartSize();
1739       ite = itu;
1740       switch(sym)  //assign lower part to upper part
1741         {
1742         case _selfAdjoint :
1743           for(; it != ite; it++, itu++) *itu = conj(*it);
1744           break;
1745         case _skewSymmetric :
1746           for(; it != ite; it++, itu++) *itu = - *it;
1747           break;
1748         case _skewAdjoint :
1749           for(; it != ite; it++, itu++) *itu = - conj(*it);
1750           break;
1751         case _symmetric :
1752         default         :
1753           for(; it != ite; it++, itu++) *itu = *it;
1754         }
1755       sym = _noSymmetry;
1756     }
1757   it = values_.begin() + 1;
1758   ite = values_.begin() + 1 + storage_p->diagonalSize() + storage_p->lowerPartSize();
1759   itm = mat.values_.begin() + 1;
1760   for(; it != ite; it++, itm++) *it += *itm; //add lower part
1761   if(mat.sym == _noSymmetry) //add upper part
1762     {
1763       for(; it != values_.end(); it++, itm++) *it += *itm;
1764       return *this;
1765     }
1766   itm = mat.values_.begin() + 1;
1767   switch(mat.sym)  //add upper part using lower part
1768     {
1769     case _selfAdjoint :
1770       for(; it != values_.end(); it++, itm++) *it += conj(*itm);
1771       break;
1772     case _skewSymmetric :
1773       for(; it != values_.end(); it++, itm++) *it += - *itm;
1774       break;
1775     case _skewAdjoint :
1776       for(; it != values_.end(); it++, itm++) *it += -conj(*itm);
1777       break;
1778     case _symmetric :
1779     default         :
1780       for(; it != values_.end(); it++, itm++) *it += *itm;
1781     }
1782   return *this;
1783 }
1784 
1785 template<typename T>
operator -=(const LargeMatrix<T> & mat)1786 LargeMatrix<T>& LargeMatrix<T>::operator-=(const LargeMatrix<T>& mat)
1787 {
1788   //if(storage_p != mat.storage_p) error("largematrix_mismatch_storage");
1789   if(!sameStorage(*storage_p,*mat.storage_p)) error("largematrix_mismatch_storage");
1790   typename std::vector<T>::iterator it = values_.begin() + 1;
1791   typename std::vector<T>::const_iterator itm = mat.values_.begin() + 1;
1792   if(storage_p->accessType() != _sym || sym == mat.sym) //add values
1793     {
1794       for(; it != values_.end(); it++, itm++) *it -= *itm;
1795       return *this;
1796     }
1797   //case of symmetric storage but the symmetry properties are different, the result has no symmetry
1798   typename std::vector<T>::iterator itu, ite;
1799   if(sym != _noSymmetry) //values_ vector has to be extended
1800     {
1801       number_t s = values_.size() + storage_p->lowerPartSize();
1802       if(Trace::traceMemory)
1803         {
1804           thePrintStream<<"LargeMatrix::-= re-allocates a large matrix : "<<&values_<<", "
1805                         <<s<<" non zeros coefficients "<<dimValues();
1806           if(storage_p!=0) thePrintStream<<", storage "<<storage_p->name();
1807           thePrintStream<<eol<<std::flush;
1808         }
1809       values_.resize(s);          //extend values to lowerPartSize
1810       it = values_.begin() + 1;
1811       itu = values_.begin() + 1 + storage_p->diagonalSize() + storage_p->lowerPartSize();
1812       ite = itu;
1813       switch(sym)  //assign lower part to upper part
1814         {
1815         case _selfAdjoint :
1816           for(; it != ite; it++, itu++) *itu = conj(*it);
1817           break;
1818         case _skewSymmetric :
1819           for(; it != ite; it++, itu++) *itu = - *it;
1820           break;
1821         case _skewAdjoint :
1822           for(; it != ite; it++, itu++) *itu = - conj(*it);
1823           break;
1824         case _symmetric :
1825         default         :
1826           for(; it != ite; it++, itu++) *itu = *it;
1827         }
1828       sym = _noSymmetry;
1829     }
1830   it = values_.begin() + 1;
1831   ite = values_.begin() + 1 + storage_p->diagonalSize() + storage_p->lowerPartSize();
1832   itm = mat.values_.begin() + 1;
1833   for(; it != ite; it++, itm++) *it -= *itm; //add lower part
1834   if(mat.sym == _noSymmetry) //add upper part
1835     {
1836       for(; it != values_.end(); it++, itm++) *it -= *itm;
1837       return *this;
1838     }
1839 
1840   itm = mat.values_.begin() + 1;
1841   switch(mat.sym)  //add upper part using lower part
1842     {
1843     case _selfAdjoint :
1844       for(; it != values_.end(); it++, itm++) *it -= conj(*itm);
1845       break;
1846     case _skewSymmetric :
1847       for(; it != values_.end(); it++, itm++) *it -= - *itm;
1848       break;
1849     case _skewAdjoint :
1850       for(; it != values_.end(); it++, itm++) *it -= -conj(*itm);
1851       break;
1852     case _symmetric :
1853     default         :
1854       for(; it != values_.end(); it++, itm++) *it -= *itm;
1855     }
1856   return *this;
1857 }
1858 
1859 //add to current LargeMatrix some values given by iterators itb to ite
1860 template <typename T>
1861 template<typename iterator>
add(iterator & itb,iterator & ite)1862 LargeMatrix<T>& LargeMatrix<T>::add(iterator& itb, iterator& ite)
1863 {
1864   typename std::vector<T>::iterator itv=values_.begin();
1865   number_t i=0;
1866   for(iterator it=itb; itb!=ite && i<values_.size(); it++, itv++, i++) *itv+=*it;
1867 }
1868 
1869 // add a matrix (mat) at ranks (rows, cols), values of matrix are stored by row
1870 // when the current matrix has a symetry, only lower part of mat is added
1871 template <typename T>
add(const std::vector<T> & mat,const std::vector<number_t> & rows,const std::vector<number_t> & cols)1872 LargeMatrix<T>& LargeMatrix<T>::add(const std::vector<T>& mat, const std::vector<number_t>& rows, const std::vector<number_t>& cols)
1873 {
1874   std::vector<number_t> pos;
1875   storage_p->positions(rows, cols, pos, true, sym); //get adresses of submatrix elements
1876   typename std::vector<T>::const_iterator itm = mat.begin();
1877   typename std::vector<T>::iterator itv = values_.begin();
1878   std::vector<number_t>::iterator itp;
1879   if(sym == _noSymmetry) //add full matrix mat
1880     for(itp = pos.begin(); itp != pos.end(); itp++, itm++)
1881       {
1882         *(itv + *itp) += *itm;
1883       }
1884   else                 //add lower part of mat in "symmetric" matrix
1885     {
1886       itp = pos.begin();
1887       for(number_t i = 0; i < rows.size(); i++, itm += cols.size())
1888         for(number_t j = 0; j < cols.size(); j++)
1889           if(rows[i] >= cols[j])
1890             {
1891               *(itv + *itp) += *(itm + j);
1892               itp++;
1893             }
1894     }
1895   return *this;
1896 }
1897 
1898 // add a constant to submatrix given by its ranks (rows, cols)
1899 template <typename T>
add(const T & c,const std::vector<number_t> & rows,const std::vector<number_t> & cols)1900 LargeMatrix<T>& LargeMatrix<T>::add(const T& c, const std::vector<number_t>& rows, const std::vector<number_t>& cols)
1901 {
1902   std::vector<number_t> pos;
1903   storage_p->positions(rows, cols, pos, true, sym); //get adresses of submatrix elements (only lower part if current matrix has symmetry)
1904   typename std::vector<T>::const_iterator itm;
1905   typename std::vector<T>::iterator itv = values_.begin();
1906   std::vector<number_t>::iterator itp;
1907   for(itp = pos.begin(); itp != pos.end(); itp++, itm++)
1908     {
1909       *(itv + *itp) += c;
1910     }
1911   return *this;
1912 }
1913 
1914 /*! add to current LargeMatrix a scaled LargeMatrix mat (submatrix) given by its ranks (rows, cols) in current matrix and a scaling factor (scale)
1915   a void rows or cols  means that the numbering of mat is the same as current matrix
1916   in that case, if the storage of mat and current matrix are the same, direct summation is used
1917   else access to position is used (expansive method)
1918    no storage update !!!
1919 */
1920 template <typename T>
1921 template <typename K, typename C>
add(const LargeMatrix<K> & mat,const std::vector<number_t> & rows,const std::vector<number_t> & cols,C scale)1922 LargeMatrix<T>& LargeMatrix<T>::add(const LargeMatrix<K>& mat, const std::vector<number_t>& rows,
1923                                     const std::vector<number_t>& cols, C scale)
1924 {
1925   if(strucType != mat.strucType) error("largematrix_mismatch_structure");
1926   if(dimValues() != mat.dimValues()) error("largematrix_mismatch_size");
1927   if(sym != _noSymmetry && mat.sym == _noSymmetry) error("nonsym_to_sym", "addition");
1928   if(sym != _noSymmetry && mat.sym != _noSymmetry && sym != mat.sym)
1929     error("largematrix_diff_sym");
1930 
1931   //simple case : same storage and same symmetry
1932   if(rows.size() == 0 && cols.size() == 0 && storage_p == mat.storagep())
1933     {
1934       typename std::vector<T>::iterator itv = values_.begin();
1935       typename std::vector<K>::const_iterator itm = mat.values().begin();
1936       if(sym == mat.sym) // same symmetry property, add all entries
1937         {
1938           for(; itv != values_.end(); itv++, itm++) *itv += scale** itm;
1939           return *this;
1940         }
1941     }
1942 
1943   //general case, use positions (no optimisation, to be improved)
1944   std::vector<number_t> num_r = rows;
1945   std::vector<number_t> num_c = cols;
1946   std::vector<number_t>::iterator it;
1947   //if(num_r.size() == 0) //if rows is void, take all the rows
1948   if(num_r.size() <= 1) //take all the rows and shift by num_r[0] if exists, no shift else
1949     {
1950       number_t n = 1, shr=0;
1951       if(num_r.size()==1) shr=num_r[0];
1952       //num_r.resize(nbRows);
1953       num_r.resize(mat.nbRows);
1954       n+=shr;
1955       for(it = num_r.begin(); it != num_r.end(); it++, n++) *it = n;
1956     }
1957   //if(num_c.size() == 0) //if cols is void, take all the cols
1958   if(num_c.size() <= 1) //take all the rows and shift by num_c[0] if exists, no shift else
1959     {
1960       number_t n = 1, shc=0;
1961       if(num_c.size()==1) shc=num_c[0];
1962       //num_c.resize(nbCols);
1963       num_c.resize(mat.nbCols);
1964       n+=shc;
1965       for(it = num_c.begin(); it != num_c.end(); it++, n++) *it = n;
1966     }
1967 
1968   //loop on submatrix rows
1969   number_t r = 1;
1970   for(it = num_r.begin(); it != num_r.end(); it++, r++)
1971     {
1972       //get adresses of row r of matrix mat
1973       std::vector<number_t> mcols(num_c.size()), mrows(1, r), mpos, cpos;
1974       std::vector<number_t>::iterator itc, itp, itq;
1975       number_t c = 1;
1976       for(itc = mcols.begin(); itc != mcols.end(); itc++, c++) *itc = c;
1977       mat.storagep()->positions(mrows, mcols, mpos, false, mat.sym);     //get adresses of mat coefficients on row n (zero coefficient have a zero adress)
1978 
1979       //translate row/columns indices into numbering of current matrix and get positions into
1980       itc = mcols.begin();
1981       itq = mpos.begin();
1982       std::vector<number_t>::iterator itn = num_c.begin();
1983       number_t n = 0;
1984       for(itp = mpos.begin(); itp != mpos.end(); itp++, itn++)  //keep non zero addresses
1985         {
1986           if(*itp != 0)
1987             {
1988               *itc = *itn;
1989               *itq = *itp;
1990               itc++;
1991               itq++;
1992               n++;
1993             }
1994         }
1995       mcols.resize(n);
1996       mpos.resize(n);
1997       mrows[0] = *it;
1998       positions(mrows, mcols, cpos, false); //get addresses of row n in current matrix
1999 
2000       // do combination
2001       itp = cpos.begin(), itq = mpos.begin();
2002       if(sym == _noSymmetry)
2003         {
2004           switch(mat.sym)
2005             {
2006             case _skewSymmetric :
2007               for(itc = mcols.begin(); itc != mcols.end() ; itc++, itp++, itq++)
2008                 if(*it >= *itc) values_[*itp] += scale * mat(*itq); //lower triangular part
2009                 else values_[*itp] -= scale * mat(*itq);            //upper triangular part
2010               break;
2011             case _selfAdjoint :
2012               for(itc = mcols.begin(); itc != mcols.end() ; itc++, itp++, itq++)
2013                 if(*it >= *itc) values_[*itp] += scale * mat(*itq); //lower triangular part
2014                 else values_[*itp] += scale * conj(mat(*itq));       //upper triangular part
2015               break;
2016             case _skewAdjoint :
2017               for(itc = mcols.begin(); itc != mcols.end() ; itc++, itp++, itq++)
2018                 if(*it >= *itc) values_[*itp] += scale * mat(*itq); //lower triangular part
2019                 else values_[*itp] -= scale * conj(mat(*itq));       //upper triangular part
2020               break;
2021             default : //no symmetry or symmetric
2022               for(itc = mcols.begin(); itc != mcols.end(); itc++, itp++, itq++)
2023                 values_[*itp] += scale * mat(*itq);
2024             }
2025         }
2026       else if(mat.sym == sym) //same symmetry property
2027         {
2028           for(itc = mcols.begin(); itc != mcols.end(); itc++, itp++, itq++)
2029             if(*it >= *itc) values_[*itp] += scale * mat(*itq);
2030         }
2031       else
2032         error("largematrix_mismatch_sym");
2033     }
2034   return *this;
2035 }
2036 
2037 // combine cols of matrix : c2 = c2 + a *c1 (indices start from 1) with update storage option
2038 // use getCols
2039 template <typename T>
addColToCol(number_t c1,number_t c2,complex_t a,bool updateStorage)2040 void LargeMatrix<T>::addColToCol(number_t c1, number_t c2, complex_t a, bool updateStorage)
2041 {
2042   ScalarType b = complexToT<ScalarType>(a);
2043   std::set<number_t> rowsc1= storage_p->getRows(c1), rowsc2=storage_p->getRows(c2);
2044   rowsc1.insert(rowsc2.begin(),rowsc2.end());
2045   if(rowsc1.size()==rowsc2.size())  // same set of rows (compatible storage) do combination
2046     {
2047       std::vector<std::pair<number_t, number_t> > adrs1=getCol(c1), adrs2=getCol(c2);
2048       std::vector<std::pair<number_t, number_t> >::iterator it1=adrs1.begin(), it2=adrs2.begin();
2049       std::map<number_t,number_t> mapadrs2;
2050       for(; it2!=adrs2.end(); it2++)  mapadrs2[it2->first] = it2->second;
2051       for(; it1!=adrs1.end(); it1++)  values_[mapadrs2[it1->first]] += b *values_[it1->second];
2052       return;
2053     }
2054   if(!updateStorage)
2055     {
2056       where("LargeMatrix<T>::addColToCol(...)");
2057       error("storage_not_updated");
2058     }
2059   //update storage (expansive  operation)
2060   error("not_yet_implemented",string_t("LargeMatrix<T>::addColToCol(...)")+string_t(" ")+words("with dynamic update storage"));
2061 }
2062 
2063 // combine rows of matrix : r2 = r2 + a *r1 (indices start from 1) with update storage option
2064 // use getRows
2065 template <typename T>
addRowToRow(number_t r1,number_t r2,complex_t a,bool updateStorage)2066 void LargeMatrix<T>::addRowToRow(number_t r1, number_t r2, complex_t a, bool updateStorage)
2067 {
2068   ScalarType b = complexToT<ScalarType>(a);
2069   std::set<number_t> colsr1= storage_p->getCols(r1), colsr2=storage_p->getCols(r2);
2070   colsr1.insert(colsr2.begin(),colsr2.end());
2071   if(colsr1.size()==colsr2.size())  // compatible storage, do combination
2072     {
2073       std::vector<std::pair<number_t, number_t> > adrs1=getRow(r1), adrs2=getRow(r2);
2074       std::vector<std::pair<number_t, number_t> >::iterator it1=adrs1.begin(), it2=adrs2.begin();
2075       std::map<number_t,number_t> mapadrs2;
2076       for(; it2!=adrs2.end(); it2++)  mapadrs2[it2->first] = it2->second;
2077       for(; it1!=adrs1.end(); it1++)  values_[mapadrs2[it1->first]] += b *values_[it1->second];
2078       return;
2079     }
2080   if(!updateStorage)
2081     {
2082       where("LargeMatrix<T>::addColToCol(...)");
2083       error("storage_not_updated");
2084     }
2085   //update storage (expansive  operation)
2086   error("not_yet_implemented",string_t("LargeMatrix<T>::addRowToRow(...)")+string_t(" ")+words("with dynamic update storage"));
2087 }
2088 
2089 // norm of a LargeMatrix (Frobenius norm)
2090 template <typename T>
norm2() const2091 real_t LargeMatrix<T>::norm2() const
2092 {
2093   real_t n=0.;
2094   typename std::vector<T>::const_iterator itm=values_.begin()+1;
2095   for(; itm!=values_.end(); ++itm)
2096     {
2097       real_t t = xlifepp::norm2(*itm);
2098       n+=t*t;
2099     }
2100   if(storage_p->accessType()==_sym) //add the strict lower part
2101     {
2102       itm=values_.begin()+1+storage_p->diagonalSize();
2103       for(; itm!=values_.end(); ++itm)
2104         {
2105           real_t t = xlifepp::norm2(*itm);
2106           n+=t*t;
2107         }
2108     }
2109   return std::sqrt(n);
2110 }
2111 
2112 template <typename T>
norm2(const LargeMatrix<T> & A)2113 inline real_t norm2(const LargeMatrix<T>& A)
2114 {
2115   return A.norm2();
2116 }
2117 
2118 // norm infinite of a LargeMatrix
2119 template <typename T>
norminfty() const2120 real_t LargeMatrix<T>::norminfty() const
2121 {
2122   real_t n=0.;
2123   typename std::vector<T>::const_iterator itm=values_.begin()+1;
2124   for(; itm!=values_.end(); ++itm)
2125     {
2126       real_t t = xlifepp::norminfty(*itm);
2127       if(t>n) n=t;
2128     }
2129   return n;
2130 }
2131 
2132 template <typename T>
norminfty(const LargeMatrix<T> & A)2133 inline real_t norminfty(const LargeMatrix<T>& A)
2134 {
2135   return A.norminfty();
2136 }
2137 
2138 // partial norm of column c, only components in range [r1,r2]
2139 template <typename T>
partialNormOfCol(number_t c,number_t r1,number_t r2) const2140 real_t LargeMatrix<T>::partialNormOfCol(number_t c, number_t r1, number_t r2) const
2141 {
2142   real_t n=0.;
2143   std::vector<std::pair<number_t, number_t> > rowadrs=getCol(c,r1,r2);
2144   std::vector<std::pair<number_t, number_t> >::iterator itra=rowadrs.begin();
2145   for(; itra!=rowadrs.end(); itra++) n += xlifepp::norm2(values_[itra->second]);
2146   return std::sqrt(n);
2147 }
2148 
2149 //! get col c (>=1) as vector
2150 template <typename T>
col(number_t c) const2151 std::vector<T> LargeMatrix<T>::col(number_t c) const
2152 {
2153   std::vector<T> vcol(nbRows,T());
2154   std::vector<std::pair<number_t, number_t> > rowadr=getCol(c); // get (row indices, adresses) of col c
2155   std::vector<std::pair<number_t, number_t> >::iterator ita=rowadr.begin();
2156   for(; ita!=rowadr.end(); ++ita) vcol[ita->first-1]=values_[ita->second];
2157   return vcol;
2158 }
2159 
2160 //! get row r (>=1) as vector
2161 template <typename T>
row(number_t r) const2162 std::vector<T> LargeMatrix<T>::row(number_t r) const
2163 {
2164   std::vector<T> vrow(nbCols,T());
2165   std::vector<std::pair<number_t, number_t> > coladr=getRow(r); // get (row indices, adresses) of col c
2166   std::vector<std::pair<number_t, number_t> >::iterator ita=coladr.begin();
2167   for(; ita!=coladr.end(); ++ita) vrow[ita->first-1]=values_[ita->second];
2168   return vrow;
2169 }
2170 
2171 // delete rows r1,..., r2 (may be expansive for some storage)
2172 template <typename T>
deleteRows(number_t r1,number_t r2)2173 void LargeMatrix<T>::deleteRows(number_t r1, number_t r2)
2174 {
2175   if(storage_p!=0)
2176     {
2177       storage_p->deleteRows(r1, r2, values_,sym);
2178       nbRows=storage_p->nbOfRows();
2179     }
2180 }
2181 // delete cols c1,..., c2 (may be expansive for some storage)
2182 template <typename T>
deleteCols(number_t c1,number_t c2)2183 void LargeMatrix<T>::deleteCols(number_t c1, number_t c2)
2184 {
2185   if(storage_p!=0)
2186     {
2187       storage_p->deleteCols(c1, c2, values_,sym);
2188       nbCols=storage_p->nbOfColumns();
2189     }
2190 }
2191 
2192 // set to 0 cols/rows cr1,..., cr2 (index start from 1), no col/row deletion
2193 // generic algorithm use getCol/getRow of storage,
2194 // may be slightly improved by using storage child versions, not yet done
2195 template <typename T>
setColToZero(number_t c1,number_t c2)2196 void LargeMatrix<T>:: setColToZero(number_t c1, number_t c2)
2197 {
2198   if(c1==0)
2199     {
2200       c1=1;
2201       c2=nbCols;
2202     }
2203   if(c2==0)
2204     {
2205       c2=nbCols;
2206     }
2207   if(c1>c2) return;
2208   std::vector<std::pair<number_t, number_t> > adrs;
2209   std::vector<std::pair<number_t, number_t> >::iterator ita;
2210   for(number_t c=c1; c<=c2; c++)
2211     {
2212       adrs = getCol(c, 1, 0);  //get adresses of all non zero of column c
2213       if(sym ==_noSymmetry)
2214         for(ita=adrs.begin(); ita!=adrs.end(); ita++) values_[ita->second]=T(0);
2215       else //matrix with symmetry property
2216         for(ita=adrs.begin(); ita!=adrs.end(); ita++)
2217           if(ita->first >= c) values_[ita->second]=T(0);
2218     }
2219 }
2220 
2221 template <typename T>
setRowToZero(number_t r1,number_t r2)2222 void LargeMatrix<T>:: setRowToZero(number_t r1, number_t r2)
2223 {
2224   if(r1==0)
2225     {
2226       r1=1;
2227       r2=nbRows;
2228     }
2229   if(r2==0)
2230     {
2231       r2=nbRows;
2232     }
2233   if(r1>r2) return;
2234   std::vector<std::pair<number_t, number_t> > adrs;
2235   std::vector<std::pair<number_t, number_t> >::iterator ita;
2236   for(number_t r=r1; r<=r2; r++)
2237     {
2238       adrs = getRow(r, 1, 0);  //get adresses of all non zero of row c
2239       if(sym ==_noSymmetry)
2240         for(ita=adrs.begin(); ita!=adrs.end(); ita++) values_[ita->second]=T(0);
2241       else //matrix with symmetry property
2242         for(ita=adrs.begin(); ita!=adrs.end(); ita++)
2243           if(ita->first <= r) values_[ita->second]=T(0);
2244     }
2245 }
2246 
2247 /*! copy in current matrix values of mat located at mat_adrs at position cur_adrs
2248   it is assumed that mat_adrs and cur_adrs have the same size (address map!)
2249 */
2250 template <typename T>
copyVal(const LargeMatrix<T> & mat,const std::vector<number_t> & mat_adrs,const std::vector<number_t> & cur_adrs)2251 void LargeMatrix<T>::copyVal(const LargeMatrix<T>& mat, const std::vector<number_t>& mat_adrs, const std::vector<number_t>& cur_adrs)
2252 {
2253   if (cur_adrs.size() != mat_adrs.size())
2254   {
2255     where("LargeMatrix<T>::copyVal(...)");
2256     error("bad_size", "address map", mat_adrs.size(), cur_adrs.size());
2257   }
2258   std::vector<number_t>::const_iterator itma=mat_adrs.begin(), itca=cur_adrs.begin();
2259   number_t sma=mat.values_.size()-1, sca=values_.size()-1;
2260   for (; itma!=mat_adrs.end(); itma++, itca++)
2261   {
2262     if (*itma > sma)
2263     {
2264       where("LargeMatrix<T>::copyVal(...)");
2265       error("index_out_of_range", "itma", 0, sma);
2266     }
2267     if (*itca >sca)
2268     {
2269       where("LargeMatrix<T>::copyVal(...)");
2270       error("index_out_of_range", "itca", 0, sca);
2271     }
2272     values_[*itca]=mat.values_[*itma];
2273   }
2274 }
2275 
2276 /*---------------------------------------------------------------------------------------------------
2277   LargeMatrix<T> print utilities
2278 ---------------------------------------------------------------------------------------------------*/
2279 template <typename T>
print(std::ostream & os) const2280 void LargeMatrix<T>::print(std::ostream& os) const
2281 {
2282   if(theVerboseLevel == 0)
2283     {
2284       return;
2285     }
2286   number_t nnz = nbNonZero();
2287   string_t vt = words("value", valueType_) + " " + words("structure", strucType);
2288   string_t sto = "undefined storage";
2289   if(storage_p != 0)
2290     {
2291       sto = words("access type", storage_p->accessType()) + " " + words("storage type", storage_p->storageType());
2292     }
2293   os << message("largematrix_header", words("symmetry", sym), vt, nbRows, nbCols, sto, nnz)<<eol;
2294   if(theVerboseLevel > 0 && storage_p != 0)
2295     {
2296       storage_p->printEntries(os, values_, theVerboseLevel, sym);
2297       number_t n=rowPermutation_.size();
2298       if(n>0)
2299         {
2300           os<<"row permutation : [";
2301           if(n<=2*theVerboseLevel)
2302             {
2303               for(number_t i=0; i<n; i++) os<<rowPermutation_[i]<<" ";
2304             }
2305           else
2306             {
2307               for(number_t i=0; i<theVerboseLevel; i++) os<<rowPermutation_[i]<<" ";
2308               os<<"... ";
2309               for(number_t i=n-theVerboseLevel; i<n; i++) os<<rowPermutation_[i]<<" ";
2310             }
2311           os<<"]"<<eol;
2312         }
2313       n=colPermutation_.size();
2314       if(n>0)
2315         {
2316           os<<"column permutation : [";
2317           if(n<=2*theVerboseLevel)
2318             {
2319               for(number_t i=0; i<n; i++) os<<colPermutation_[i]<<" ";
2320             }
2321           else
2322             {
2323               for(number_t i=0; i<theVerboseLevel; i++) os<<colPermutation_[i]<<" ";
2324               os<<"... ";
2325               for(number_t i=n-theVerboseLevel; i<n; i++) os<<colPermutation_[i]<<" ";
2326             }
2327           os<<"]"<<eol;
2328         }
2329     }
2330 }
2331 
2332 //! output stream operator
2333 template <typename T>
operator <<(std::ostream & os,const LargeMatrix<T> & mat)2334 std::ostream& operator<<(std::ostream& os, const LargeMatrix<T>& mat)
2335 {
2336   mat.print(os);
2337   return os;
2338 }
2339 
2340 //visualize storage on output stream (like spy on matlab)
2341 template <typename T>
viewStorage(std::ostream & os) const2342 void LargeMatrix<T>::viewStorage(std::ostream& os) const
2343 {
2344   storage_p->visual(os);
2345 }
2346 
2347 /*---------------------------------------------------------------------------------------------------
2348   save to file utilities
2349 ---------------------------------------------------------------------------------------------------*/
2350 /* save matrix to a file along different format
2351    only _dense and _coo storage type are allowed
2352    the file format being consistent with Matlab load functions
2353    if encodeName is true, the name of file includes some additionnal matrix informations
2354     newname = name(m_n_SorageType_ValueType_StructType_p_q).ext
2355    (m,n) size of matrix, (p,q) size of submatrices if StrucType=_matrix
2356 */
2357 
2358 template <typename T>
saveToFile(const string_t & fn,StorageType st,bool encodeName) const2359 void LargeMatrix<T>::saveToFile(const string_t& fn, StorageType st, bool encodeName) const
2360 {
2361   string_t fen = fn;
2362   if(encodeName)
2363     {
2364       fen = encodeFileName(fn, st);
2365     }
2366   std::ofstream of(fen.c_str());
2367   if(of.fail())
2368     {
2369       error("file_failopen", "LargeMatrix<T>::saveToFile", fen);
2370     }
2371   of.precision(fullPrec);
2372   switch(st)
2373     {
2374     case _dense :
2375       storage_p->printDenseMatrix(of, values_, sym);
2376       break;
2377     case _coo   :
2378       storage_p->printCooMatrix(of, values_, sym);
2379       break;
2380     default :
2381       error("largematrix_nosavematrix", words("storage type", st));
2382     }
2383   of.close();
2384 }
2385 
2386 template <typename T>
saveToFile(const char * fn,StorageType st,bool encodeName) const2387 void LargeMatrix<T>::saveToFile(const char* fn, StorageType st, bool encodeName) const
2388 {
2389   string_t fen = fn;
2390   saveToFile(fen,st,encodeName);
2391 }
2392 
2393 //encode file name with additionnal matrix informations
2394 //  n=name.ext -> name(m_n_SorageType_ValueType_StructType_p_q).ext
2395 // (m,n) size of matrix, (p,q) size of submatrices if StrucType=_matrix
2396 template <typename T>
encodeFileName(const string_t & fn,StorageType st) const2397 string_t  LargeMatrix<T>::encodeFileName(const string_t& fn, StorageType st) const
2398 {
2399   number_t pos = fn.find_last_of('.');
2400   string_t fr, ext = "", stn = "dense", vt = "real";
2401   if(valueType_ == _complex)
2402     {
2403       vt = "complex";
2404     }
2405   if(st == _coo)
2406     {
2407       stn = "coo";
2408     }
2409   if(pos != string_t::npos)
2410     {
2411       fr = fn.substr(0, pos);
2412       ext = fn.substr(pos);
2413     }
2414   else
2415     {
2416       fr = fn;
2417     }
2418   fr += "(" + tostring(nbRows) + "_" + tostring(nbCols) + "_" + stn + "_" + vt;
2419   if(strucType == _scalar)
2420     {
2421       fr += "_scalar)" + ext;
2422     }
2423   else
2424     {
2425       fr += "_scalar_" + tostring(nbRowsSub) + "_" + tostring(nbColsSub) + ")" + ext;
2426     }
2427   return fr;
2428 }
2429 
2430 /*---------------------------------------------------------------------------------------------------
2431  load matrix from a file either
2432    in dense format (s=_dense)     :   A11 A12 ...  A1n       re(A11) im(A11)  re(A21) im(A21) ...
2433                                       A21 A22 ...  A2n       re(A21) im(A21)  re(A22) im(A22) ...
2434                     ....                   ...
2435    in coordinate format (st=_coo) :   i j Aij (one per row) or if complex values : i j re(Aij) im(Aij)
2436  only space separator
2437  storage type, acces type, value type, struct type and symmetry of the matrix have to be already set
2438  calls the virtual storage_p->loadFromFileDense or storage_p->loadFromFileCoo functions
2439 ---------------------------------------------------------------------------------------------------*/
2440 template <typename T>
loadFromFile(const string_t & fn,StorageType stf)2441 void LargeMatrix<T>::loadFromFile(const string_t& fn, StorageType stf)
2442 {
2443   trace_p->push("LargeMatrix::loadFromFile");
2444   std::ifstream ifs(fn.c_str());
2445   if(ifs.fail()) error("file_failopen", "LargeMatrix::loadFromFile", fn);
2446 
2447   //check compatibility by analysing first line
2448   string_t line;
2449   std::getline(ifs, line);
2450   line = trim(line);
2451   std::stringstream ss(line);
2452   real_t r;
2453   number_t nbc = 0;
2454   while(!ss.eof())
2455     {
2456       ss >> r;
2457       nbc++;
2458     }
2459   number_t nbcw = 0, nbcwr = 0;
2460   if(stf == _dense)
2461     {
2462       nbcw = nbCols * nbColsSub;
2463       nbcwr = 2 * nbcw;
2464     }
2465   else
2466     {
2467       nbcw = 3;
2468       nbcwr = 4;
2469     }
2470   if((valueType_ == _real && nbc != nbcw) || (valueType_ == _complex && nbc != nbcw && nbc != nbcwr))
2471     {
2472       ss.str(string_t());
2473       ss.clear();
2474       ss << "LargeMatrix::loadFromFile(" << fn << ", " << words("storage type", stf) << ")";
2475       error("bad_dim", ss.str(), nbcw, nbc);
2476     }
2477   bool rAsC = (valueType_ == _complex && nbc == nbcw);
2478   //call child functions
2479   ifs.clear();
2480   ifs.seekg(0, std::ios::beg);  //go to the beginning of file
2481   storage_p->clear();
2482   switch(stf)
2483     {
2484     case _dense:
2485       storage_p->loadFromFileDense(ifs, values_, sym, rAsC);
2486       break;
2487     case _coo:
2488       storage_p->loadFromFileCoo(ifs, values_, sym, rAsC);
2489       break;
2490     default:
2491       where("LargeMatrix::loadFromFile");
2492       error("storage_not_handled", words("storage type", stf), words("access type", _noAccess));
2493     }
2494   ifs.close();
2495   trace_p->pop();
2496 }
2497 
2498 /*======================================================================================================
2499   special matrix product used by svd compression methods
2500   LargeMatrix * MatCol or MatCol * LargeMatrix or LargeMatrix * MatRow or MatRow * LargeMatrix
2501   =====================================================================================================*/
2502 /*! do the product R = A * M where
2503        A is any largeMatrix
2504        pM pointer to the first element of the dense col matrix
2505        pR pointer to the first element of the dense col result matrix
2506        p the number of cols of M
2507        assuming the number of rows of M is equal to the number of cols of A
2508 */
2509 template<typename T>
multMatrixCol(T * pM,T * pR,number_t p) const2510 void LargeMatrix<T>::multMatrixCol(T* pM, T* pR, number_t p) const
2511 {
2512   number_t m=numberOfRows(), n=numberOfCols();
2513   T* pRk=pR, *pMk=pM;
2514   typename std::vector<T>::const_iterator itAb=values_.begin()+1, itA;
2515   if(storageType()==_dense) //fast algorithm
2516     {
2517       if(accessType()==_row)
2518         {
2519           for(number_t j=0; j<p; ++j)
2520             for(number_t i=0; i<m; ++i, ++pRk)
2521               {
2522                 T rij=T();
2523                 itA=itAb+i*n;
2524                 pMk=pM+j*n;
2525                 for(number_t k=0; k<n; ++k, ++itA, ++pMk) rij+=*itA**pMk;
2526                 *pRk=rij;
2527               }
2528           return;
2529         }
2530       if(accessType()==_col)
2531         {
2532           for(number_t j=0; j<p; ++j)
2533             for(number_t i=0; i<m; ++i, ++pRk)
2534               {
2535                 T rij=T();
2536                 itA=itAb+i;
2537                 pMk=pM+j*n;
2538                 for(number_t k=0; k<n; ++k, itA+=m, ++pMk) rij+=*itA**pMk;
2539                 *pRk=rij;
2540               }
2541           return;
2542         }
2543     }
2544   //general case : use matrix vector product
2545   for(number_t k=0; k<p; ++k, pRk+=n, pMk+=n)
2546     multMatrixVector(*this, pMk, pRk);
2547 }
2548 
2549 /*! do the product R = M * A where
2550        A is any largeMatrix
2551        pM pointer to the first element of the dense col matrix
2552        pR pointer to the first element of the dense col result matrix
2553        p the number of rows of M
2554        assuming the number of rows of M is equal to the number of cols of A
2555 */
2556 template<typename T>
multLeftMatrixCol(T * pM,T * pR,number_t p) const2557 void LargeMatrix<T>::multLeftMatrixCol(T* pM, T* pR, number_t p) const
2558 {
2559   number_t m=numberOfRows(), n=numberOfCols();
2560   T* pRk=pR, *pMk=pM;
2561   typename std::vector<T>::const_iterator itAb=values_.begin()+1, itA;
2562   if(storageType()==_dense) //fast algorithm
2563     {
2564       if(accessType()==_row)
2565         {
2566           for(number_t j=0; j<n; ++j)
2567             for(number_t i=0; i<p; ++i, ++pRk)
2568               {
2569                 T rij=T();
2570                 itA=itAb+j;
2571                 pMk=pM+i;
2572                 for(number_t k=0; k<m; ++k, itA+=n, pMk+=p) rij+=*pMk ** itA;
2573                 *pRk=rij;
2574               }
2575           return;
2576         }
2577       if(accessType()==_col)
2578         {
2579           for(number_t j=0; j<n; ++j)
2580             for(number_t i=0; i<p; ++i, ++pRk)
2581               {
2582                 T rij=T();
2583                 itA=itAb+j*m;
2584                 pMk=pM+i;
2585                 for(number_t k=0; k<m; ++k, itA++, pMk+=p) rij+=*pMk ** itA;
2586                 *pRk=rij;
2587               }
2588           return;
2589         }
2590     }
2591   //general case : use matrix vector product
2592   std::vector<T> x(n), y(m);
2593   typename std::vector<T>::iterator itx;
2594   for(number_t i=0; i<p; ++i)
2595     {
2596       pMk=pM+i;
2597       for(itx=x.begin(); itx!=x.end(); ++itx, pMk+=p) *itx = *pMk;
2598       multVectorMatrix(*this, x, y);
2599       pRk=pR+i;
2600       for(itx=y.begin(); itx!=y.end(); ++itx, pRk+=p) *pRk = *itx;
2601     }
2602 }
2603 
2604 
2605 /*! do the product R = A * M where
2606        A is any largeMatrix
2607        pM pointer to the first element of the dense row matrix
2608        pR pointer to the first element of the dense row result matrix
2609        p the number of cols of M
2610        assuming the number of rows of M is equal to the number of cols of A
2611 */
2612 template<typename T>
multMatrixRow(T * pM,T * pR,number_t p) const2613 void LargeMatrix<T>::multMatrixRow(T* pM, T* pR, number_t p) const
2614 {
2615   number_t m=numberOfRows(), n=numberOfCols();
2616   T* pRk=pR, *pMk=pM;
2617   typename std::vector<T>::const_iterator itAb=values_.begin()+1, itA;
2618   if(storageType()==_dense) //fast algorithm
2619     {
2620       if(accessType()==_row)
2621         {
2622           for(number_t i=0; i<m; ++i)
2623             for(number_t j=0; j<p; ++j, ++pRk)
2624               {
2625                 T rij=T();
2626                 itA=itAb+i*n;
2627                 pMk=pM+j;
2628                 for(number_t k=0; k<n; ++k, ++itA, pMk+=p) rij+=*itA**pMk;
2629                 *pRk=rij;
2630               }
2631           return;
2632         }
2633       if(accessType()==_col)
2634         {
2635           for(number_t i=0; i<m; ++i)
2636             for(number_t j=0; j<p; ++j, ++pRk)
2637               {
2638                 T rij=T();
2639                 itA=itAb+i;
2640                 pMk=pM+j;
2641                 for(number_t k=0; k<n; ++k, itA+=m, pMk+=p) rij+=*itA**pMk;
2642                 *pRk=rij;
2643               }
2644           return;
2645         }
2646     }
2647   //general case : use matrix vector product
2648   std::vector<T> x(n), y(m);
2649   typename std::vector<T>::iterator itx;
2650   for(number_t j=0; j<p; ++j)
2651     {
2652       pMk=pM+j;
2653       for(itx=x.begin(); itx!=x.end(); ++itx, pMk+=p) *itx = *pMk;
2654       multMatrixVector(*this, x, y);
2655       pRk=pR+j;
2656       for(itx=y.begin(); itx!=y.end(); ++itx, pRk+=p) *pRk = *itx;
2657     }
2658 }
2659 
2660 /*! do the product R = M * A where
2661        A is any largeMatrix
2662        pM pointer to the first element of the dense row matrix
2663        pR pointer to the first element of the dense row result matrix
2664        p the number of rows of M
2665        assuming the number of rows of M is equal to the number of cols of A
2666 */
2667 template<typename T>
multLeftMatrixRow(T * pM,T * pR,number_t p) const2668 void LargeMatrix<T>::multLeftMatrixRow(T* pM, T* pR, number_t p) const
2669 {
2670   number_t m=numberOfRows(), n=numberOfCols();
2671   T* pRk=pR, *pMk=pM;
2672   typename std::vector<T>::const_iterator itAb=values_.begin()+1, itA;
2673   if(storageType()==_dense) //fast algorithm
2674     {
2675       if(accessType()==_row)
2676         {
2677           for(number_t i=0; i<p; ++i)
2678             for(number_t j=0; j<n; ++j, ++pRk)
2679               {
2680                 T rij=T();
2681                 itA=itAb+j;
2682                 pMk=pM+i*m;
2683                 for(number_t k=0; k<m; ++k, itA+=n, pMk++) rij+=*pMk**itA;
2684                 *pRk=rij;
2685               }
2686           return;
2687         }
2688       if(accessType()==_col)
2689         {
2690           for(number_t i=0; i<p; ++i)
2691             for(number_t j=0; j<n; ++j, ++pRk)
2692               {
2693                 T rij=T();
2694                 itA=itAb+j*m;
2695                 pMk=pM+i*m;
2696                 for(number_t k=0; k<m; ++k, itA++, pMk++) rij+=*pMk**itA;
2697                 *pRk=rij;
2698               }
2699           return;
2700         }
2701     }
2702   //general case : use matrix vector product
2703   std::vector<T> x(m), y(n);
2704   typename std::vector<T>::iterator itx;
2705   for(number_t i=0; i<p; ++i)
2706     {
2707       pMk=pM+i*m;
2708       for(itx=x.begin(); itx!=x.end(); ++itx, pMk++) *itx = *pMk;
2709       multVectorMatrix(*this, x, y);
2710       pRk=pR+i*n;
2711       for(itx=y.begin(); itx!=y.end(); ++itx, pRk++) *pRk = *itx;
2712     }
2713 }
2714 
2715 /*---------------------------------------------------------------------------------------------------
2716   extern operations for LargeMatrix
2717   for each functionnality, consistant template version
2718   and consistant specializations (real_t/complex_t Scalar/Vector/Matrix) are proposed
2719 ---------------------------------------------------------------------------------------------------*/
2720 /*!product with factorized matrix
2721       no permutation  : L*U*X or L*D*Lt*X or (L*D*L*)*X
2722       row permutation  (PA=LU) :  inv(P)*L*U*X or inv(P)*L*D*Lt*X or inv(P)*(L*D*L*)*X
2723       col permutation  (AQ=LU) :  L*U*inv(Q)*X or L*D*Lt*inv(Q)*X or (L*D*L*)*inv(Q)*X
2724       row and col permutation  (PAQ=LU) :  inv(P)*L*U*inv(Q)*X or inv(P)*L*D*Lt*inv(Q)*X or inv(P)*(L*D*L*)*inv(Q)*X
2725    called by multMatrixVector functions
2726 */
2727 template <typename T, typename V, typename R>
multFactMatrixVector(const LargeMatrix<T> & mat,const std::vector<V> & vec,std::vector<R> & res)2728 void multFactMatrixVector(const LargeMatrix<T>& mat, const std::vector<V>& vec, std::vector<R>& res)
2729 {
2730   number_t n=vec.size();
2731   res.resize(n);
2732   typename std::vector<V>::const_iterator itv=vec.begin();
2733   typename std::vector<R>::iterator itr;
2734   std::vector<R> r1(n), r2(n);
2735   for(itr=r1.begin(); itr!=r1.end(); ++itr, ++itv) *itr=*itv;
2736   if(mat.colPermutation_.size()>0) permuteInv(r1,r1,mat.colPermutation_);
2737   switch(mat.factorization_)
2738     {
2739     case _ilu:
2740     case _lu:
2741       mat.storage_p->upperMatrixVector(mat.values_, r1, r2, mat.sym);
2742       mat.storage_p->lowerD1MatrixVector(mat.values_, r2, res, mat.sym);
2743       break;
2744     case _ldlt:
2745       mat.storage_p->upperD1MatrixVector(mat.values_, r1, r2, mat.sym);
2746       mat.storage_p->diagonalMatrixVector(mat.values_, r2, r1, mat.sym);
2747       mat.storage_p->lowerD1MatrixVector(mat.values_, r1, res, mat.sym);
2748       break;
2749     case _ldlstar:
2750       mat.storage_p->upperD1MatrixVector(mat.values_, r1, r2, mat.sym);
2751       mat.storage_p->diagonalMatrixVector(mat.values_, r2, r1, mat.sym);
2752       for(itr=r1.begin(); itr!=r1.end(); ++itr) *itr=conj(*itr); //conjugate res conj(A)*X= conj(A*conj(X))
2753       mat.storage_p->lowerD1MatrixVector(mat.values_, r1, res, mat.sym);
2754       for(itr=res.begin(); itr!=res.end(); ++itr) *itr=conj(*itr); //conjugate res
2755       break;
2756     default :
2757       where("multFactMatrixVector(LargeMatrix, vector, vector)");
2758       error("wrong_factorization_type", words("factorization type", mat.factorization_));
2759     }
2760   if(mat.rowPermutation_.size()>0) permuteInv(res,res,mat.rowPermutation_);
2761 }
2762 
2763 /*!product with factorized matrix A=LU, or A=LDLt or A =LDL*
2764       no permutation  : X*L*U = (Ut*Lt*Xt)t
2765       row permutation  (PA=LU) : X*inv(P)*L*U = Ut*Lt*inv(P)t*Xt =  Ut*Lt*P*Xt
2766       col permutation  (AQ=LU) : X*L*U*inv(Q) = inv(Q)t*Ut*Lt*Xt =  Q*Ut*Lt*Xt
2767       row and col permutation  (PAQ=LU) :  X*inv(P)*L*U*inv(Q) = inv(Q)t*Ut*Lt*inv(P)t*Xt =  Q*Ut*Lt*P*Xt
2768    called by multMatrixVector
2769 */
2770 template <typename T, typename V, typename R>
multVectorFactMatrix(const LargeMatrix<T> & mat,const std::vector<V> & vec,std::vector<R> & res)2771 void multVectorFactMatrix(const LargeMatrix<T>& mat, const std::vector<V>& vec, std::vector<R>& res)
2772 {
2773 
2774   error("free_error","product Vector * Factorized Matrix is not yet available");
2775 
2776 //    ### DOES NOT WORK, lowerVectorMatrix, upperVectorMatrix, ... not yet available n storage class###
2777 //    number_t n=vec.size();
2778 //    res.resize(n);
2779 //    typename std::vector<V>::const_iterator itv=vec.begin();
2780 //    typename std::vector<R>::iterator itr;
2781 //    std::vector<R> r1(n), r2(n);
2782 //    for(itr=r1.begin();itr!=r1.end();++itr, ++itv) *itr=*itv;
2783 //    if(mat.rowPermutation_.size()>0) permute(r1,r1,mat.rowPermutation_);
2784 //    switch(mat.factorization_)
2785 //    {
2786 //    case _lu: mat.storage_p->vectorLowerD1Matrix(mat.values_, r1, r2, mat.sym);
2787 //              mat.storage_p->vectorUpperMatrix(mat.values_, r2, res, mat.sym);
2788 //
2789 //        break;
2790 //    case _ldlt: mat.storage_p->vectorLowerD1Matrix(mat.values_, r1, res, mat.sym);
2791 //                mat.storage_p->diagonalMatrixVector(mat.values_, r2, r1, mat.sym);
2792 //                mat.storage_p->lowerD1MatrixVector(mat.values_, r1, r2, mat.sym);
2793 //
2794 //        break;
2795 //    case _ldlstar: mat.storage_p->vectorLowerD1Matrix(mat.values_, r1, res, mat.sym);
2796 //                   mat.storage_p->diagonalMatrixVector(mat.values_, r2, r1, mat.sym);
2797 //                   for(itr=r1.begin();itr!=r1.end();++itr) *itr=conj(*itr);  //conjugate res conj(A)*X= conj(A*conj(X))
2798 //                   mat.storage_p->lowerD1MatrixVector(mat.values_, r1, r2, mat.sym);
2799 //                   for(itr=res.begin();itr!=res.end();++itr) *itr=conj(*itr);  //conjugate res
2800 //        break;
2801 //    default :  error("free_error","factorization type not handled in multFactMatrixVector");
2802 //    }
2803 //    if(mat.colPermutation_.size()>0) permute(res,res,mat.colPermutation_);
2804 }
2805 
2806 //! templated  mat<T> * vec<T>
2807 template <typename T>
multMatrixVector(const LargeMatrix<T> & mat,const std::vector<T> & vec,std::vector<T> & res)2808 void multMatrixVector(const LargeMatrix<T>& mat, const std::vector<T>& vec, std::vector<T>& res)
2809 {
2810   trace_p->push("multMatrixVector");
2811   if (vec.size() != mat.nbCols) error("largematrix_mismatch_dim");
2812   if (res.size() < mat.nbRows) res.resize(mat.nbRows, 0);
2813   if (mat.factorization_==_noFactorization) mat.storage_p->multMatrixVector(mat.values_, vec, res, mat.sym);
2814   else multFactMatrixVector(mat, vec, res);
2815   trace_p->pop();
2816 }
2817 
2818 //! templated  mat<T> * vec<V> (pointer form)
2819 template <typename T, typename V, typename R>
multMatrixVector(const LargeMatrix<T> & mat,V * vp,R * rp)2820 void multMatrixVector(const LargeMatrix<T>& mat, V* vp, R* rp)
2821 {
2822   mat.storage_p->multMatrixVector(mat.values_, vp, rp, mat.sym);
2823 }
2824 
2825 //! templated  vec<V> * mat<T>  (pointer form)
2826 template <typename T, typename V, typename R>
multVectorMatrix(const LargeMatrix<T> & mat,V * vp,R * rp)2827 void multVectorMatrix(const LargeMatrix<T>& mat, V* vp, R* rp)
2828 {
2829   mat.storage_p->multVectorMatrix(mat.values_, vp, rp, mat.sym);
2830 }
2831 
2832 //! templated  vec<V> * mat<T>  (pointer form)
2833 template <typename T, typename V, typename R>
multVectorMatrix(V * vp,const LargeMatrix<T> & mat,R * rp)2834 void multVectorMatrix(V* vp, const LargeMatrix<T>& mat, R* rp)
2835 {
2836   mat.storage_p->multVectorMatrix(mat.values_, vp, rp, mat.sym);
2837 }
2838 
2839 template <typename T>
operator *(const LargeMatrix<T> & mat,const std::vector<T> & vec)2840 std::vector<T> operator*(const LargeMatrix<T>& mat, const std::vector<T>& vec)
2841 {
2842   trace_p->push("LargeMatrix * vector");
2843   std::vector<T> res(mat.nbRows, T());
2844   multMatrixVector(mat, vec, res);
2845   trace_p->pop();
2846   return res;
2847 }
2848 
2849 //! templated  mat<Matrix<T> > * vec<Vector<T> >
2850 template <typename T>
multMatrixVector(const LargeMatrix<Matrix<T>> & mat,const std::vector<Vector<T>> & vec,std::vector<Vector<T>> & res)2851 void multMatrixVector(const LargeMatrix<Matrix<T> >& mat, const std::vector<Vector<T> >& vec, std::vector<Vector<T> >& res)
2852 {
2853   trace_p->push("multMatrixVector(LargeMatrix<Matrix>, vector<Vector>, vector<Vector>)");
2854   if(vec.size() != mat.nbCols) error("largematrix_mismatch_dim");
2855   if(res.size() < mat.nbRows)  res.resize(mat.nbRows, Vector<T>(mat.nbRowsSub, T()));
2856   if(mat.factorization_==_noFactorization) mat.storage_p->multMatrixVector(mat.values_, vec, res, mat.sym);
2857   else error("largematrix_factorized", mat.name);
2858   trace_p->pop();
2859 }
2860 
2861 template <typename T>
operator *(const LargeMatrix<Matrix<T>> & mat,const std::vector<Vector<T>> & vec)2862 std::vector<Vector<T> > operator*(const LargeMatrix<Matrix<T> >& mat, const std::vector<Vector<T> >& vec)
2863 {
2864   std::vector<Vector<T> > res(mat.nbRows, Vector<T>(mat.nbRowsSub, T()));
2865   multMatrixVector(mat, vec, res);
2866   return res;
2867 }
2868 
2869 // specializations mat * vec
2870 std::vector<complex_t> operator*(const LargeMatrix<real_t>& mat, const std::vector<complex_t>& vec);
2871 std::vector<complex_t> operator*(const LargeMatrix<complex_t>& mat, const std::vector<real_t>& vec);
2872 std::vector<Vector<complex_t> > operator*(const LargeMatrix<Matrix<real_t> >& mat, const std::vector<Vector<complex_t> >& vec);
2873 std::vector<Vector<complex_t> > operator*(const LargeMatrix<Matrix<complex_t> >& mat, const std::vector<Vector<real_t> >& vec);
2874 
2875 //templated  vec<T> * mat<T>
2876 template <typename T>
multVectorMatrix(const LargeMatrix<T> & mat,const std::vector<T> & vec,std::vector<T> & res)2877 void multVectorMatrix(const LargeMatrix<T>& mat, const std::vector<T>& vec, std::vector<T>& res)
2878 {
2879   trace_p->push("multVectorMatrix");
2880   if(vec.size() != mat.nbRows) error("largematrix_mismatch_dim");
2881   if(res.size() < mat.nbCols)  res.resize(mat.nbCols, 0);
2882   if(mat.factorization_==_noFactorization) mat.storage_p->multVectorMatrix(mat.values_, vec, res, mat.sym);
2883   else multVectorFactMatrix(mat, vec, res);
2884   trace_p->pop();
2885 }
2886 
2887 //templated  vec<T> * mat<T>
2888 template <typename T>
multVectorMatrix(const std::vector<T> & vec,const LargeMatrix<T> & mat,std::vector<T> & res)2889 void multVectorMatrix(const std::vector<T>& vec, const LargeMatrix<T>& mat, std::vector<T>& res)
2890 {
2891   trace_p->push("multVectorMatrix");
2892   if(vec.size() != mat.nbRows) error("largematrix_mismatch_dim");
2893   if(res.size() < mat.nbCols)  res.resize(mat.nbCols, 0);
2894   if(mat.factorization_==_noFactorization) mat.storage_p->multVectorMatrix(mat.values_, vec, res, mat.sym);
2895   else multVectorFactMatrix(mat, vec, res);
2896   trace_p->pop();
2897 }
2898 
2899 template <typename T> template <typename K>
operator *=(const K & v)2900 LargeMatrix<T>& LargeMatrix<T>::operator*=(const K& v)
2901 {
2902   typename std::vector<T>::iterator it = values_.begin();
2903   for(; it != values_.end(); it++)  *it *= v ;
2904   return *this;
2905 }
2906 
2907 template<typename S1, typename S2>
multInverMatrixVector(const LargeMatrix<S1> & mat,std::vector<S2> & vec,std::vector<typename Conditional<NumTraits<S1>::IsComplex,S1,S2>::type> & res,FactorizationType fac)2908 void multInverMatrixVector(const LargeMatrix<S1>& mat, std::vector<S2>& vec,
2909                            std::vector<typename Conditional<NumTraits<S1>::IsComplex, S1, S2>::type>& res,
2910                            FactorizationType fac)
2911 {
2912   switch(fac)
2913     {
2914     case _lu:
2915       mat.luSolve(vec, res);
2916       break;
2917     case _ldlt:
2918       mat.ldltSolve(vec, res);
2919       break;
2920     case _ldlstar:
2921       mat.ldlstarSolve(vec, res);
2922       break;
2923     case _umfpack:
2924       mat.umfluSolve(vec, res);
2925       break;
2926     default:
2927       error("largematrix_not_factorized", mat.name);
2928     }
2929 }
2930 
2931 template <typename T> template <typename K>
operator /=(const K & v)2932 LargeMatrix<T>& LargeMatrix<T>::operator/=(const K& v)
2933 {
2934   typename std::vector<T>::iterator it = values_.begin();
2935   for(; it != values_.end(); it++)
2936     {
2937       *it /= v ;
2938     }
2939   return (*this);
2940 }
2941 
2942 template <typename T>
operator *(const std::vector<T> & vec,const LargeMatrix<T> & mat)2943 std::vector<T> operator*(const std::vector<T>& vec, const LargeMatrix<T>& mat)
2944 {
2945   std::vector<T> res(mat.nbCols, T());
2946   multVectorMatrix(mat, vec, res);
2947   return (res);
2948 }
2949 
2950 //templated  vec<Vector<T> > * mat<Matrix<T> >
2951 template <typename T>
multVectorMatrix(const LargeMatrix<Matrix<T>> & mat,const std::vector<Vector<T>> & vec,std::vector<Vector<T>> & res)2952 void multVectorMatrix(const LargeMatrix<Matrix<T> >& mat, const std::vector<Vector<T> >& vec, std::vector<Vector<T> >& res)
2953 {
2954   trace_p->push("multVectorMatrix(LargeMatrix<Matrix>, vector<Vector>, vector<Vector>)");
2955   if(vec.size() != mat.nbRows) error("largematrix_mismatch_dim");
2956   if(res.size() < mat.nbCols)  res.resize(mat.nbCols, Vector<T>(mat.nbColsSub, T()));
2957   if(mat.factorization_==_noFactorization) mat.storage_p->multVectorMatrix(mat.values_, vec, res, mat.sym);
2958   else  error("largematrix_factorized", mat.name);
2959   trace_p->pop();
2960 }
2961 
2962 //templated  vec<Vector<T> > * mat<Matrix<T> >
2963 template <typename T>
multVectorMatrix(const std::vector<Vector<T>> & vec,const LargeMatrix<Matrix<T>> & mat,std::vector<Vector<T>> & res)2964 void multVectorMatrix(const std::vector<Vector<T> >& vec, const LargeMatrix<Matrix<T> >& mat, std::vector<Vector<T> >& res)
2965 {
2966   trace_p->push("multVectorMatrix(vector<Vector>, LargeMatrix<Matrix, vector<Vector>)");
2967   if(vec.size() != mat.nbRows) error("largematrix_mismatch_dim");
2968   if(res.size() < mat.nbCols)  res.resize(mat.nbCols, Vector<T>(mat.nbColsSub, T()));
2969   if(mat.factorization_==_noFactorization) mat.storage_p->multVectorMatrix(mat.values_, vec, res, mat.sym);
2970   else  error("largematrix_factorized", mat.name);
2971   trace_p->pop();
2972 }
2973 
2974 template <typename T>
operator *(const std::vector<Vector<T>> & vec,const LargeMatrix<Matrix<T>> & mat)2975 std::vector<Vector<T> > operator*(const std::vector<Vector<T> >& vec, const LargeMatrix<Matrix<T> >& mat)
2976 {
2977   std::vector<Vector<T> > res(mat.nbCols, Vector<T>(vec.begin()->size(), T()));
2978   multVectorMatrix(mat, vec, res);
2979   return res;
2980 }
2981 
2982 // specialize version vec * mat
2983 std::vector<complex_t> operator*(const std::vector<complex_t>& vec, const LargeMatrix<real_t>& mat);
2984 std::vector<complex_t> operator*(const std::vector<real_t>& vec, const LargeMatrix<complex_t>& mat);
2985 std::vector<Vector<complex_t> > operator*(const std::vector<Vector<complex_t> >& vec, const LargeMatrix<Matrix<real_t> >& mat);
2986 std::vector<Vector<complex_t> > operator*(const std::vector<Vector<real_t> >& vec, const LargeMatrix<Matrix<complex_t> >& mat);
2987 
2988 // ---------------------------------------------------------------------
2989 //  Factorisation LDLt, LDL*, LU of LargeMatrix
2990 // ---------------------------------------------------------------------
2991 // LDLt Factorization of a symmetric matrix
2992 template <typename T>
ldltFactorize()2993 void LargeMatrix<T>::ldltFactorize()
2994 {
2995   trace_p->push("LargeMatrix::ldlt");
2996   if(_symmetric != sym) storage_p->noFactorization("L.D.Lt");
2997   StorageType st = storage_p->storageType();
2998   if(st!=_skyline && st!=_dense) storage_p->noFactorization("L.D.Lt");
2999   storage_p->ldlt(values_, values_);
3000   factorization_=_ldlt;
3001   trace_p->pop();
3002 }
3003 
3004 template<typename S>
ldltFactorize(LargeMatrix<S> & mat)3005 void ldltFactorize(LargeMatrix<S>& mat)
3006 {
3007   mat.ldltFactorize();
3008 }
3009 
3010 // LDL* Factorization of a Hermitian positive definite matrix
3011 template <typename T>
ldlstarFactorize()3012 void LargeMatrix<T>::ldlstarFactorize()
3013 {
3014   trace_p->push("LargeMatrix::ldlstar");
3015   if(_selfAdjoint != sym) storage_p->noFactorization("L.D.LStar");
3016   if(_skyline != (storage_p->storageType())) storage_p->noFactorization("L.D.LStar");
3017   storage_p->ldlstar(values_, values_);
3018   factorization_=_ldlstar;
3019   trace_p->pop();
3020 }
3021 
3022 template<typename S>
ldlstarFactorize(LargeMatrix<S> & mat)3023 void ldlstarFactorize(LargeMatrix<S>& mat)
3024 {
3025   mat.ldlstarFactorize();
3026 }
3027 
3028 /*! do LU factorization of skyline or dense matrix
3029     LU with row permutation is available only for dense matrices
3030     if matrix is stored as symmetric it is extended to store upper part (toUnsymmetric function)
3031 */
3032 template<typename T>
luFactorize(bool withPermutation)3033 void LargeMatrix<T>::luFactorize(bool withPermutation)
3034 {
3035   trace_p->push("luFactorization");
3036   if(_skyline == (storage_p->storageType()))
3037     {
3038       toUnsymmetric(accessType());
3039       storage_p->lu(values_, values_,sym);
3040       factorization_=_lu;
3041       trace_p->pop();
3042       return;
3043     }
3044   else if(_dense == storage_p->storageType())
3045     {
3046       if(_sym != storage_p->accessType()) toUnsymmetric(_dual);
3047       if(withPermutation) storage_p->lu(values_, values_, rowPermutation_, sym);
3048       else storage_p->lu(values_, values_, sym);
3049       factorization_=_lu;
3050       trace_p->pop();
3051       return;
3052     }
3053   storage_p->noFactorization("L.U");
3054   trace_p->pop();
3055 }
3056 
3057 template<typename S>
luFactorize(LargeMatrix<S> & mat,bool withPermutation=true)3058 void luFactorize(LargeMatrix<S>& mat, bool withPermutation=true)
3059 {
3060   mat.luFactorize(withPermutation);
3061 }
3062 
3063 /*  Factorization incomplete LU without permutation */
3064 
3065 template<typename T>
iluFactorize()3066 void LargeMatrix<T>::iluFactorize()
3067 {
3068   trace_p->push("iluFactorization");
3069   if( _cs != (storage_p->storageType()) ) storage_p->noFactorization("IL.U");
3070   toUnsymmetric(accessType());
3071   storage_p->ilu(values_, values_,sym);
3072   factorization_=_ilu;
3073   trace_p->pop();
3074 }
3075 
3076 template<typename S>
iluFactorize(LargeMatrix<S> & mat)3077 void iluFactorize(LargeMatrix<S>& mat)
3078 {
3079   mat.iluFactorize();
3080 }
3081 
3082 
3083 /*  Factorization incomplete LDLt without permutation */
3084 // ---------------------------------------------------------------------
3085 // iLDLt Factorization of a symmetric matrix
3086 template <typename T>
ildltFactorize()3087 void LargeMatrix<T>::ildltFactorize()
3088 {
3089   trace_p->push("LargeMatrix::ildlt");
3090   if(_symmetric != sym) storage_p->noFactorization("iL.D.Lt");
3091   StorageType st = storage_p->storageType();
3092   if(st!=_skyline && st!=_dense && st!=_cs) storage_p->noFactorization("iL.D.Lt");
3093   storage_p->ildlt(values_, values_);
3094   factorization_=_ildlt;
3095   trace_p->pop();
3096 }
3097 
3098 template<typename S>
ildltFactorize(LargeMatrix<S> & mat)3099 void ildltFactorize(LargeMatrix<S>& mat)
3100 {
3101   mat.ildltFactorize();
3102 }
3103 
3104 /*  Factorization incomplete LLt without permutation */
3105 // ---------------------------------------------------------------------
3106 // iLLt Factorization of a symmetric matrix positive definate
3107 template <typename T>
illtFactorize()3108 void LargeMatrix<T>::illtFactorize()
3109 {
3110   trace_p->push("LargeMatrix::illt");
3111   if(_selfAdjoint != sym && _symmetric != sym) storage_p->noFactorization("iL.Lt");
3112   StorageType st = storage_p->storageType();
3113   if(st!=_skyline && st!=_dense && st!=_cs) storage_p->noFactorization("iL.Lt");
3114   storage_p->illt(values_, values_);
3115   factorization_=_illt;
3116   trace_p->pop();
3117 }
3118 
3119 template<typename S>
illtFactorize(LargeMatrix<S> & mat)3120 void illtFactorize(LargeMatrix<S>& mat)
3121 {
3122   mat.illtFactorize();
3123 }
3124 
3125 // iLDL* Factorization of a hermitian matrix
3126 template <typename T>
ildlstarFactorize()3127 void LargeMatrix<T>::ildlstarFactorize()
3128 {
3129   trace_p->push("LargeMatrix::ildlstar");
3130   if( _selfAdjoint != sym && _symmetric != sym ) storage_p->noFactorization("iL.D.LstarR");
3131   StorageType st = storage_p->storageType();
3132   if(st!=_skyline && st!=_dense && st!=_cs) storage_p->noFactorization("iL.D.Lstar");
3133   storage_p->ildlstar(values_, values_);
3134   factorization_=_ildlstar;
3135   trace_p->pop();
3136 }
3137 
3138 template<typename S>
ildlstarFactorize(LargeMatrix<S> & mat)3139 void ildlstarFactorize(LargeMatrix<S>& mat)
3140 {
3141   mat.ildlstarFactorize();
3142 }
3143 
3144 /*  Factorization incomplete LLstar without permutation */
3145 // ---------------------------------------------------------------------
3146 // iLLt Factorization of a symmetric matrix positive definate
3147 template <typename T>
illstarFactorize()3148 void LargeMatrix<T>::illstarFactorize()
3149 {
3150   trace_p->push("LargeMatrix::illstar");
3151   if( _selfAdjoint != sym && _symmetric != sym) storage_p->noFactorization("iL.Lstarr");
3152   StorageType st = storage_p->storageType();
3153   if(st!=_skyline && st!=_dense && st!=_cs) storage_p->noFactorization("iL.Lstar");
3154   storage_p->illstar(values_, values_);
3155   factorization_=_illstar;
3156   trace_p->pop();
3157 }
3158 
3159 template<typename S>
illstarFactorize(LargeMatrix<S> & mat)3160 void illstarFactorize(LargeMatrix<S>& mat)
3161 {
3162   mat.illstarFactorize();
3163 }
3164 
3165 template<typename T>
umfpackFactorize()3166 void LargeMatrix<T>::umfpackFactorize()
3167 {
3168   trace_p->push("umfpackFactorization");
3169 #ifdef XLIFEPP_WITH_UMFPACK
3170   umfLU_p=new UmfPackLU<LargeMatrix<T> >(*this);
3171   factorization_=_umfpack;
3172 #else //no umfpack
3173   error("xlifepp_without_umfpack");
3174 #endif // XLIFEPP_WITH_UMFPACK
3175   trace_p->pop();
3176 }
3177 
3178 template<typename S>
umfpackFactorize(LargeMatrix<S> & mat)3179 void umfpackFactorize(LargeMatrix<S>& mat)
3180 {
3181   mat.umfpackFactorize();
3182 }
3183 
3184 // ---------------------------------------------------------------------
3185 //  Solver for LDLt, LDL*, LU system, matrix has to be factorized before
3186 // ---------------------------------------------------------------------
3187 // Template version of solver with matrix factorization LLT
3188 template <typename T> template<typename S1, typename S2>
lltSolve(std::vector<S1> & vec1,std::vector<S2> & vec2) const3189 void LargeMatrix<T>::lltSolve(std::vector<S1>& vec1, std::vector<S2>& vec2) const
3190 {
3191   trace_p->push("LargeMatrix::lltSolve");
3192   number_t n=vec1.size();
3193   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::lltSolve", vec1.size(), vec2.size());
3194   if(n != vec2.size()) vec2.resize(n);
3195   storage_p->sorLowerSolver(values_, vec1, vec2,1.);
3196   storage_p->sorUpperSolver(values_, vec2, vec2, 1.,sym);
3197   trace_p->pop();
3198 }
3199 // Template version of solver with matrix factorization LDLT
3200 template <typename T> template<typename S1, typename S2>
ldltSolve(std::vector<S1> & vec1,std::vector<S2> & vec2) const3201 void LargeMatrix<T>::ldltSolve(std::vector<S1>& vec1, std::vector<S2>& vec2) const
3202 {
3203   trace_p->push("LargeMatrix::ldltSolve");
3204   number_t n=vec1.size();
3205   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::ldltSolve", vec1.size(), vec2.size());
3206   if(n != vec2.size()) vec2.resize(n);
3207   storage_p->lowerD1Solver(values_, vec1, vec2);
3208   storage_p->diagonalSolver(values_, vec2, vec2);
3209   storage_p->upperD1Solver(values_, vec2, vec2, sym);
3210   trace_p->pop();
3211 }
3212 
3213 // Template version of solver with matrix factorization LDL*
3214 template <typename T> template<typename S>
ldlstarSolve(std::vector<S> & vec1,std::vector<T> & vec2) const3215 void LargeMatrix<T>::ldlstarSolve(std::vector<S>& vec1, std::vector<T>& vec2) const
3216 {
3217   trace_p->push("LargeMatrix::ldlstarSolve");
3218   if(sym != _selfAdjoint) storage_p->noSolver("L.D.L*");
3219   number_t n=vec1.size();
3220   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::ldlstarSolve", vec1.size(), vec2.size());
3221   if(n != vec2.size()) vec2.resize(n);
3222   storage_p->lowerD1Solver(values_, vec1, vec2);
3223   storage_p->diagonalSolver(values_, vec2, vec2);
3224   storage_p->upperD1Solver(values_, vec2, vec2, sym);
3225   trace_p->pop();
3226 }
3227 
3228 // Template version of solver of LU-factorized matrix
3229 template <typename T> template<typename S1, typename S2>
luSolve(std::vector<S1> & vec1,std::vector<S2> & vec2) const3230 void LargeMatrix<T>::luSolve(std::vector<S1>& vec1, std::vector<S2>& vec2) const
3231 {
3232   trace_p->push("LargeMatrix::luSolve");
3233   number_t n=vec1.size();
3234   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::luSolve", vec1.size(), vec2.size());
3235   if(n != vec2.size()) vec2.resize(n);
3236   if(rowPermutation_.size()>0) permute(vec1,vec1,rowPermutation_);
3237   storage_p->lowerD1Solver(values_, vec1, vec2);
3238   storage_p->upperSolver(values_, vec2, vec2, sym);
3239   if(colPermutation_.size()>0) permute(vec2,vec2,colPermutation_);
3240   trace_p->pop();
3241 }
3242 
3243 // Template version of solver of umfpack LU-factorized matrix
3244 template <typename T> template<typename S1, typename S2>
umfluSolve(std::vector<S1> & vec1,std::vector<S2> & vec2) const3245 void LargeMatrix<T>::umfluSolve(std::vector<S1>& vec1, std::vector<S2>& vec2) const
3246 {
3247 #ifdef XLIFEPP_WITH_UMFPACK
3248   trace_p->push("LargeMatrix::umfluSolver");
3249   number_t n=vec1.size();
3250   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::umfluSolve", vec1.size(), vec2.size());
3251   if(n != vec2.size()) vec2.resize(n);
3252   if(umfLU_p==0) error("largematrix_not_factorized",name);
3253   umfLU_p->solve(vec1,vec2);
3254   trace_p->pop();
3255 #else
3256   error("xlifepp_without_umfpack");
3257 #endif
3258 }
3259 
3260 // Template version of sor Matrix Vector
3261 template <typename T> template<typename S1, typename S2>
sorLowerMatrixVector(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3262 void LargeMatrix<T>::sorLowerMatrixVector(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3263 {
3264   trace_p->push("LargeMatrix::sorLowerMatrixVector");
3265   number_t n=vec1.size();
3266   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorLowerMatrixVector", vec1.size(), vec2.size());
3267   if(n != vec2.size()) vec2.resize(n);
3268   storage_p->sorLowerMatrixVector(values_, vec1, vec2, w);
3269   trace_p->pop();
3270 }
3271 
3272 // Template version of sor Matrix Vector
3273 template <typename T> template<typename S1, typename S2>
sorDiagonalMatrixVector(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3274 void LargeMatrix<T>::sorDiagonalMatrixVector(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3275 {
3276   trace_p->push("LargeMatrix::sorDiagonalMatrixVector");
3277   number_t n=vec1.size();
3278   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorDiagonalMatrixVector", vec1.size(), vec2.size());
3279   if(n != vec2.size()) vec2.resize(n);
3280   storage_p->sorDiagonalMatrixVector(values_, vec1, vec2, w);
3281   trace_p->pop();
3282 }
3283 
3284 // Template version of sor Matrix Vector
3285 template <typename T> template<typename S1, typename S2>
sorUpperMatrixVector(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3286 void LargeMatrix<T>::sorUpperMatrixVector(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3287 {
3288   trace_p->push("LargeMatrix::sorUpperMatrixVector");
3289   number_t n=vec1.size();
3290   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorUpperMatrixVector", vec1.size(), vec2.size());
3291   if(n != vec2.size()) vec2.resize(n);
3292   storage_p->sorUpperMatrixVector(values_, vec1, vec2, w, sym);
3293   trace_p->pop();
3294 }
3295 
3296 // Template version of sor solver
3297 template <typename T> template<typename S1, typename S2>
sorLowerSolve(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3298 void LargeMatrix<T>::sorLowerSolve(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3299 {
3300   trace_p->push("LargeMatrix::sorLowerSolver");
3301   number_t n=vec1.size();
3302   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorLowerSolver", vec1.size(), vec2.size());
3303   if(n != vec2.size()) vec2.resize(n);
3304   storage_p->sorLowerSolver(values_, vec1, vec2, w);
3305   trace_p->pop();
3306 }
3307 
3308 // Template version of sor solver
3309 template <typename T> template<typename S1, typename S2>
sorDiagonalSolve(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3310 void LargeMatrix<T>::sorDiagonalSolve(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3311 {
3312   trace_p->push("LargeMatrix::sorDiagonalSolver");
3313   number_t n=vec1.size();
3314   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorDiagonalSolver", vec1.size(), vec2.size());
3315   if(n != vec2.size()) vec2.resize(n);
3316   storage_p->sorDiagonalSolver(values_, vec1, vec2, w);
3317   trace_p->pop();
3318 }
3319 
3320 // Template version of sor solver
3321 template <typename T> template<typename S1, typename S2>
sorUpperSolve(const std::vector<S1> & vec1,std::vector<S2> & vec2,const real_t w) const3322 void LargeMatrix<T>::sorUpperSolve(const std::vector<S1>& vec1, std::vector<S2>& vec2, const real_t w) const
3323 {
3324   trace_p->push("LargeMatrix::sorUpperSolver");
3325   number_t n=vec1.size();
3326   if(n != numberOfRows())  error("bad_dim", "LargeMatrix::sorUpperSolver", vec1.size(), vec2.size());
3327   if(n != vec2.size()) vec2.resize(n);
3328   storage_p->sorUpperSolver(values_, vec1, vec2, w, sym);
3329   trace_p->pop();
3330 }
3331 
3332 // ---------------------------------------------------------------------
3333 //  interface to UmfPack to solve AX=B
3334 //      current LargeMatrix : A
3335 //      vec : right hand side B
3336 //      res : solution X
3337 //      soa : boolean flag to stop on abnormal situation in UmfPack
3338 //      return the reciproqual condition number rcond = 1/||A||*||inv(A)|| in norm 1
3339 //  Note : these functions call implicitely LU factorisation, see luFactorize for LU factorisation with umfpack
3340 // ---------------------------------------------------------------------
3341 template <typename T> template<typename S>
umfpackSolve(const std::vector<S> & vec,std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex,ScalarType,S>::type> & res,bool soa)3342 real_t LargeMatrix<T>::umfpackSolve(const std::vector<S>& vec, std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType,
3343                                     S>::type>& res, bool soa)
3344 {
3345 #ifdef XLIFEPP_WITH_UMFPACK
3346   UmfPackSolver umPSolver;  //umfPack solver object
3347   return umPSolver(*this, vec, res, soa);
3348 #else
3349   error("xlifepp_without_umfpack");
3350   return real_t(0.); // dummy return
3351 #endif
3352 }
3353 
3354 //multiple right hand side, vec has to be of the same type
3355 template <typename T> template<typename S>
umfpackSolve(const std::vector<std::vector<S> * > & bs,std::vector<std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex,ScalarType,S>::type> * > & xs,bool soa)3356 real_t LargeMatrix<T>::umfpackSolve(const std::vector<std::vector<S>*>& bs, std::vector<std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType,
3357                                     S>::type>* >& xs, bool soa)
3358 {
3359 #ifdef XLIFEPP_WITH_UMFPACK
3360   UmfPackSolver umPSolver;  //umfPack solver object
3361   return umPSolver(*this, bs, xs, soa);
3362 #else
3363   error("xlifepp_without_umfpack");
3364   return real_t(0.); // dummy return
3365 #endif
3366 }
3367 
3368 // other interface to UmfPack to solve AX=B
3369 //      colPointer, rowIndex : sparse strage information
3370 //      values : values of matrix
3371 //      vec : right hand side B
3372 //      res : solution X
3373 //      soa : boolean flag to stop on abnormal situation in UmfPack
3374 //      return the reciproqual condition number rcond = 1/||A||*||inv(A)|| in norm 1
3375 template <typename T> template<typename S>
umfpackSolve(const std::vector<int_t> & colPointer,const std::vector<int_t> & rowIndex,const std::vector<T> & values,const std::vector<S> & vec,std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex,ScalarType,S>::type> & res,bool soa)3376 real_t LargeMatrix<T>::umfpackSolve(const std::vector<int_t>& colPointer, const std::vector<int_t>& rowIndex, const std::vector<T>& values, const std::vector<S>& vec,
3377                                     std::vector<typename Conditional<NumTraits<ScalarType>::IsComplex, ScalarType, S>::type>& res, bool soa)
3378 {
3379 #ifdef XLIFEPP_WITH_UMFPACK
3380   UmfPackSolver umPSolver; //umfPack solver object
3381   return umPSolver(nbRows, colPointer, rowIndex, &values[0], vec, res, _A, soa);
3382 #else
3383   error("xlifepp_without_umfpack");
3384   return real_t(0.); // dummy return
3385 #endif
3386 }
3387 
3388 /* ---------------------------------------------------------------------
3389    solve triangular systems
3390        LD1*x = b   (lowerD1Solve)
3391        U*b = b     (upperSolve)
3392        x*LD1 = b   (lowerD1LeftSolve)
3393        x*U = b     (upperLeftSolve)
3394  ---------------------------------------------------------------------*/
3395 // solve triangular system LD1*x = b
3396 template <typename T>
lowerD1Solve(std::vector<T> & b,std::vector<T> & x) const3397 std::vector<T>& LargeMatrix<T>::lowerD1Solve(std::vector<T>& b, std::vector<T>& x) const
3398 {
3399   if(nbRows!=b.size())
3400     {
3401       where("lowerD1Solve(vector, vector)");
3402       error("largematrix_mismatch_dim");
3403     }
3404   if(b.size() != nbRows) error("bad_dim", "LargeMatrix::lowerD1Solve(vector, vector)", b.size(), nbRows);
3405   if(nbCols != x.size()) x.resize(nbCols);
3406   if(rowPermutation_.size()>0) permute(b, b, rowPermutation_);
3407   storage_p->lowerD1Solver(values_, b, x);
3408   if(colPermutation_.size()>0) permute(x, x, colPermutation_);
3409   return x;
3410 }
3411 
3412 // solve triangular system U*x = b
3413 template <typename T>
upperSolve(std::vector<T> & b,std::vector<T> & x) const3414 std::vector<T>& LargeMatrix<T>::upperSolve(std::vector<T>& b, std::vector<T>& x) const
3415 {
3416   if(b.size() != nbRows)  error("bad_dim", "LargeMatrix::upperSolve(vector, vector)", b.size(), nbRows);
3417   if(nbCols != x.size()) x.resize(nbCols);
3418   if(rowPermutation_.size()>0) permute(b, b, rowPermutation_);
3419   storage_p->upperSolver(values_, b, x, sym);
3420   if(colPermutation_.size()>0) permute(x, x, colPermutation_);
3421   return x;
3422 }
3423 
3424 // solve triangular system x*LD1 = b
3425 template <typename T>
lowerD1LeftSolve(std::vector<T> & b,std::vector<T> & x) const3426 std::vector<T>& LargeMatrix<T>::lowerD1LeftSolve(std::vector<T>& b, std::vector<T>& x) const
3427 {
3428   if(b.size() != nbCols)  error("bad_dim", "LargeMatrix::lowerD1LeftSolve(vector, vector)", b.size(), nbRows);
3429   if(nbRows != x.size()) x.resize(nbRows);
3430   if(colPermutation_.size()>0) permute(b, b, colPermutation_);
3431   storage_p->lowerD1LeftSolver(values_, b, x);
3432   if(rowPermutation_.size()>0) permute(x, x, rowPermutation_);
3433   return x;
3434 }
3435 
3436 // solve triangular system x*U = b
3437 template <typename T>
upperLeftSolve(std::vector<T> & b,std::vector<T> & x) const3438 std::vector<T>& LargeMatrix<T>::upperLeftSolve(std::vector<T>& b, std::vector<T>& x) const
3439 {
3440   if(b.size() != nbCols)  error("bad_dim", "LargeMatrix::upperLeftSolve(vector, vector)", b.size(), nbRows);
3441   if(nbRows != x.size()) x.resize(nbRows);
3442   if(colPermutation_.size()>0) permute(b, b, colPermutation_);
3443   storage_p->upperLeftSolver(values_, b, x, sym);
3444   if(rowPermutation_.size()>0) permute(x, x, rowPermutation_);
3445   return x;
3446 }
3447 
3448 /* ---------------------------------------------------------------------
3449    solve triangular systems
3450        LD1*X = M   (lowerD1Solve)
3451        U*X = M     (upperSolve)
3452        X*LD1 = M   (lowerD1LeftSolve)
3453        X*U = M     (upperLeftSolve)
3454    the matrix result X is stored as a col dense LargeMatrix
3455  ---------------------------------------------------------------------*/
3456 // solve triangular system LD1*X = M
3457 template <typename T>
lowerD1Solve(const LargeMatrix<T> & M,const LargeMatrix<T> & X) const3458 LargeMatrix<T>& LargeMatrix<T>::lowerD1Solve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const
3459 {
3460   if(nbRows!=M.nbRows)
3461     {
3462       where("lowerD1Solve(LargeMatrix,LargeMatrix)");
3463       error("largematrix_mismatch_dim");
3464     }
3465   X=LargeMatrix(nbCols, M.nbCols, _dense, _col);
3466   typename std::vector<T>::iterator itX = X.values_.begin()+1, itx;
3467   std::vector<T> x(nbCols), b(M.nbRows);
3468   for(number_t k=1; k<=M.nbCols; ++k)
3469     {
3470       b=M.col(k);
3471       lowerD1Solve(b, x,1.);
3472       itx=x.begin();
3473       for(number_t i=0; i<nbCols; i++,++itX, ++itx) *itX=*itx;
3474     }
3475   return X;
3476 }
3477 
3478 template <typename T>
upperSolve(const LargeMatrix<T> & M,const LargeMatrix<T> & X) const3479 LargeMatrix<T>& LargeMatrix<T>::upperSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const
3480 {
3481   if(nbRows!=M.nbRows)
3482     {
3483       where("lowerD1Solve(LargeMatrix,LargeMatrix)");
3484       error("largematrix_mismatch_dim");
3485     }
3486   X=LargeMatrix(nbCols, M.nbCols, _dense, _col);
3487   typename std::vector<T>::iterator itX = X.values_.begin()+1, itx;
3488   std::vector<T> x(nbCols), b(M.nbRows);
3489   for(number_t k=1; k<=M.nbCols; ++k)
3490     {
3491       b=M.col(k);
3492       upperSolve(b, x,1.);
3493       itx=x.begin();
3494       for(number_t i=0; i<nbCols; i++,++itX, ++itx) *itX=*itx;
3495     }
3496   return X;
3497 }
3498 
3499 template <typename T>
lowerD1LeftSolve(const LargeMatrix<T> & M,const LargeMatrix<T> & X) const3500 LargeMatrix<T>& LargeMatrix<T>::lowerD1LeftSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const
3501 {
3502   if(nbCols!=M.nbCols)
3503     {
3504       where("lowerD1Solve(LargeMatrix,LargeMatrix)");
3505       error("largematrix_mismatch_dim");
3506     }
3507   X=LargeMatrix(M.nbRows, nbRows, _dense, _col);
3508   typename std::vector<T>::iterator itX = X.values_.begin()+1, itx;
3509   std::vector<T> x(M.nbRows), b(M.nbRows);
3510   for(number_t k=1; k<=M.nbCols; ++k)
3511     {
3512       b=M.col(k);
3513       lowerD1LeftSolve(b, x,1.);
3514       itx=x.begin();
3515       for(number_t i=0; i<M.nbRows; i++,++itX, ++itx) *itX=*itx;
3516     }
3517   return X;
3518 
3519 }
3520 
3521 template <typename T>
upperLeftSolve(const LargeMatrix<T> & M,const LargeMatrix<T> & X) const3522 LargeMatrix<T>& LargeMatrix<T>::upperLeftSolve(const LargeMatrix<T>& M, const LargeMatrix<T>& X) const
3523 {
3524   if(nbCols!=M.nbCols)
3525     {
3526       where("lowerD1Solve(LargeMatrix,LargeMatrix)");
3527       error("largematrix_mismatch_dim");
3528     }
3529   X=LargeMatrix(M.nbRows, nbRows, _dense, _col);
3530   typename std::vector<T>::iterator itX = X.values_.begin()+1, itx;
3531   std::vector<T> x(M.nbRows), b(M.nbRows);
3532   for(number_t k=1; k<=M.nbCols; ++k)
3533     {
3534       b=M.col(k);
3535       upperLeftSolve(b, x,1.);
3536       itx=x.begin();
3537       for(number_t i=0; i<M.nbRows; i++,++itX, ++itx) *itX=*itx;
3538     }
3539   return X;
3540 }
3541 
3542 
3543 // ---------------------------------------------------------------------
3544 //  Construct a diagonal Matrix from a size, storage and a specific value
3545 //  st, at : storage type
3546 //  nbr, nbc : number of rows and columns (may be different)
3547 //
3548 //  return diagonal matrix
3549 // ---------------------------------------------------------------------
3550 template <typename T>
diagonalMatrix(StorageType st,AccessType at,number_t nbr,number_t nbc,const T v)3551 LargeMatrix<T> diagonalMatrix(StorageType st, AccessType at, number_t nbr, number_t nbc, const T v)
3552 {
3553   return LargeMatrix<T>(_diagonal, st, at, nbr, nbc, v);
3554 }
3555 
3556 // ---------------------------------------------------------------------
3557 //  Construct a diagonal Matrix from a Matrix with a specific value
3558 //  \param mat prototype matrix
3559 //  \param v value of diagonal
3560 //  \return diagonal matrix
3561 // ---------------------------------------------------------------------
3562 template <typename T>
diagonalMatrix(const LargeMatrix<T> & mat,const T v)3563 LargeMatrix<T> diagonalMatrix(const LargeMatrix<T>& mat, const T v)
3564 {
3565   trace_p->push("diagonalMatrix");
3566   if(mat.nbRows != mat.nbCols)  error("mat_nonsquare","diagoalMatrix()", mat.nbRows, mat.nbCols);
3567   if(0 == mat.nbRows)           error("is_void","mat");
3568   // Same as copy constructor, there is an issue with the number of reference to a storage
3569   // Only when a largeMatrix is created by loading from a file, does this problem happen.
3570   // The following is only a temporary solution, the root solution ... not this time!!!
3571   if(0 == mat.storage_p->numberOfObjects())
3572     {
3573       mat.storage_p->objectPlus();
3574     }
3575   LargeMatrix<T> diagMat(mat.storage_p, T(), mat.sym);
3576   diagMat.storage_p->setDiagValue(diagMat.values_, v);
3577   trace_p->pop();
3578   return diagMat;
3579 }
3580 
3581 // ---------------------------------------------------------------------
3582 //  Construct an identity Matrix from a Matrix
3583 //  \param mat prototype matrix
3584 //  \return identity matrix
3585 // ---------------------------------------------------------------------
3586 template <typename T>
identityMatrix(const LargeMatrix<T> & mat)3587 LargeMatrix<T> identityMatrix(const LargeMatrix<T>& mat)
3588 {
3589   return diagonalMatrix(mat, T(1.0));
3590 }
3591 
3592 // ---------------------------------------------------------------------
3593 //  Add two largeMatrix and store result into the third.
3594 //     The two matrices must share the same storage.
3595 //     The result matrix will point to the same storage after the summation
3596 //  \param matA first matrix
3597 //  \param matB second matrix
3598 //  \param matC result matrix which share the same storage.
3599 // ---------------------------------------------------------------------
3600 template<typename T>
addMatrixMatrix(const LargeMatrix<T> & matA,const LargeMatrix<T> & matB,LargeMatrix<T> & matC)3601 void addMatrixMatrix(const LargeMatrix<T>& matA, const LargeMatrix<T>& matB, LargeMatrix<T>& matC)
3602 {
3603   trace_p->push("addMatrixMatrix");
3604   if((matA.nbRows != matB.nbRows) || (matA.nbCols != matB.nbCols)  ||
3605       (matA.nbRows != matC.nbRows) || (matA.nbCols != matC.nbCols))
3606     {
3607       error("largematrix_mismatch_dim");
3608     }
3609   else if((matA.storage_p != matB.storage_p) ||
3610           (matA.storage_p->accessType() != matC.storage_p->accessType()) ||
3611           (matA.storage_p->storageType() != matC.storage_p->storageType()))
3612     {
3613       error("largematrix_mismatch_storage");
3614     }
3615   else if(matA.storage_p != matC.storage_p)
3616     {
3617       if(matA.values_.size() != matC.values_.size())
3618         {
3619           matC.values_.resize(matA.values_.size());
3620         }
3621       matA.storage_p->addMatrixMatrix(matA.values_, matB.values_, matC.values_);
3622 
3623       // Decrease number of object using matrix storage of matrix C
3624       matC.storage_p->objectMinus();
3625       matC.storage_p = matA.storage_p;
3626 
3627       // Increase number of object using matrix storage of matrix A (and B, of course)
3628       matA.storage_p->objectPlus();
3629     }
3630   else
3631     {
3632       if(matA.values_.size() != matC.values_.size())
3633         {
3634           matC.values_.resize(matA.values_.size());
3635         }
3636       matA.storage_p->addMatrixMatrix(matA.values_, matB.values_, matC.values_);
3637     }
3638 
3639   if(matA.sym != matB.sym)
3640     {
3641       matC.sym = _noSymmetry;
3642     }
3643   else if(_diagonal == matA.sym)
3644     {
3645       matC.sym = matB.sym;
3646     }
3647   else if(_diagonal == matB.sym)
3648     {
3649       matC.sym = matA.sym;
3650     }
3651   else
3652     {
3653       matC.sym = matA.sym;
3654     }
3655 
3656   trace_p->pop();
3657 }
3658 
3659 // ---------------------------------------------------------------------
3660 //  Add two largeMatrix whose storage need not be the same.
3661 //   The result matrix is based on the matrix that is most "non-symmetric"
3662 //   This function only serves for the mode "Shift and invert" of eigenSolver.
3663 //   Any external usage should be followed with a deletion of result matrix.
3664 //  \param[in] matA first matrix
3665 //  \param[in] matB second matrix
3666 //  \return pointer to result matrix.
3667 // ---------------------------------------------------------------------
3668 template<typename T>
addMatrixMatrixSkyline(const LargeMatrix<T> & matA,const LargeMatrix<T> & matB)3669 LargeMatrix<T>* addMatrixMatrixSkyline(const LargeMatrix<T>& matA, const LargeMatrix<T>& matB)
3670 {
3671   LargeMatrix<T>* res = 0;
3672   if(matA.storagep() == matB.storagep())
3673     {
3674       res = new LargeMatrix<T>(matA);
3675       LargeMatrix<T>* tmpB = const_cast<LargeMatrix<T>* >(&matB);
3676       *res += *tmpB;
3677       res->toSkyline();
3678       return (res);
3679     }
3680 
3681   bool firstOpA = false;
3682   bool isAllocA = false;
3683   bool isAllocB = false;
3684   LargeMatrix<T>* pB = 0, *pA = 0;
3685   if(_skyline != matA.storageType())
3686     {
3687       pA = new LargeMatrix<T>(matA, true);
3688       pA->toSkyline();
3689       isAllocA = true;
3690     }
3691   else pA = const_cast<LargeMatrix<T>* >(&matA);
3692 
3693   if(_skyline != matB.storageType())
3694     {
3695       pB = new LargeMatrix<T>(matB, true);
3696       pB->toSkyline();
3697       isAllocB = true;
3698     }
3699   else pB = const_cast<LargeMatrix<T>* >(&matB);
3700 
3701   if(_dual == pA->accessType())
3702     {
3703       res = pA;
3704       firstOpA = true;
3705     }
3706   if(_dual == pB->accessType())
3707     {
3708       res = pB;
3709       firstOpA = false;
3710     }
3711   if(0 == res)
3712     {
3713       res = pA;
3714       firstOpA = true;
3715     }
3716 
3717   if(res == &matA)
3718     {
3719       res = new LargeMatrix<T>(matA, true);
3720       firstOpA = true;
3721     }
3722 
3723   if(res == &matB)
3724     {
3725       res = new LargeMatrix<T>(matB, true);
3726       firstOpA = false;
3727     }
3728 
3729   SkylineStorage* p = 0;
3730   if(firstOpA) p = static_cast<SkylineStorage*>(pB->storagep());
3731   else p = static_cast<SkylineStorage*>(pA->storagep());
3732   const std::vector<number_t>& rowPointer = p->rowPointer();
3733   const std::vector<number_t>& colPointer = p->colPointer();
3734 
3735   if(firstOpA) res->storagep()->addTwoMatrix(res->values(), res->sym, rowPointer, colPointer, pB->values(), pB->sym);
3736   else  res->storagep()->addTwoMatrix(res->values(), res->sym, rowPointer, colPointer, pA->values(), pA->sym);
3737   if((pA->values().size() != res->values().size()) || (pB->values().size() != res->values().size())) res->sym = _noSymmetry;
3738   if(firstOpA && isAllocB) delete pB;
3739   if((!firstOpA) && isAllocA) delete pA;
3740 
3741   return (res);
3742 }
3743 
3744 //  Add a scaled matrix
3745 template<typename T>
addMatrixMatrix(const LargeMatrix<T> & matA,const LargeMatrix<T> & matB,T s=T (1))3746 LargeMatrix<T> addMatrixMatrix(const LargeMatrix<T>& matA, const LargeMatrix<T>& matB, T s=T(1)) //! A+s*B
3747 {
3748   LargeMatrix<T> matC(matB);
3749   if(s!=T(1)) matC*=s;
3750   return matC+=matA;
3751 }
3752 
3753 //  Add two largeMatrix operator+
3754 template<typename T>
operator +(const LargeMatrix<T> & matA,const LargeMatrix<T> & matB)3755 LargeMatrix<T> operator+(const LargeMatrix<T>& matA, const LargeMatrix<T>& matB)
3756 {
3757   LargeMatrix<T> matC(matA);
3758   addMatrixMatrix(matA, matB, matC);
3759   return matC;
3760 }
3761 // Specialization of operator+ of two matrices
3762 LargeMatrix<complex_t> operator+(const LargeMatrix<real_t>& matA, const LargeMatrix<complex_t>& matB);
3763 LargeMatrix<complex_t> operator+(const LargeMatrix<complex_t>& matA, const LargeMatrix<real_t>& matB);
3764 
3765 //  Add two largeMatrix operator-
3766 template<typename T>
operator -(const LargeMatrix<T> & matA,const LargeMatrix<T> & matB)3767 LargeMatrix<T> operator-(const LargeMatrix<T>& matA, const LargeMatrix<T>& matB)
3768 {
3769   return addMatrixMatrix(matA, matB, T(-1));
3770 }
3771 // Specialization of operator- of two matrices
3772 LargeMatrix<complex_t> operator-(const LargeMatrix<real_t>& matA, const LargeMatrix<complex_t>& matB);
3773 LargeMatrix<complex_t> operator-(const LargeMatrix<complex_t>& matA, const LargeMatrix<real_t>& matB);
3774 
3775 /*!
3776    Multiple a largeMatrix with a scalar
3777    The result matrix will point to the same storage
3778    \param mat matrix
3779    \param v scalar
3780    \return result matrix which shares the same storage.
3781  */
3782 template<typename T>
multMatrixScalar(const LargeMatrix<T> & mat,const T v)3783 LargeMatrix<T> multMatrixScalar(const LargeMatrix<T>& mat, const T v)
3784 {
3785   trace_p->push("multMatrixScalar");
3786   LargeMatrix<T> result(mat);
3787   typename std::vector<T>::iterator itb = result.values_.begin(), it;
3788   for(it = itb; it != result.values_.end(); it++)
3789     {
3790       *it *= v ;
3791     }
3792   trace_p->pop();
3793   return result;
3794 }
3795 
3796 
3797 //!  Multiple a largeMatrix with a scalar
3798 template<typename T>
operator *(const LargeMatrix<T> & mat,const T v)3799 LargeMatrix<T> operator*(const LargeMatrix<T>& mat, const T v)
3800 {
3801   return multMatrixScalar(mat, v);
3802 }
3803 
3804 //!  Multiple a largeMatrix with a scalar
3805 template<typename T>
operator *(const T v,const LargeMatrix<T> & mat)3806 LargeMatrix<T> operator*(const T v, const LargeMatrix<T>& mat)
3807 {
3808   return multMatrixScalar(mat, v);
3809 }
3810 
3811 // Specialization of multiplication largeMatrix and scalar
3812 LargeMatrix<complex_t> operator*(const LargeMatrix<complex_t>& mat, const real_t v);
3813 LargeMatrix<complex_t> operator*(const real_t v, const LargeMatrix<complex_t>& mat);
3814 LargeMatrix<complex_t> operator*(const LargeMatrix<real_t>& mat, const complex_t v);
3815 LargeMatrix<complex_t> operator*(const complex_t v, const LargeMatrix<real_t>& mat);
3816 
3817 
3818 // ---------------------------------------------------------------------
3819 /*! extern template product matrix*matrix
3820   the storage of the resulting matrix is ALWAYS dense
3821   there is no chance to get a sparse matrix except in case of product with
3822   a diagonal matrix where the storage is unchanged */
3823 // ---------------------------------------------------------------------
3824 template <typename SA, typename SB, typename SR>
multMatrixMatrix(const LargeMatrix<SA> & mA,const LargeMatrix<SB> & mB,LargeMatrix<SR> & mR)3825 void multMatrixMatrix(const LargeMatrix<SA>& mA, const LargeMatrix<SB>& mB, LargeMatrix<SR>& mR)
3826 {
3827   if(mA.nbCols!=mB.nbRows || mA.nbColsSub!=mB.nbRowsSub)
3828     {
3829       where("multMatrixMatrix(LargeMatrix,LargeMatrix)");
3830       error("largematrix_mismatch_dim");
3831     }
3832   //initialisation of mR attributes
3833   mR.valueType_=_real;
3834   if(mA.valueType_==_complex || mB.valueType_==_complex) mR.valueType_=_complex;
3835   mR.strucType=_scalar;
3836   mR.nbRowsSub=mA.nbRowsSub;
3837   mR.nbColsSub=mB.nbColsSub;
3838   if(mR.nbRowsSub>1 || mR.nbColsSub>1) mR.strucType=_matrix;
3839   mR.nbRows=mA.nbRows;
3840   mR.nbCols=mB.nbCols;
3841   mR.sym=_noSymmetry;
3842   //create storage and allocate values
3843   if(mR.storage_p!=0) delete mR.storage_p;   //delete current storage of matrix R
3844   mR.storage_p=new RowDenseStorage(mR.nbRows,mR.nbCols);     //create row dense storage
3845   mR.storage_p->objectPlus();
3846 
3847   number_t s = mR.nbRows*mR.nbCols+1;
3848   if(Trace::traceMemory)
3849     {
3850       thePrintStream<<"LargeMatrix::multMatrixMatrix re-allocates a large matrix : "<<&mR.values_<<", "
3851                     <<s<<" non zeros coefficients "<<mR.dimValues();
3852       if(mR.storage_p!=0) thePrintStream<<", storage "<<mR.storage_p->name();
3853       thePrintStream<<eol<<std::flush;
3854     }
3855   mR.values_.resize(s);
3856   //do product
3857   mA.storage_p->multMatrixMatrix(mA.values_,*mB.storage_p, mB.values_,mR.values_, mA.sym, mB.sym);
3858 }
3859 
3860 template <typename T>
operator *(const LargeMatrix<T> & mA,const LargeMatrix<T> & mB)3861 LargeMatrix<T> operator*(const LargeMatrix<T>& mA, const LargeMatrix<T>& mB)
3862 {
3863   LargeMatrix<T> mR;
3864   multMatrixMatrix(mA,mB,mR);
3865   return mR;
3866 }
3867 //specialization
3868 LargeMatrix<complex_t> operator*(const LargeMatrix<complex_t>&, const LargeMatrix<real_t>&);
3869 LargeMatrix<complex_t> operator*(const LargeMatrix<real_t>&, const LargeMatrix<complex_t>&);
3870 LargeMatrix<Matrix<complex_t> > operator*(const LargeMatrix<Matrix<complex_t> >&, const LargeMatrix<Matrix<real_t> >&);
3871 LargeMatrix<Matrix<complex_t> > operator*(const LargeMatrix<Matrix<real_t> >&, const LargeMatrix<Matrix<complex_t> >&);
3872 
3873 //extern template product matrix * diag matrix, diag matrix given by a vector
3874 //when vector is a vector of d-vectors, diag matrix is assumed to be a diag matrix of d x d diag matrices
3875 template <typename SA, typename SB, typename SR>
multMatrixMatrix(const LargeMatrix<SA> & mA,const std::vector<SB> & mB,LargeMatrix<SR> & mR)3876 void multMatrixMatrix(const LargeMatrix<SA>& mA, const std::vector<SB>& mB, LargeMatrix<SR>& mR)
3877 {
3878   if(mB.size()==0)
3879     {
3880       where("multMatrixMatrix(LargeMatrix,Vector)");
3881       error("is_void", "vector");
3882     }
3883   dimPair ds = dimsOf(mB[0]);
3884   if(mA.nbCols!=mB.size() || mA.nbColsSub!=ds.first)
3885     {
3886       where("multMatrixMatrix(LargeMatrix,Vector)");
3887       error("largematrix_mismatch_dim");
3888     }
3889   //initialisation of mR attributes
3890   structPair sp = Value::typeOf(mB[0]);
3891   mR.valueType_=_real;
3892   if(mA.valueType_==_complex || sp.first==_complex) mR.valueType_=_complex;
3893   mR.strucType=_scalar;
3894   mR.nbRowsSub=mA.nbRowsSub;
3895   mR.nbColsSub=mA.nbColsSub;
3896   if(mR.nbRowsSub>1 || mR.nbColsSub>1) mR.strucType=_matrix;
3897   mR.nbRows=mA.nbRows;
3898   mR.nbCols=mA.nbCols;
3899   mR.sym=_noSymmetry;
3900   //create storage and allocate values
3901   if(mR.storage_p!=0) delete mR.storage_p;   //delete current storage of matrix R
3902   mR.storage_p=mA.storage_p;                 //same storage as A
3903   if(Trace::traceMemory)
3904     {
3905       thePrintStream<<"LargeMatrix::multMatrixMatrix re-allocates a large matrix : "<<&mR.values_<<", "
3906                     <<mR.storage_p->size()<<" non zeros coefficients "<<mR.dimValues();
3907       if(mR.storage_p!=0) thePrintStream<<", storage "<<mR.storage_p->name();
3908       thePrintStream<<eol<<std::flush;
3909     }
3910   mR.values_.resize(mR.storage_p->size());
3911   //do product
3912   mA.storage_p->multMatrixDiagMatrix(mA.values_, mB,mR.values_);
3913 }
3914 
3915 //no operator * :  matrix * diag matrix (ambiguity with matrix * vector) , use multMarixMatrix
3916 
3917 //extern template product diag matrix * matrix, diag matrix given by a vector
3918 //when vector is a vector of d-vectors, diag matrix is assumed to be a diag matrix of d x d diag matrices
3919 template <typename SA, typename SB, typename SR>
multMatrixMatrix(const std::vector<SA> & mA,const LargeMatrix<SB> & mB,LargeMatrix<SR> & mR)3920 void multMatrixMatrix(const std::vector<SA>& mA, const LargeMatrix<SB>& mB, LargeMatrix<SR> & mR)
3921 {
3922   if(mB.size()==0)
3923     {
3924       where("multMatrixMatrix(Vector,LargeMatrix)");
3925       error("is_void", "vector");
3926     }
3927   dimPair ds = dimsOf(mA[0]);
3928   if(mB.nbCols!=mA.size() || mB.nbColsSub!=ds.first)
3929     {
3930       where("multMatrixMatrix(Vector,LargeMatrix)");
3931       error("largematrix_mismatch_dim");
3932     }
3933   //initialisation of mR attributes
3934   structPair sp = Value::typeOf(mA[0]);
3935   mR.valueType_=_real;
3936   if(mB.valueType_==_complex || sp.first==_complex) mR.valueType_=_complex;
3937   mR.strucType=_scalar;
3938   mR.nbRowsSub=mB.nbRowsSub;
3939   mR.nbColsSub=mB.nbColsSub;
3940   if(mR.nbRowsSub>1 || mR.nbColsSub>1) mR.strucType=_matrix;
3941   mR.nbRows=mB.nbRows;
3942   mR.nbCols=mB.nbCols;
3943   mR.sym=_noSymmetry;
3944   //create storage and allocate values
3945   if(mR.storage_p!=0) delete mR.storage_p;   //delete current storage of matrix R
3946   mR.storage_p=mB.storage_p;                 //same storage as B
3947   if(Trace::traceMemory)
3948     {
3949       thePrintStream<<"LargeMatrix::multMatrixMatrix re-allocates a large matrix : "<<&mR.values_<<", "
3950                     <<mR.storage_p->size()<<" non zeros coefficients "<<mR.dimValues();
3951       if(mR.storage_p!=0) thePrintStream<<", storage "<<mR.storage_p->name();
3952       thePrintStream<<eol<<std::flush;
3953     }
3954   mR.values_.resize(mR.storage_p->size());
3955   //do product
3956   mB.storage_p->multDiagMatrixMatrix(mA,mB.values_,mR.values_);
3957 }
3958 
3959 //no operator * :  diag matrix * matrix (ambiguity with vector * matrix), use multMarixMatrix
3960 
3961 
3962 // special hermitian product for vectors of form (row index, val), the second is given as a map row index -> val for better efficiency
3963 // function used by QR algorithm
3964 template<typename T, typename K>
3965 T hermitianProduct(const std::vector<std::pair<number_t,T> >& u, const std::map<number_t,K>& v)
3966 {
3967   typename std::vector<std::pair<number_t,T> >::const_iterator itu=u.begin();
3968   typename std::map<number_t,K>::const_iterator itve=v.end(), itv;
3969   T hp=0.;
3970   for(; itu!=u.end(); itu++)
3971     {
3972       itv=v.find(itu->first);
3973       if(itv!=itve) hp+=itu->second * conj(itv->second);
3974     }
3975   return hp;
3976 }
3977 
3978 // special dot product for vectors of form (row index, val), the second is given as a map row index -> val for better efficiency
3979 // function used by QR algorithm
3980 template<typename T, typename K>
3981 T dotProduct(const std::vector<std::pair<number_t,T> >& u, const std::map<number_t,K>& v)
3982 {
3983   typename std::vector<std::pair<number_t,T> >::const_iterator itu=u.begin();
3984   typename std::map<number_t,K>::const_iterator itve=v.end(), itv;
3985   T hp=0.;
3986   for(; itu!=u.end(); itu++)
3987     {
3988       itv=v.find(itu->first);
3989       if(itv!=itve) hp+=itu->second * itv->second;
3990     }
3991   return hp;
3992 }
3993 
3994 // do special linear combination u + av, used in QR algorithm
3995 // use an (index, value) representation and eliminate near 0 components
3996 template<typename T, typename K>
combine(std::vector<std::pair<number_t,K>> & u,const std::map<number_t,T> & v,K a)3997 void combine(std::vector<std::pair<number_t,K> >& u, const std::map<number_t,T>& v, K a)
3998 {
3999   std::vector<std::pair<number_t,K> > uv;
4000   uv.reserve(u.size()+v.size());
4001   std::set<number_t> markv;
4002   typename std::vector<std::pair<number_t,K> >::iterator itu=u.begin();
4003   typename std::map<number_t,T>::const_iterator itve=v.end(), itv;
4004   for(; itu!=u.end(); itu++)
4005     {
4006       itv=v.find(itu->first);
4007       K r= itu->second;
4008       if(itv!=itve)
4009         {
4010           r += a * itv->second;
4011           markv.insert(itu->first);
4012         }
4013       if(norm2(r)>10*theEpsilon) uv.push_back(std::pair<number_t, K>(itu->first,r));
4014     }
4015   if(markv.size()<v.size())  //add to u unmarked v components
4016     {
4017       for(itv=v.begin(); itv!=v.end(); itv++)
4018         if(markv.find(itv->first) == markv.end() && xlifepp::norm2(itv->second)> 10*theEpsilon)  //v component not found
4019           uv.push_back(std::pair<number_t,K>(itv->first, a*itv->second));
4020     }
4021   u=uv;
4022 }
4023 
4024 //create transposed matrix
4025 template <typename T>
transpose(const LargeMatrix<T> & L)4026 LargeMatrix<T> transpose(const LargeMatrix<T>& L)
4027 {
4028   LargeMatrix<T> Lt;
4029   Lt.valueType_=L.valueType_;
4030   Lt.strucType=L.strucType;
4031   Lt.nbRows=L.nbCols;
4032   Lt.nbCols=L.nbRows;
4033   Lt.nbRowsSub=L.nbColsSub;
4034   Lt.nbColsSub=L.nbRowsSub;
4035   Lt.sym=L.sym;
4036   Lt.name=L.name+"^t";
4037   Lt.factorization_=_noFactorization;  //forgot factorisation properties
4038 #ifdef XLIFEPP_WITH_UMFPACK
4039   Lt.umfLU_p=0;
4040   if(L.umfLU_p!=0)
4041     warning("free_warning","LargeMatrix transpose does not keep the umfpackLU object, redo factorisation if required");
4042 #endif
4043   Lt.storagep()=0;
4044   if(L.storagep()==0)
4045   {
4046     where("transpose(LargeMatrix)");
4047     error("matrix_nostorage");
4048   }
4049   Lt.storagep() = L.storagep()->transpose(L.values(),Lt.values());  //build the transposed storage and fill values
4050   return Lt;
4051 }
4052 
4053 //-----------------------------------------------------------------------------------------------------------
4054 /*!
4055    QR factorization of rectangular matrix pxn using Housolder method
4056    generic algorithm using a column algorithm with dynamic storage creation of matrix results
4057 
4058    mat      : matrix to factorize
4059    matR     : upper triangular matrix p x n stored as ColCsStorage (pointer)
4060    matQ     : unitary matrix of size p x p  stored as RowCsStorage (pointer)
4061    computeQ : if true the matrix Q is computed else not
4062    rhs      : right hand side vector pointer (modified), if 0 no rhs
4063    withColPermutation : if true, column may be permuted (more stable factorization).
4064             if false and algorithm fails, withColPermutation is forced to true and algorithm is rerun
4065    numcol_p : renumbering of columns if they have been permuted (pointer)
4066    stop     : iteration number when the algorithm stops: stop = nbr when algorithm exits normally
4067 
4068    Note 1 : to avoid unsightly rounding effect in reduction, values < 10*theEspsilon (~10^-15) are rounded to 0
4069    Note 2 : when there are constraint redanduncies, it may occur some average effects.
4070       For instance, two Dirichlet conditions at the same point (in Lagrange interpolation)
4071       with different right hand side produce a Dirichlet condition with a mean of right hand sides
4072       It may be inconvenient !
4073  */
4074 //-----------------------------------------------------------------------------------------------------------
4075 
4076 template<typename T, typename K>
QR(const LargeMatrix<T> & mat,LargeMatrix<T> * & matR,bool computeQ,LargeMatrix<T> * & matQ,std::vector<K> * rhs,bool & withColPermutation,std::vector<number_t> * & numcol_p,number_t & stop)4077 void QR(const LargeMatrix<T>& mat, LargeMatrix<T>*& matR, bool computeQ, LargeMatrix<T>*& matQ, std::vector<K>* rhs,
4078         bool& withColPermutation, std::vector<number_t>*& numcol_p, number_t& stop)
4079 {
4080   number_t nbr=mat.nbRows, nbc=mat.nbCols;
4081   //if(nbr > nbc) error("free_error","in ColCsStorage::QR, algorithm can no be applied when nbRows > nbCol");
4082 
4083   trace_p->push("QR(LargeMatrix, ...");
4084 
4085   //initialization of numcol
4086   numcol_p= new std::vector<number_t>(nbc);
4087   std::vector<number_t>& numcol= *numcol_p;
4088   std::vector<number_t>::iterator itn =numcol.begin();
4089   for(number_t j=0; j<nbc; j++, itn++) *itn = j;
4090 
4091   //construct special column representation of R matrix, for each column -> vector of pair of row index and value
4092   std::vector<std::vector<std::pair<number_t,T> > > cr(nbc);
4093   typename std::vector<std::vector<std::pair<number_t,T> > >::iterator itcr=cr.begin();
4094   typename std::vector<std::pair<number_t,T> >::iterator itcv;
4095   typename std::vector<std::pair<number_t,K> >::iterator itsv;
4096 
4097   number_t c=1;
4098   for(; itcr!=cr.end(); itcr++, c++)
4099     {
4100       std::vector<std::pair<number_t, number_t> > rowadrs=mat.getCol(c);
4101       std::vector<std::pair<number_t,T> > colval(rowadrs.size());
4102       itcv=colval.begin();
4103       std::vector<std::pair<number_t, number_t> >::iterator itra=rowadrs.begin();
4104       for(; itra!=rowadrs.end(); itra++, itcv++) *itcv= std::pair<number_t,T>(itra->first-1, mat.values()[itra->second]);
4105       *itcr=colval;
4106     }
4107 
4108   //construct special row representation of Q matrix, for each row -> vector of pair of col index and value
4109   std::vector<std::vector<std::pair<number_t,T> > > qr;
4110   if(computeQ)
4111     {
4112       qr.resize(nbr);
4113       itcr=qr.begin();
4114       number_t i=0;
4115       for(; itcr!=qr.end(); itcr++, i++) *itcr =std::vector<std::pair<number_t,T> >(1,std::pair<number_t,T>(i,T(1)));
4116     }
4117 
4118   //construct special representation of rhs vector, row index and value
4119   std::vector<std::pair<number_t,K> > rhsr;
4120   if(rhs!=0)
4121     {
4122       rhsr.resize(nbr);
4123       number_t i=0;
4124       typename std::vector<K>::iterator itv=rhs->begin();
4125       for(itsv=rhsr.begin(); itsv!=rhsr.end(); itsv++, itv++, i++) *itsv= std::pair<number_t,K>(i,*itv);
4126     }
4127 
4128   //to store diagonal of R matrix
4129   std::vector<T> diag(nbr, T(0));
4130   typename std::vector<T>::iterator itdiag=diag.begin();
4131 
4132   bool cont=true;
4133   number_t k=0, m=std::min(nbr,nbc);
4134   real_t releps=.001;
4135 
4136   //main loop of Housolder reduction
4137   //--------------------------------
4138   for(; k<m && cont; k++, itdiag++)
4139     {
4140       real_t nk=0;
4141       number_t numk=numcol[k];
4142       std::vector<std::pair<number_t,T> >& crk=cr[numk];
4143       for(itcv=crk.begin(); itcv!=crk.end(); itcv++)
4144         if(itcv->first>=k)
4145           {
4146             real_t nit=xlifepp::norm2(itcv->second);
4147             nk+=nit*nit;
4148           }
4149       real_t vmax=std::sqrt(nk);
4150       //locate column of largest amplitude if permutation allowed
4151       if(withColPermutation)
4152         {
4153           number_t jmax = k;
4154           for(number_t j=k+1; j< nbc; j++)  //travel column
4155             {
4156               real_t nj=0;
4157               std::vector<std::pair<number_t,T> >& crj=cr[numcol[j]];
4158               for(itcv=crj.begin(); itcv!=crj.end(); itcv++)
4159                 if(itcv->first>=k)
4160                   {
4161                     real_t nit=xlifepp::norm2(itcv->second);
4162                     nj+=nit*nit;
4163                   }
4164               nj=std::sqrt(nj);
4165               if(nj > vmax*(1+releps))
4166                 {
4167                   jmax=j;  //add criterium nj>(1+releps)vmax to avoid useless permutation
4168                   vmax=nj;
4169                 }
4170             }
4171           if(jmax!=k)
4172             {
4173               numcol[k]=numcol[jmax];  //virtual permutation of columns k and j
4174               numcol[jmax]=numk;
4175             }
4176         }
4177       if(vmax< 10*theEpsilon)  cont=false;
4178       else
4179         {
4180           //construct Housolder vector vk
4181           std::map<number_t,T> vk;
4182           numk = numcol[k];
4183           for(itcv=cr[numk].begin(); itcv!=cr[numk].end(); itcv++)
4184             if(itcv->first >= k) vk[itcv->first]=itcv->second;  //sorted vector vk
4185           typename std::map<number_t,T>::iterator itvk;
4186           itvk=vk.find(k);
4187           if(itvk==vk.end()) vk[k]=-vmax;
4188           else itvk->second-=vmax;
4189           real_t nmoins=0;
4190           for(itvk=vk.begin(); itvk!=vk.end(); itvk++)
4191             {
4192               real_t nit=xlifepp::norm2(itvk->second);
4193               nmoins+=nit*nit;
4194             }
4195           vk[k]+=2*vmax;
4196           real_t nplus=0;
4197           for(itvk=vk.begin(); itvk!=vk.end(); itvk++)
4198             {
4199               real_t nit=xlifepp::norm2(itvk->second);
4200               nplus+=nit*nit;
4201             }
4202           if(nplus >= nmoins)
4203             {
4204               if(nmoins>10*theEpsilon) vk[k]-=2*vmax;
4205               else nmoins=nplus;
4206             }
4207           else
4208             {
4209               if(nplus>10*theEpsilon)  nmoins=nplus;
4210               else vk[k]-=2*vmax;
4211             };
4212           nmoins=std::sqrt(nmoins);
4213           for(itvk=vk.begin(); itvk!=vk.end(); itvk++) itvk->second/=nmoins; //Housolder vector
4214           std::map<number_t,T> cvk=vk;
4215           for(itvk=cvk.begin(); itvk!=cvk.end(); itvk++) itvk->second=conj(itvk->second); //conjugated Housolder vector
4216 
4217           //update R and Q from H=I-2vv*
4218           //itn =numcol.begin()+k;
4219           itn =numcol.begin();
4220 #ifdef XLIFEPP_WITH_OMP
4221           #pragma omp parallel for schedule(dynamic) firstprivate(vk)
4222 #endif
4223           for(number_t j=k; j<nbc; j++)
4224             {
4225               std::vector<std::pair<number_t,T> >& crj=cr[*(itn+j)];
4226               T psj= hermitianProduct(crj,vk);                                   //special hermitian product
4227               if(xlifepp::norm2(psj) > 10*theEpsilon) combine(crj, vk, -2*psj);  // do linear combination cr[rj]-2psj*vk = Hk*cr[rj]
4228               itcv=crj.begin();
4229               if(j==k)
4230                 {
4231                   bool cont = true;
4232                   while(cont && itcv!=crj.end())
4233                     {
4234                       if(itcv->first == k)
4235                         {
4236                           *itdiag = itcv->second;
4237                           cont=false;
4238                         }
4239                       ++itcv;
4240                     }
4241                 }
4242             }
4243           if(computeQ)
4244             {
4245               itcr=qr.begin();
4246               for(; itcr!=qr.end(); itcr++)
4247                 {
4248                   T psi= dotProduct(*itcr,vk);                               //special dot product
4249                   if(norm2(psi)> 10*theEpsilon) combine(*itcr, cvk, -2*psi);// do linear combination qr[i]-2psi*conj(vk) = qr[i]*Hk^*
4250                 }
4251             }
4252           if(rhs!=0) //update rhsr
4253             {
4254               K ps= hermitianProduct(rhsr, vk);                                //special hermitian product
4255               if(xlifepp::norm2(ps)> 10*theEpsilon) combine(rhsr, vk, -2*ps);  //do linear combination rhsr-2ps*vk = Hk*rhsr
4256 
4257             }
4258         } //end else
4259     } //end for(number_t k=0; k<m; k++)
4260 
4261   //end of algorithm (retry if fails)
4262   if(!cont && !withColPermutation) //retry QR algorithm forcing permutation of columns
4263     {
4264       warning("free_warning","QR algorithm without column permutation failed, retry forcing column permutation");
4265       withColPermutation=true;
4266       qr.clear();
4267       cr.clear();
4268       rhsr.clear();
4269       delete numcol_p;
4270       QR(mat, matR, computeQ, matQ, rhs, withColPermutation, numcol_p, stop);
4271     }
4272   else // generate final matrix
4273     {
4274       stop=m;
4275       if(!cont)
4276         {
4277           stop=k-1;
4278           warning("free_warning","QR algorithm with column permutation stopped at iteration "+tostring(stop));
4279         }
4280       //create LargeMatrix R, (we normalize R,  dividing row r by the diagonal coefficient)
4281       std::vector< std::vector<number_t> > rowindex(nbc);
4282       std::vector< std::vector<number_t> >::iterator itri=rowindex.begin();
4283       itn=numcol.begin();
4284       for(itcr=cr.begin(); itcr!=cr.end(); itcr++, itri++, itn++) //rearrange row indices
4285         {
4286           std::vector<std::pair<number_t,T> >& crc=cr[*itn];
4287           std::vector<number_t> ric(crc.size());
4288           std::vector<number_t>::iterator itk = ric.begin();
4289           for(itcv=crc.begin(); itcv!=crc.end(); itcv++, itk++) *itk=itcv->first +1;
4290           *itri = ric;
4291         }
4292       ColCsStorage* css=new ColCsStorage(nbr, nbc, rowindex);  //create col storage
4293       matR=new LargeMatrix<T>(mat.valueType_, mat.strucType, nbr, nbc, _noSymmetry, mat.nbRowsSub, mat.nbColsSub, T(0), "R", css);
4294       typename std::vector<T>::iterator itval=matR->values().begin()+1;
4295       itn=numcol.begin();
4296       for(itcr=cr.begin(); itcr!=cr.end(); itcr++, itn++)  //sequential copy of values
4297         {
4298           std::vector<std::pair<number_t,T> >& crc=cr[*itn];
4299           for(itcv=crc.begin(); itcv!=crc.end(); itcv++, itval++)
4300             {
4301               *itval = itcv->second;
4302               number_t r=itcv->first;
4303               T d=diag[r];
4304               if(d!=T(0)) *itval /=d;
4305             }
4306         }
4307       //create LargeMatrix Q if required
4308       matQ=0;
4309       if(computeQ)
4310         {
4311           std::vector< std::vector<number_t> > colindex(nbr);
4312           std::vector< std::vector<number_t> >::iterator itci=colindex.begin();
4313           for(itcr=qr.begin(); itcr!=qr.end(); itcr++, itci++) //rearrange row indices
4314             {
4315               std::vector<std::pair<number_t,T> >& qri=*itcr;
4316               std::vector<number_t> ric(qri.size());
4317               itn=ric.begin();
4318               for(itcv=qri.begin(); itcv!=qri.end(); itcv++, itn++) *itn=itcv->first +1;
4319               *itci = ric;
4320             }
4321           RowCsStorage* rss=new RowCsStorage(nbr, nbr, colindex);  //create row storage
4322           matQ=new LargeMatrix<T>(mat.valueType_, mat.strucType, nbr, nbr, _noSymmetry, mat.nbRowsSub, mat.nbColsSub, T(0), "Q", rss);
4323           itval=matQ->values().begin()+1;
4324           for(itcr=qr.begin(); itcr!=qr.end(); itcr++)  //sequential copy of values
4325             {
4326               std::vector<std::pair<number_t,T> >& qri=*itcr;
4327               for(itcv=qri.begin(); itcv!=qri.end(); itcv++, itval++) *itval = itcv->second;
4328             }
4329         }
4330       if(rhs!=0) //update rhs
4331         {
4332           rhs->clear();
4333           rhs->resize(nbr, K(0));
4334           typename std::vector<K>::iterator itv=rhs->begin();
4335           for(itsv=rhsr.begin(); itsv!=rhsr.end(); itsv++)
4336             {
4337               number_t r=itsv->first;
4338               T d=diag[r];
4339               if(d!=T(0)) * (itv + r) = itsv->second / d;  // normalization
4340               else * (itv + r) = itsv->second;
4341             }
4342         }
4343 
4344       //finalization
4345       if(!withColPermutation)
4346         {
4347           delete numcol_p;
4348           numcol_p=0;
4349         }
4350     }
4351 
4352   trace_p->pop();
4353 }
4354 /*!
4355    solve upper triangular system pxp with diag = Id with a list of right hand sides
4356    each right hand side is a vector of pairs (row index, value)
4357    using a column algorithm with dynamic storage update
4358           p
4359       | 1 x ... x |
4360       | 0 1 ... x |
4361  at = |     ...   |
4362       | 0   0 1 x |
4363       | 0     0 1 |
4364 
4365    mat      : upper triangular matrix
4366    rhss     : list of right hand sides
4367 
4368    rhss is overwritten !
4369 
4370 */
4371 template<typename T, typename K>
QRSolve(const LargeMatrix<T> & mat,std::vector<std::vector<std::pair<number_t,K>>> & rhss)4372 void QRSolve(const LargeMatrix<T>& mat, std::vector<std::vector<std::pair<number_t,K> > >& rhss)
4373 {
4374   number_t p=mat.nbRows, k = p;
4375   typename std::vector<std::vector<std::pair<number_t,K> > >::iterator itr;
4376   typename std::vector<std::pair<number_t,K> >::iterator itp;
4377   const std::vector<T>& val=mat.values();
4378   for(; k>1; k--)
4379     {
4380       std::vector<std::pair<number_t, number_t> > colpadr=mat.getCol(k, 1, k-1);
4381       if(colpadr.size()>0)
4382         {
4383           std::vector<std::pair<number_t, number_t> >::iterator ita=colpadr.begin();
4384           std::map<number_t,T> mapval;
4385           for(; ita!=colpadr.end(); ita++) mapval.insert(std::make_pair(ita->first-1,val[ita->second]));
4386           for(itr=rhss.begin(); itr!=rhss.end(); itr++)
4387             {
4388               itp=itr->begin();
4389               bool cont=true;
4390               while(itp!=itr->end() && cont)   //to be improved (sequential search)
4391                 {
4392                   if(itp->first == k-1)
4393                     {
4394                       combine(*itr, mapval,-itp->second);
4395                       cont=false;
4396                     }
4397                   itp++;
4398                 }
4399             }
4400         }
4401     }
4402 }
4403 
4404 // solve upper triangular system mat * x = b with some matrix columns and one vector as right hand sides
4405 // diagonal coefficient of mat are assumed to be 1
4406 // create a general right hand sides with storage well adapted to dynamic column size computation used in previous function
4407 // Note : this particular form has been developed in the context of management of essential conditions where matrices are very sparse
4408 // WARNING : this algorithm does not work yet if template T and K are not the same !!! TODO in future
4409 template<typename T, typename K>
QRSolve(const LargeMatrix<T> & mat,LargeMatrix<T> * mat2,std::vector<K> * rhs)4410 void QRSolve(const LargeMatrix<T>& mat, LargeMatrix<T>* mat2, std::vector<K>* rhs)
4411 {
4412   if(mat2==0 && rhs==0) return;
4413   trace_p->push("QRSolve(LargeMatrix, ...");
4414 
4415   number_t nr=0, nbr=mat.nbRows, nbc=0;
4416   if(rhs!=0) nr+=1;
4417   if(mat2!=0)
4418     {
4419       nbc=mat2->nbCols;
4420       nr+=nbc;
4421     }
4422   std::vector<std::vector<std::pair<number_t,K> > > rhss;
4423   rhss.resize(nr);
4424   typename std::vector<std::vector<std::pair<number_t,K> > >::iterator itr=rhss.begin();
4425   typename std::vector<std::pair<number_t, K> >::iterator its;
4426   typename std::vector<std::pair<number_t, T> >::iterator itv;
4427 
4428   if(mat2!=0)
4429     {
4430       std::vector<T>& val=mat2->values();
4431       for(number_t c=1; c<=nbc; c++, itr++)
4432         {
4433           std::vector<std::pair<number_t, number_t> > colpadr=mat2->getCol(c);
4434           std::vector<std::pair<number_t, number_t> >::iterator ita=colpadr.begin();
4435           itr->resize(colpadr.size());
4436           itv=itr->begin();
4437           for(; ita!=colpadr.end(); ita++, itv++) *itv = std::make_pair(ita->first-1,val[ita->second]);
4438         }
4439     }
4440 
4441   if(rhs!=0)
4442     {
4443       itr->resize(nbr);
4444       itv=itr->begin();
4445       typename std::vector<T>::iterator its=rhs->begin();
4446       for(number_t r=0; r<nbr; r++, itv++, its++) *itv = std::make_pair(r,*its);
4447     }
4448 
4449   QRSolve(mat,rhss);   //call general QRSolver
4450 
4451   if(mat2!=0)   //reconstruct mat2
4452     {
4453       mat2->clear();
4454       std::vector< std::vector<number_t> > rowindex(nbc);
4455       std::vector< std::vector<number_t> >::iterator itri=rowindex.begin();
4456       itr=rhss.begin();
4457       for(number_t c=0; c<nbc; c++, itr++, itri++)
4458         {
4459           itri->resize(itr->size());
4460           std::vector<number_t>::iterator itk = itri->begin();
4461           for(itv=itr->begin(); itv!=itr->end(); itv++, itk++) *itk=itv->first +1;
4462         }
4463       ColCsStorage* css=new ColCsStorage(nbr, nbc, rowindex);  //create col storage
4464       mat2->init(css, T(0), _noSymmetry);
4465       typename std::vector<T>::iterator itval=mat2->values().begin()+1;
4466       itr=rhss.begin();
4467       for(number_t c=0; c<nbc; c++, itr++)
4468         for(itv=itr->begin(); itv!=itr->end(); itv++, itval++) *itval=itv->second;
4469     }
4470 
4471   if(rhs!=0) //reconstruct rhs
4472     {
4473       rhs->clear();
4474       rhs->resize(nbr,T(0));
4475       for(its=itr->begin(); its!=itr->end(); its++) *(rhs->begin()+ its->first) =its->second;
4476     }
4477   trace_p->pop();
4478 }
4479 
4480 //Gauss solver using algorithms defined in storage classes
4481 template<typename T>
gaussSolve(LargeMatrix<T> & mat,std::vector<std::vector<T>> & rhss)4482 void gaussSolve(LargeMatrix<T>& mat, std::vector<std::vector<T> >& rhss)
4483 {
4484   mat.storagep()->gaussSolver(mat.values(),rhss);
4485 }
4486 
4487 template<typename T>
gaussSolve(LargeMatrix<T> & mat,std::vector<T> & rhs)4488 void gaussSolve(LargeMatrix<T>& mat, std::vector<T>& rhs)
4489 {
4490   mat.storagep()->gaussSolver(mat.values(),rhs);
4491 }
4492 
4493 //-----------------------------------------------------------------------------------------------------------------------------
4494 /*!
4495   Resolve an eigen problem with block davidson method
4496   \param[in] pA Pointer to large matrix A of the eigen problem A*X = lambda*B*X. It MUSTN'T be NULL
4497   \param[in] pB Pointer to large matrix B of the eigen problem A*X = lambda*B*X. If it's NULL. Eigen problem is standard: A*X=lambda*X
4498   \param[in,out] res result
4499   \param[in] nev The number of eigen values and eigenSolver searched for
4500   \param[in] tol Tolerance
4501   \param[in] which Specification of which eigen values are returned. Largest-LM, Smallest-SM,
4502   \param[in] isInverted true if inverted matrix
4503   \param[in] fac factorization type
4504   \param[in] isShift true if eigen problem with shift or not
4505 */
4506 template<typename ST>
eigenDavidsonSolve(const LargeMatrix<ST> * pA,const LargeMatrix<ST> * pB,std::vector<std::pair<complex_t,Vector<complex_t>>> & res,number_t nev,real_t tol,string_t which,bool isInverted,FactorizationType fac,bool isShift)4507 number_t eigenDavidsonSolve(const LargeMatrix<ST>* pA, const LargeMatrix<ST>* pB, std::vector<std::pair<complex_t,Vector<complex_t> > >& res,
4508                             number_t nev, real_t tol, string_t which, bool isInverted, FactorizationType fac, bool isShift)
4509 {
4510   if(0 == pA)
4511     {
4512       where("eigenDavidsonSolve(...)");
4513       error("is_void", "matrix A");
4514     }
4515   if((0 != pB) && ((_symmetric != pB->sym) && (_selfAdjoint != pB->sym)))
4516     {
4517       where("eigenDavidsonSolve(...)");
4518       error("largematrix_mismatch_sym");
4519     }
4520   if((0 != pA) && (0 != pB) && (pA->nbCols != pB->nbCols))
4521     {
4522       where("eigenDavidsonSolve(...)");
4523       error("largematrix_mismatch_dim");
4524     }
4525   if(nev > pA->nbCols)
4526     {
4527       where("eigenDavidsonSolve(...)");
4528       error("is_greater", nev, pA->nbCols);
4529     }
4530 
4531   typedef NumTraits<ST> SCT;
4532   typedef MultiVec<ST>  MV;
4533   typedef Operator<ST>  OP;
4534 
4535   string_t ortho("SVQB");
4536   bool locking = true;
4537   bool insitu = false;
4538   MsgEigenType verbosity = _errorsEigen;
4539 
4540   number_t probSize = pA->nbCols;
4541   number_t maxNumBlocks = 5;
4542   int_t maxLocks = nev;
4543   int_t maxRestarts = 200;
4544 
4545   // Compute automatically nev and blockSize as well as numblock
4546   number_t blockSize = nev;
4547   number_t numBlocks = 2;
4548   while((blockSize*numBlocks) > probSize) --blockSize;
4549   for(number_t i = 3 ; i <= maxNumBlocks; ++i)
4550     {
4551       if((blockSize*i) > probSize) break;
4552       numBlocks = i;
4553     }
4554 
4555   while(((blockSize+maxLocks) > nev) && ((blockSize*numBlocks+maxLocks) > probSize)) --maxLocks;
4556   if(maxLocks < 0)
4557     {
4558       maxLocks = 0;
4559       locking = false;
4560     }
4561   while((numBlocks>2) && ((blockSize*numBlocks+maxLocks) > probSize)) --numBlocks;
4562   if((blockSize*numBlocks+maxLocks) > probSize)
4563     {
4564       nev = static_cast<int>(std::floor(probSize/numBlocks));
4565       blockSize = nev;
4566       maxLocks  = probSize - (blockSize*numBlocks);
4567       string_t msg = "ATTENTION! LargeMatrix::eigenDavidsonSolver. Because the matrix is too small. Only ";
4568       msg += tostring(nev) + " eigenvalues can be retrieved! \n";
4569       warning("free_warning",msg);
4570     }
4571 
4572   // Create parameter list to pass into the solver manager
4573   Parameters pl;
4574   pl.add("Verbosity", (int_t)verbosity);
4575   pl.add("Which", which);
4576   pl.add("Orthogonalization", ortho);
4577   pl.add("Block Size", blockSize);
4578   pl.add("Num Blocks", numBlocks);
4579   pl.add("Maximum Restarts", maxRestarts);
4580   pl.add("Convergence Tolerance", tol);
4581   pl.add("Use Locking", locking);
4582   pl.add("Locking Tolerance", tol/10);
4583   pl.add("In Situ Restarting", insitu);
4584   pl.add("Max Locked", maxLocks);
4585 
4586   SmartPtr<const OP> A = _smPtrNull, B = _smPtrNull;
4587   if(0 != pB)
4588     {
4589       if(isShift)
4590         {
4591           pl.add("Which", string_t("LM"));
4592           A = new LargeMatrixAdapterInverseGeneralized<LargeMatrix<ST>,ST>(pA, pB, fac);
4593         }
4594       else
4595         {
4596           if("SM" == which)
4597             {
4598               pl.add("Which", string_t("LM"));
4599               A = new LargeMatrixAdapterInverseGeneralized<LargeMatrix<ST>,ST>(pA, pB, fac);
4600             }
4601           else
4602             {
4603               A = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pA);
4604               B = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pB);
4605             }
4606         }
4607     }
4608   else
4609     {
4610       if(isShift)
4611         {
4612           A = new LargeMatrixAdapterInverse<LargeMatrix<ST>,ST>(pA, fac);
4613         }
4614       else
4615         {
4616           if("SM" == which)
4617             {
4618               pl.add("Which", string_t("LM"));
4619               A = new LargeMatrixAdapterInverse<LargeMatrix<ST>,ST>(pA, fac);
4620             }
4621           else
4622             {
4623               A = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pA);
4624             }
4625         }
4626     }
4627 
4628   SmartPtr<MV> ivec = SmartPtr<MultiVecAdapter<ST> >(new MultiVecAdapter<ST>(pA->nbCols, blockSize));
4629   ivec->mvRandom();
4630 
4631   // Define eigen problem
4632   SmartPtr<EigenProblem<ST,MV,OP> > problem;
4633   if(_smPtrNull != B) problem = SmartPtr<EigenProblem<ST,MV,OP> >(new EigenProblem<ST,MV,OP>(A,B,ivec));
4634   else problem = SmartPtr<EigenProblem<ST,MV,OP> >(new EigenProblem<ST,MV,OP>(A,ivec));
4635 
4636   // Inform the eigenproblem that the operator cK is symmetric
4637   problem->setHermitian(true);
4638 
4639   // Set the number of eigenvalues requested
4640   problem->setNEV(nev);
4641 
4642   // Inform the eigenproblem that you are done passing it information
4643   bool boolret = problem->setProblem();
4644   if(!boolret) error("eigen_eigenproblem", "");
4645 
4646   BlockDavidsonSolMgr<ST,MV,OP> bdSolverMan(problem, pl);
4647   ComputationInfo returnCode = bdSolverMan.solve();
4648 
4649   number_t numev = 0;
4650   if(_success == returnCode)
4651     {
4652       EigenSolverSolution<ST,MV> sol = problem->getSolution();
4653       SmartPtr<MV> evecs = sol.evecs;
4654       numev = sol.numVecs;
4655       res.resize(numev);
4656       for(number_t i = 0; i<numev; i++)
4657         {
4658           std::vector<complex_t> eVec(ivec->getVecLength());
4659           for(number_t j = 0; j < ivec->getVecLength(); ++j)
4660             {
4661               if(0 == sol.index[i]) eVec[j] = (complex_t(SCT::real((*evecs)(j,i)),0));
4662               else if(1 == sol.index[i]) eVec[j] = (complex_t(SCT::real((*evecs)(j,i)),SCT::real((*evecs)(j,i+1))));
4663               else eVec[i] = (complex_t(SCT::real((*evecs)(j,i-1)),SCT::real((*evecs)(j,i))));
4664             }
4665           res.at(i) = std::make_pair(complex_t(sol.evals[i].realpart,sol.evals[i].imagpart), eVec);
4666         }
4667     }
4668 
4669   return (numev);
4670 }
4671 
4672 //-----------------------------------------------------------------------------------------------------------------------------
4673 /*!
4674   Resolve an eigen problem with block Krylov-Schur method
4675  \param[in] pA Pointer to large matrix A of the eigen problem A*X = lambda*B*X. It MUSTN'T be NULL
4676  \param[in] pB Pointer to large matrix B of the eigen problem A*X = lambda*B*X. If it's NULL. Eigen problem is standard: A*X=lambda*X
4677  \param[in,out] res result
4678  \param[in] nev The number of eigen values and eigenSolver searched for
4679  \param[in] tol Tolerance
4680  \param[in] which Specification of which eigen values are returned. Largest-LM, Smallest-SM,
4681  \param[in] isInverted true if inverted matrix
4682  \param[in] fac factorization type
4683  \param[in] isShift true if eigen problem with shift or not
4684 */
4685 template<typename ST>
eigenKrylovSchurSolve(const LargeMatrix<ST> * pA,const LargeMatrix<ST> * pB,std::vector<std::pair<complex_t,Vector<complex_t>>> & res,number_t nev,real_t tol,string_t which,bool isInverted,FactorizationType fac,bool isShift)4686 number_t eigenKrylovSchurSolve(const LargeMatrix<ST>* pA, const LargeMatrix<ST>* pB, std::vector<std::pair<complex_t,Vector<complex_t> > >& res,
4687                                number_t nev, real_t tol, string_t which, bool isInverted, FactorizationType fac, bool isShift)
4688 {
4689   if (0 == pA)
4690   {
4691     where("eigenKrylovSchurSolve(...)");
4692     error("null_pointer", "matrix A");
4693   }
4694   if (nev > pA->nbCols)
4695   {
4696     where("eigenKrylovSchurSolve(...)");
4697     error("is_greater", nev, pA->nbCols);
4698   }
4699   typedef NumTraits<ST> SCT;
4700   typedef MultiVec<ST>  MV;
4701   typedef Operator<ST>  OP;
4702 
4703   string_t ortho("SVQB");
4704   bool insitu = false;
4705   MsgEigenType verbosity = _errorsEigen;
4706 
4707   number_t probSize = pA->nbCols;
4708   number_t maxNumBlocks = (nev < 3) ? 3 : nev;
4709   number_t maxRestarts = 250;
4710 
4711   //
4712   // Compute automatically nev and blockSize as well as numblock
4713   //
4714   number_t blockSize = 1;
4715   number_t numBlocks = (nev/blockSize < 3) ? 3 : (static_cast<int>(std::ceil(nev/blockSize)));
4716   number_t i = 0;
4717   while(i<(maxNumBlocks-3))
4718     {
4719       if((blockSize*numBlocks) > probSize) break;
4720       ++numBlocks;
4721       ++i;
4722     }
4723   if((blockSize*numBlocks) > probSize)
4724     {
4725       while((blockSize >1) && ((blockSize*numBlocks) > probSize)) --blockSize;
4726       while((numBlocks >3) && ((blockSize*numBlocks+blockSize) > probSize)) --numBlocks;
4727       if((probSize-1) == numBlocks) numBlocks -= blockSize;
4728       nev = numBlocks-1; //blockSize;
4729       string_t msg = "ATTENTION! LargeMatrix::eigenKrylovSchurSolver. Because the matrix is too small. Only ";
4730       msg += tostring(nev) + " eigenvalues can be retrieved! \n";
4731       warning("free_warning",msg);
4732     }
4733 
4734   // Create parameter list to pass into the solver manager
4735   Parameters pl;
4736   pl.add("Verbosity", (int_t)verbosity);
4737   pl.add("Which", which);
4738   pl.add("Orthogonalization", ortho);
4739   pl.add("Block Size", (int_t)blockSize);
4740   pl.add("Num Blocks", (int_t)numBlocks);
4741   pl.add("Maximum Restarts", (int_t)maxRestarts);
4742   pl.add("Convergence Tolerance", tol);
4743   pl.add("Locking Tolerance", tol/10);
4744   pl.add("In Situ Restarting", insitu);
4745 
4746 //    LargeMatrix<ST>* pcB = 0;
4747   SmartPtr<const OP> A = _smPtrNull, B = _smPtrNull;
4748   if(0 == pB)
4749     {
4750       if(isShift)
4751         {
4752           pl.add("Which", string_t("LM"));
4753           A = new LargeMatrixAdapterInverse<LargeMatrix<ST>,ST>(pA, fac);
4754         }
4755       else
4756         {
4757           if("SM" == which)
4758             {
4759               A = new LargeMatrixAdapterInverse<LargeMatrix<ST>,ST>(pA, fac);
4760               pl.add("Which", string_t("LM"));
4761             }
4762           else
4763             {
4764               A = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pA);
4765             }
4766         }
4767     }
4768   else
4769     {
4770       if(isShift)
4771         {
4772           pl.add("Which", string_t("LM"));
4773           A = new LargeMatrixAdapterInverseGeneralized<LargeMatrix<ST>,ST>(pA, pB, fac);
4774           B = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pB);
4775         }
4776       else
4777         {
4778           if("SM" == which)
4779             {
4780               pl.add("Which", string_t("LM"));
4781               A = new LargeMatrixAdapterInverseGeneralized<LargeMatrix<ST>,ST>(pA, pB, fac);  // A^-1*B*X=lambda*X
4782               B = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pB);
4783             }
4784           else
4785             {
4786               A = new LargeMatrixAdapterInverseGeneralized<LargeMatrix<ST>,ST>(pB, pA, fac);  // B^-1*A*X=lambda*X
4787               B = new LargeMatrixAdapter<LargeMatrix<ST>,ST>(pA);
4788             }
4789         }
4790     }
4791 
4792   SmartPtr<MV> ivec = SmartPtr<MultiVecAdapter<ST> >(new MultiVecAdapter<ST>(pA->nbCols, blockSize));
4793   ivec->mvRandom();
4794 
4795   // Define eigen problem
4796   SmartPtr<EigenProblem<ST,MV,OP> > problem;
4797   if(0 != pB)  problem = SmartPtr<EigenProblem<ST,MV,OP> >(new EigenProblem<ST,MV,OP>(A,B,ivec));
4798   else problem = SmartPtr<EigenProblem<ST,MV,OP> >(new EigenProblem<ST,MV,OP>(A,ivec));
4799 
4800   // Inform the eigenproblem that the operator cK is symmetric or non-symmetric
4801   // By default, it's set to non-symmetric
4802   problem->setHermitian(false);
4803 
4804   // Set the number of eigenvalues requested
4805   problem->setNEV(nev);
4806 
4807   // Inform the eigenproblem that you are done passing it information
4808   bool boolret = problem->setProblem();
4809   if(!boolret) error("eigen_eigenproblem", "");
4810 
4811   BlockKrylovSchurSolMgr<ST,MV,OP> krSolverMan(problem, pl);
4812   ComputationInfo returnCode = krSolverMan.solve();
4813 
4814   number_t numev = 0;
4815   if(_success == returnCode)
4816     {
4817       EigenSolverSolution<ST,MV> sol = problem->getSolution();
4818       SmartPtr<MV> evecs = sol.evecs;
4819       numev = sol.numVecs;
4820       res.resize(numev);
4821       for(number_t i = 0; i<numev; i++)
4822         {
4823           std::vector<complex_t> eVec(ivec->getVecLength());
4824           for(number_t j = 0; j < ivec->getVecLength(); ++j)
4825             {
4826               if(0 == sol.index[i]) eVec[j] = (complex_t(SCT::real((*evecs)(j,i)),0));
4827               else if(1 == sol.index[i]) eVec[j] = (complex_t(SCT::real((*evecs)(j,i)),SCT::real((*evecs)(j,i+1))));
4828               else eVec[i] = (complex_t(SCT::real((*evecs)(j,i-1)),SCT::real((*evecs)(j,i))));
4829             }
4830           res.at(i) = std::make_pair(complex_t(sol.evals[i].realpart,sol.evals[i].imagpart), eVec);
4831         }
4832     }
4833 
4834   return (numev);
4835 }
4836 
4837 } // end of namespace xlifepp
4838 
4839 #endif // LARGE_MATRIX_HPP
4840