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