1 /*
2 XLiFE++ is 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 MatrixEntry.cpp
19 \author E. Lunéville
20 \since 01 nov 2013
21 \date 01 nov 2013
22
23 \brief Implementation of xlifepp::MatrixEntry class member functions and related utilities
24 */
25
26 #include "MatrixEntry.hpp"
27 #include "utils.h"
28 #ifdef XLIFEPP_WITH_UMFPACK
29 #include "umfpackSupport.h"
30 #endif
31 namespace xlifepp
32 {
33
34 //===============================================================================
35 //member functions of MatrixEntry class
36 //===============================================================================
37
38 //constructors
MatrixEntry()39 MatrixEntry::MatrixEntry()
40 {
41 rEntries_p = 0; cEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
42 valueType_ = _real; strucType_ = _scalar; nbOfComponents = dimPair(1, 1);
43 }
44
MatrixEntry(ValueType vt,StrucType st,MatrixStorage * ms_p,dimPair valdim,SymType sy)45 MatrixEntry::MatrixEntry(ValueType vt, StrucType st, MatrixStorage* ms_p, dimPair valdim, SymType sy)
46 {
47 rEntries_p = 0; cEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
48 valueType_ = vt; strucType_ = st; nbOfComponents = valdim;
49
50 if(strucType_ == _scalar && valdim != dimPair(1, 1))
51 {
52 error("matrixentry_incoherent_dim", words("structure", _scalar), valdim.first, valdim.second);
53 }
54 if(strucType_ == _matrix && valdim == dimPair(1, 1))
55 {
56 error("matrixentry_incoherent_dim", words("structure", _matrix), 1, 1);
57 }
58
59 switch(st)
60 {
61 case _scalar :
62 switch(vt)
63 {
64 case _real : rEntries_p = new LargeMatrix<real_t>(ms_p, sy); return;
65 case _complex : cEntries_p = new LargeMatrix<complex_t>(ms_p, sy); return;
66 default : error("matrixentry_abnormal_type", words("value", vt));
67
68 }
69 case _matrix :
70 switch(vt)
71 {
72 case _real : rmEntries_p = new LargeMatrix<Matrix<real_t> >(ms_p, Matrix<real_t>(valdim.first, valdim.second, 0.), sy); return;
73 case _complex : cmEntries_p = new LargeMatrix<Matrix<complex_t> >(ms_p, Matrix<complex_t>(valdim.first, valdim.second, 0.), sy); return;
74 default : error("matrixentry_abnormal_type", words("value", vt));
75 }
76 default : error("matrixentry_novector");
77 }
78 }
79
80 //! construct special matrix (constant diagonal)
MatrixEntry(SpecialMatrix spm,StorageType st,AccessType at,number_t nbr,number_t nbc,const real_t & a)81 MatrixEntry::MatrixEntry(SpecialMatrix spm, StorageType st, AccessType at, number_t nbr, number_t nbc, const real_t& a)
82 {
83 valueType_ = _real; strucType_ = _scalar; nbOfComponents = dimPair(1, 1);
84 cEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
85 rEntries_p=new LargeMatrix<real_t>(spm, st, at , nbr, nbc, a);
86 }
87
MatrixEntry(SpecialMatrix spm,StorageType st,AccessType at,number_t nbr,number_t nbc,const complex_t & a)88 MatrixEntry::MatrixEntry(SpecialMatrix spm, StorageType st, AccessType at, number_t nbr, number_t nbc, const complex_t& a)
89 {
90 valueType_ = _complex; strucType_ = _scalar; nbOfComponents = dimPair(1, 1);
91 rEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
92 cEntries_p=new LargeMatrix<complex_t>(spm, st, at , nbr, nbc, a);
93 }
94
MatrixEntry(SpecialMatrix spm,StorageType st,AccessType at,number_t nbr,number_t nbc,const Matrix<real_t> & a)95 MatrixEntry::MatrixEntry(SpecialMatrix spm, StorageType st, AccessType at, number_t nbr, number_t nbc, const Matrix<real_t>& a)
96 {
97 valueType_ = _real; strucType_ = _matrix; nbOfComponents = dimPair(a.numberOfRows(), a.numberOfColumns());
98 rEntries_p = 0; cEntries_p = 0; cmEntries_p = 0;
99 rmEntries_p=new LargeMatrix<Matrix<real_t> >(spm, st, at , nbr, nbc, a);
100 }
101
MatrixEntry(SpecialMatrix spm,StorageType st,AccessType at,number_t nbr,number_t nbc,const Matrix<complex_t> & a)102 MatrixEntry::MatrixEntry(SpecialMatrix spm, StorageType st, AccessType at, number_t nbr, number_t nbc, const Matrix<complex_t>& a)
103 {
104 valueType_ = _complex; strucType_ = _matrix; nbOfComponents = dimPair(a.numberOfRows(), a.numberOfColumns());
105 rEntries_p = 0; cEntries_p = 0; rmEntries_p = 0;
106 cmEntries_p=new LargeMatrix<Matrix<complex_t> >(spm, st, at , nbr, nbc, a);
107 }
108
109 //copy constructor and assignment operator, it is a full copy !!!
MatrixEntry(const MatrixEntry & mat,bool storageCopy)110 MatrixEntry::MatrixEntry(const MatrixEntry& mat, bool storageCopy)
111 {
112 copy(mat, storageCopy);
113 }
114
operator =(const MatrixEntry & mat)115 MatrixEntry& MatrixEntry::operator=(const MatrixEntry& mat)
116 {
117 clear();
118 copy(mat); //does not copy the storage
119 return *this;
120 }
121
122 // deallocate memory used by a MatrixEntry
clear()123 void MatrixEntry::clear()
124 {
125 if(rEntries_p != 0) delete rEntries_p;
126 if(cEntries_p != 0) delete cEntries_p;
127 if(rmEntries_p != 0) delete rmEntries_p;
128 if(cmEntries_p != 0) delete cmEntries_p;
129 rEntries_p = 0; cEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
130 }
131
132 //copy tool of a MatrixEntry, object has to be clean before
copy(const MatrixEntry & mat,bool storageCopy)133 void MatrixEntry::copy(const MatrixEntry& mat, bool storageCopy)
134 {
135 valueType_ = mat.valueType_;
136 strucType_ = mat.strucType_;
137 nbOfComponents = mat.nbOfComponents;
138 rEntries_p = 0; cEntries_p = 0; rmEntries_p = 0; cmEntries_p = 0;
139 switch(strucType_)
140 {
141 case _scalar :
142 switch(valueType_)
143 {
144 case _real : if(mat.rEntries_p!=0) rEntries_p = new LargeMatrix<real_t>(*mat.rEntries_p, storageCopy); return;
145 case _complex : if(mat.cEntries_p!=0) cEntries_p = new LargeMatrix<complex_t>(*mat.cEntries_p, storageCopy); return;
146 default : error("matrixentry_abnormal_type", words("value", valueType_));
147 }
148 case _matrix :
149 switch(valueType_)
150 {
151 case _real : if(mat.rmEntries_p!=0) rmEntries_p = new LargeMatrix<Matrix<real_t> >(*mat.rmEntries_p, storageCopy); return;
152 case _complex : if(mat.cmEntries_p!=0) cmEntries_p = new LargeMatrix<Matrix<complex_t> >(*mat.cmEntries_p, storageCopy); return;
153 default : error("matrixentry_abnormal_type", words("value", valueType_));
154 }
155 default : error("matrixentry_novector");
156 }
157 }
158
159 //destructor
~MatrixEntry()160 MatrixEntry::~MatrixEntry()
161 {
162 if(rEntries_p != 0) delete rEntries_p;
163 if(cEntries_p != 0) delete cEntries_p;
164 if(rmEntries_p != 0) delete rmEntries_p;
165 if(cmEntries_p != 0) delete cmEntries_p;
166 }
167
168 // print entry
print(std::ostream & out) const169 void MatrixEntry::print(std::ostream& out) const
170 {
171 if(rEntries_p != 0) {rEntries_p->print(out); return;}
172 if(cEntries_p != 0) {cEntries_p->print(out); return;}
173 if(rmEntries_p != 0) {rmEntries_p->print(out); return;}
174 if(cmEntries_p != 0) {cmEntries_p->print(out); return;}
175 out<<" void matrix"<<eol;
176 }
177
178 // return the number of rows
nbOfRows() const179 number_t MatrixEntry::nbOfRows() const
180 {
181 if(rEntries_p != 0) return rEntries_p->nbRows;
182 if(cEntries_p != 0) return cEntries_p->nbRows;
183 if(rmEntries_p != 0) return rmEntries_p->nbRows;
184 if(cmEntries_p != 0) return cmEntries_p->nbRows;
185 return 0;
186 }
187
188 // return the number of columns
nbOfCols() const189 number_t MatrixEntry::nbOfCols() const
190 {
191 if(rEntries_p != 0) return rEntries_p->nbCols;
192 if(cEntries_p != 0) return cEntries_p->nbCols;
193 if(rmEntries_p != 0) return rmEntries_p->nbCols;
194 if(cmEntries_p != 0) return cmEntries_p->nbCols;
195 return 0;
196 }
197
198 // set the number of columns
setNbOfCols(number_t n)199 void MatrixEntry::setNbOfCols(number_t n)
200 {
201 if(rEntries_p != 0) rEntries_p->nbCols=n;
202 if(cEntries_p != 0) cEntries_p->nbCols=n;
203 if(rmEntries_p != 0) rmEntries_p->nbCols=n;
204 if(cmEntries_p != 0) cmEntries_p->nbCols=n;
205 }
206
207 // set the number of rows
setNbOfRows(number_t n)208 void MatrixEntry::setNbOfRows(number_t n)
209 {
210 if(rEntries_p != 0) rEntries_p->nbRows=n;
211 if(cEntries_p != 0) cEntries_p->nbRows=n;
212 if(rmEntries_p != 0) rmEntries_p->nbRows=n;
213 if(cmEntries_p != 0) cmEntries_p->nbRows=n;
214 }
215
216 //storage pointer, storage type and access type
storageType() const217 StorageType MatrixEntry::storageType() const
218 {
219 if(rEntries_p != 0) return rEntries_p->storageType();
220 if(cEntries_p != 0) return cEntries_p->storageType();
221 if(rmEntries_p != 0) return rmEntries_p->storageType();
222 if(cmEntries_p != 0) return cmEntries_p->storageType();
223 return _noStorage;
224 }
225
accessType() const226 AccessType MatrixEntry::accessType() const
227 {
228 if(rEntries_p != 0) return rEntries_p->accessType();
229 if(cEntries_p != 0) return cEntries_p->accessType();
230 if(rmEntries_p != 0) return rmEntries_p->accessType();
231 if(cmEntries_p != 0) return cmEntries_p->accessType();
232 return _noAccess;
233 }
234
storagep() const235 MatrixStorage* MatrixEntry::storagep() const
236 {
237 if(rEntries_p != 0) return rEntries_p->storagep();
238 if(cEntries_p != 0) return cEntries_p->storagep();
239 if(rmEntries_p != 0) return rmEntries_p->storagep();
240 if(cmEntries_p != 0) return cmEntries_p->storagep();
241 return 0;
242 }
243
storagep()244 MatrixStorage* MatrixEntry::storagep()
245 {
246 if(rEntries_p != 0) return rEntries_p->storagep();
247 if(cEntries_p != 0) return cEntries_p->storagep();
248 if(rmEntries_p != 0) return rmEntries_p->storagep();
249 if(cmEntries_p != 0) return cmEntries_p->storagep();
250 return 0;
251 }
252
253
symmetry() const254 SymType MatrixEntry::symmetry() const
255 {
256 if(rEntries_p != 0) return rEntries_p->sym;
257 if(cEntries_p != 0) return cEntries_p->sym;
258 if(rmEntries_p != 0) return rmEntries_p->sym;
259 if(cmEntries_p != 0) return cmEntries_p->sym;
260 return _noSymmetry;
261 }
262
symmetry()263 SymType& MatrixEntry::symmetry()
264 {
265 if(rEntries_p != 0) return rEntries_p->sym;
266 if(cEntries_p != 0) return cEntries_p->sym;
267 if(rmEntries_p != 0) return rmEntries_p->sym;
268 if(cmEntries_p != 0) return cmEntries_p->sym;
269 where("MatrixEntry::symmetry");
270 error("null_pointer","xxEntries_p");
271 return rEntries_p->sym; // dummy return
272 }
273 //! return a reference to LargeMatrix object
274 template <>
getLargeMatrix() const275 LargeMatrix<real_t>& MatrixEntry::getLargeMatrix() const
276 {
277 if (rEntries_p!=0) return *rEntries_p;
278 where("MatrixEntry::getLargeMatrix()");
279 error("null_pointer","rEntries_p");
280 return *rEntries_p; //fake return
281 }
282
283 template <>
getLargeMatrix() const284 LargeMatrix<complex_t>& MatrixEntry::getLargeMatrix() const
285 {
286 if (cEntries_p!=0) return *cEntries_p;
287 where("MatrixEntry::getLargeMatrix()");
288 error("null_pointer","cEntries_p");
289 return *cEntries_p; //fake return
290 }
291
292 template <>
getLargeMatrix() const293 LargeMatrix<Matrix<real_t> >& MatrixEntry::getLargeMatrix() const
294 {
295 if(rmEntries_p!=0) return *rmEntries_p;
296 where("MatrixEntry::getLargeMatrix()");
297 error("null_pointer","rmEntries_p");
298 return *rmEntries_p; //fake return
299 }
300
301 template <>
getLargeMatrix() const302 LargeMatrix<Matrix<complex_t> >& MatrixEntry::getLargeMatrix() const
303 {
304 if(cmEntries_p!=0) return *cmEntries_p;
305 where("MatrixEntry::getLargeMatrix()");
306 error("null_pointer","cmEntries_p");
307 return *cmEntries_p; //fake return
308 }
309
310 // return a row or a col as VectorEntry
311 // rc : row or col index
312 // at : row acces (_row) or col access (_col)
313 // ### only available for scalar MatrixEntry ###
getRowCol(number_t rc,AccessType at) const314 VectorEntry MatrixEntry::getRowCol(number_t rc, AccessType at) const
315 {
316 //get (col/row index, adress) pairs of row/col rc
317 std::vector<std::pair<number_t, number_t> > indadd;
318 number_t n=nbOfRows();
319 if (at==_row) n=nbOfCols();
320 SymType sym=symmetry();
321 if (rEntries_p!=0)
322 {
323 if (at==_row) indadd=rEntries_p->getRow(rc); else indadd=rEntries_p->getCol(rc);
324 VectorEntry v(_real,_scalar, n);
325 std::vector<real_t>::iterator itv=v.rEntries_p->begin();
326 std::vector<std::pair<number_t, number_t> >::iterator itp=indadd.begin();
327 std::vector<real_t>& mat = rEntries_p->values();
328 switch (sym)
329 {
330 case _skewSymmetric:
331 case _skewAdjoint:
332 for (;itp!=indadd.end(); ++itp)
333 {
334 number_t cr = itp->first;
335 if ((at==_row && rc > cr) || (at==_col && rc < cr)) *(itv+(cr-1))= -mat[itp->second];
336 else *(itv+(itp->first-1))=mat[itp->second];
337 }
338 break;
339 default :
340 for (;itp!=indadd.end(); ++itp) *(itv+(itp->first-1))=mat[itp->second];
341 }
342 return v;
343 }
344 if (cEntries_p!=0)
345 {
346 if (at==_row) indadd=rEntries_p->getRow(rc); else indadd=rEntries_p->getCol(rc);
347 VectorEntry v(_complex,_scalar,n);
348 std::vector<complex_t>::iterator itv=v.cEntries_p->begin();
349 std::vector<std::pair<number_t, number_t> >::iterator itp=indadd.begin();
350 std::vector<complex_t>& mat = cEntries_p->values();
351 switch (sym)
352 {
353 case _skewSymmetric:
354 for (;itp!=indadd.end(); ++itp)
355 {
356 number_t cr = itp->first;
357 if ((at==_row && rc > cr) || (at==_col && rc < cr)) *(itv+(cr-1))= -mat[itp->second];
358 else *(itv+(itp->first-1))=mat[itp->second];
359 }
360 break;
361 case _skewAdjoint:
362 for (;itp!=indadd.end(); ++itp)
363 {
364 number_t cr = itp->first;
365 if ((at==_row && rc > cr) || (at==_col && rc < cr)) *(itv+(cr-1))= -conj(mat[itp->second]);
366 else *(itv+(itp->first-1))=mat[itp->second];
367 }
368 break;
369 case _selfAdjoint:
370 for (;itp!=indadd.end(); ++itp)
371 {
372 number_t cr = itp->first;
373 if ((at==_row && rc > cr) || (at==_col && rc < cr)) *(itv+(cr-1))= conj(mat[itp->second]);
374 else *(itv+(itp->first-1))=mat[itp->second];
375 }
376 break;
377 default :
378 for (;itp!=indadd.end(); ++itp) *(itv+(itp->first-1))=mat[itp->second];
379 }
380 return v;
381 }
382 where("MatrixEntry::getRowCol(...)");
383 error("scalar_only");
384 return VectorEntry(_real,_scalar,1); //fake return
385 }
386
factorization() const387 FactorizationType MatrixEntry::factorization() const
388 {
389 if(rEntries_p != 0) return rEntries_p->factorization_;
390 if(cEntries_p != 0) return cEntries_p->factorization_;
391 if(rmEntries_p != 0) return rmEntries_p->factorization_;
392 if(cmEntries_p != 0) return cmEntries_p->factorization_;
393 return _noFactorization;
394 }
395
396 // delete rows r1,..., r2 in matrix (may be expansive)
deleteRows(number_t r1,number_t r2)397 void MatrixEntry::deleteRows(number_t r1, number_t r2)
398 {
399 if(rEntries_p != 0) { rEntries_p->deleteRows(r1,r2); return;}
400 if(cEntries_p != 0) { cEntries_p->deleteRows(r1,r2); return;}
401 if(rmEntries_p != 0) { rmEntries_p->deleteRows(r1,r2); return;}
402 if(cmEntries_p != 0) { cmEntries_p->deleteRows(r1,r2); return;}
403 }
404
405 // delete cols c1,..., c2 in matrix (may be expansive)
deleteCols(number_t c1,number_t c2)406 void MatrixEntry::deleteCols(number_t c1, number_t c2)
407 {
408 if(rEntries_p != 0) { rEntries_p->deleteCols(c1,c2); return;}
409 if(cEntries_p != 0) { cEntries_p->deleteCols(c1,c2); return;}
410 if(rmEntries_p != 0) { rmEntries_p->deleteCols(c1,c2); return;}
411 if(cmEntries_p != 0) { cmEntries_p->deleteCols(c1,c2); return;}
412 }
413
414 //convert matrix storage to skyline storage
toSkyline()415 void MatrixEntry::toSkyline()
416 {
417 if(rEntries_p != 0) {rEntries_p->toSkyline(); return;}
418 if(cEntries_p != 0) {cEntries_p->toSkyline(); return;}
419 if(rmEntries_p != 0) {rmEntries_p->toSkyline(); return;}
420 if(cmEntries_p != 0) {cmEntries_p->toSkyline(); return;}
421 where("MatrixEntry::toSkyline");
422 error("null_pointer", "xxEntries_p");
423 }
424
425 // convert current matrix storage to an other matrix storage
toStorage(MatrixStorage * ms)426 void MatrixEntry::toStorage(MatrixStorage* ms)
427 {
428 if(rEntries_p != 0) {rEntries_p->toStorage(ms); return;}
429 if(cEntries_p != 0) {cEntries_p->toStorage(ms); return;}
430 if(rmEntries_p != 0) {rmEntries_p->toStorage(ms); return;}
431 if(cmEntries_p != 0) {cmEntries_p->toStorage(ms); return;}
432 where("MatrixEntry::toStorage");
433 error("null_pointer", "xxEntries_p");
434 }
435
436 // create new scalar matrix entry from non scalar matrix entry
toScalar()437 MatrixEntry* MatrixEntry::toScalar()
438 {
439 if(nbOfComponents == std::pair<dimen_t,dimen_t>(1,1)) return this; //already scalar, nothing done
440
441 //create new scalar entries
442 MatrixEntry* mat=new MatrixEntry();
443 mat->valueType_=valueType_;
444 mat->strucType_=_scalar;
445 mat->nbOfComponents= std::pair<dimen_t,dimen_t>(1,1);
446 if(rmEntries_p != 0) {mat->rEntries_p=rmEntries_p->toScalar(real_t(0));}
447 if(cmEntries_p != 0) {mat->cEntries_p=cmEntries_p->toScalar(complex_t(0));}
448 return mat;
449 }
450
451 // convert current matrix to unsymmetric representation if it has a symmetric one
toUnsymmetric(AccessType at)452 void MatrixEntry::toUnsymmetric(AccessType at)
453 {
454 if(rEntries_p != 0) {rEntries_p->toUnsymmetric(at); return;}
455 if(cEntries_p != 0) {cEntries_p->toUnsymmetric(at); return;}
456 if(rmEntries_p != 0) {rmEntries_p->toUnsymmetric(at); return;}
457 if(cmEntries_p != 0) {cmEntries_p->toUnsymmetric(at); return;}
458 where("MatrixEntry::toUnsymmetric");
459 error("null_pointer", "xxEntries_p");
460 }
461
462 // change real entries to complex entries : rEntries-> cEntries or rmEntries -> cmEntries
463 // nothing done when MatrixEntry is a complex one
toComplex()464 MatrixEntry& MatrixEntry::toComplex()
465 {
466 if(rEntries_p!=0)
467 {
468 cEntries_p= new LargeMatrix<complex_t>(rEntries_p->storagep(), complex_t(0), rEntries_p->sym);
469 std::vector<real_t>::iterator itr=rEntries_p->values().begin();
470 std::vector<complex_t>::iterator itc=cEntries_p->values().begin();
471 for(; itr!=rEntries_p->values().end(); ++itr, ++itc) *itc= complex_t(*itr);
472 delete rEntries_p;
473 rEntries_p=0;
474 }
475 if(rmEntries_p!=0)
476 {
477 cmEntries_p= new LargeMatrix<Matrix<complex_t> >(rmEntries_p->storagep(), Matrix<complex_t>(0), rmEntries_p->sym);
478 std::vector<Matrix<real_t> >::iterator itr=rmEntries_p->values().begin();
479 std::vector<Matrix<complex_t> >::iterator itc=cmEntries_p->values().begin();
480 for(; itr!=rmEntries_p->values().end(); ++itr, ++itc) *itc= cmplx(*itr);
481 delete rmEntries_p;
482 rmEntries_p=0;
483 }
484 valueType_=_complex;
485 return *this;
486 }
487
488 // change complex entries to real entries : cEntries-> rEntries or cmEntries -> rmEntries
489 // if realPart is true take real parts else take imag parts
490 // nothing done when MatrixEntry is a real one
toReal(bool realPart)491 MatrixEntry& MatrixEntry::toReal(bool realPart)
492 {
493 if(cEntries_p!=0)
494 {
495 SymType sy = cEntries_p->sym;
496 if(sy==_selfAdjoint) sy=_symmetric;
497 if(sy==_skewAdjoint) sy=_skewSymmetric;
498 rEntries_p= new LargeMatrix<real_t>(cEntries_p->storagep(), 0., sy);
499 std::vector<complex_t>::iterator itc=cEntries_p->values().begin();
500 std::vector<real_t>::iterator itr=rEntries_p->values().begin();
501 if(realPart)
502 for(; itc!=cEntries_p->values().end(); ++itr, ++itc) *itr= itc->real();
503 else
504 for(; itc!=cEntries_p->values().end(); ++itr, ++itc) *itr= itc->imag();
505 delete cEntries_p;
506 cEntries_p=0;
507 }
508 if(cmEntries_p!=0)
509 {
510 SymType sy = cmEntries_p->sym;
511 if(sy==_selfAdjoint) sy=_symmetric;
512 if(sy==_skewAdjoint) sy=_skewSymmetric;
513 rmEntries_p= new LargeMatrix<Matrix<real_t> >(cmEntries_p->storagep(), Matrix<real_t>(0), sy);
514 std::vector<Matrix<real_t> >::iterator itr=rmEntries_p->values().begin();
515 std::vector<Matrix<complex_t> >::iterator itc=cmEntries_p->values().begin();
516 if(realPart)
517 for(; itc!=cmEntries_p->values().end(); ++itr, ++itc) *itr= itc->real();
518 else
519 for(; itc!=cmEntries_p->values().end(); ++itr, ++itc) *itr= itc->imag();
520 delete cmEntries_p;
521 cmEntries_p=0;
522 }
523 valueType_=_real;
524 return *this;
525 }
526
527 // change entries to conjugate entries if entries are not real
528 // nothing done when MatrixEntry is a real one
toConj()529 MatrixEntry& MatrixEntry::toConj()
530 {
531 if(cEntries_p!=0) cEntries_p->toConj();
532 if(cmEntries_p!=0) cmEntries_p->toConj();
533 return *this;
534 }
535
536 // test if all non diagonal coefficients are zero
isDiagonal() const537 bool MatrixEntry::isDiagonal() const
538 {
539 if(rEntries_p != 0) return rEntries_p->isDiagonal();
540 if(cEntries_p != 0) return cEntries_p->isDiagonal();
541 if(rmEntries_p != 0) return rmEntries_p->isDiagonal();
542 if(cmEntries_p != 0) return cmEntries_p->isDiagonal();
543 return true;
544 }
545
546 // test if all non diagonal coefficients are zero and diagonal coefficients are almost 1
isId(const double & tol) const547 bool MatrixEntry::isId(const double & tol) const
548 {
549 if(rEntries_p != 0) return rEntries_p->isId(tol);
550 if(cEntries_p != 0) return cEntries_p->isId(tol);
551 if(rmEntries_p != 0) return rmEntries_p->isId(tol);
552 if(cmEntries_p != 0) return cmEntries_p->isId(tol);
553 return true;
554 }
555
556 // round to zero all coefficients close to 0 (|.| < aszero)
roundToZero(real_t asZero)557 void MatrixEntry::roundToZero(real_t asZero)
558 {
559 if(rEntries_p != 0) { rEntries_p->roundToZero(asZero); return; }
560 if(cEntries_p != 0) { cEntries_p->roundToZero(asZero); return; }
561 if(rmEntries_p != 0) { rmEntries_p->roundToZero(asZero); return; }
562 if(cmEntries_p != 0) { cmEntries_p->roundToZero(asZero); return; }
563 }
564
565 //! set cols or rows to 0 (index start from 1)
setColToZero(number_t c1,number_t c2)566 void MatrixEntry::setColToZero(number_t c1, number_t c2)
567 {
568 if(rEntries_p != 0) rEntries_p->setColToZero(c1,c2);
569 if(cEntries_p != 0) cEntries_p->setColToZero(c1,c2);
570 if(rmEntries_p != 0) rmEntries_p->setColToZero(c1,c2);
571 if(cmEntries_p != 0) cmEntries_p->setColToZero(c1,c2);
572 }
setRowToZero(number_t r1,number_t r2)573 void MatrixEntry::setRowToZero(number_t r1, number_t r2)
574 {
575 if(rEntries_p != 0) rEntries_p->setRowToZero(r1,r2);
576 if(cEntries_p != 0) cEntries_p->setRowToZero(r1,r2);
577 if(rmEntries_p != 0) rmEntries_p->setRowToZero(r1,r2);
578 if(cmEntries_p != 0) cmEntries_p->setRowToZero(r1,r2);
579 }
580
581 /*! change matrix entry representation : from current representation to matrix of nbr x nbc matrices
582 rowPos : list of row indexes to be moved, nbr = rowPos.size
583 colPos : list of col indexes to be moved, nbc = colPos.size
584 for instance [0 0]
585 rowPos=[ 0 2 0], colPos=[1 2] means to move from representation [x y] to [x y]
586 [0 0]
587 [0 0 x]
588 rowPos=[ 1 0 0], colPos=[0 0 3] means to move from representation [x] to [0 0 0]
589 [0 0 0]
590 Note : rowPos and colPos has to be consistent with current representation (not checked here)
591
592 */
toMatrix(const std::vector<dimen_t> & rowPos,const std::vector<dimen_t> & colPos)593 void MatrixEntry::toMatrix(const std::vector<dimen_t>& rowPos, const std::vector<dimen_t>& colPos)
594 {
595 dimen_t nbr=rowPos.size(), nbc=colPos.size();
596 if(nbr==1 && nbc==1) return; //nothing is done (no 1 x 1 matrices)
597 dimPair dims(nbr, nbc);
598 if(nbOfComponents==dims) return; //same representation
599
600 if(rEntries_p!=0 || cEntries_p!=0) //current is a matrix of real scalar
601 {
602 dimen_t r=nbr, c=nbc, k=0;
603 while(k<nbr) {if(rowPos[k]>0) {r=k; k=nbr;} else k++;}
604 k=0;
605 while(k<nbc) {if(colPos[k]>0) {c=k; k=nbc;} else k++;}
606 if(r==nbr || c==nbc) return; //nothing is done, rowPos or colPos is null
607 r++, c++;
608 if(rEntries_p!=0)
609 {
610 Matrix<real_t> mat(nbr, nbc, 0.);
611 rmEntries_p = new LargeMatrix<Matrix<real_t> >(rEntries_p->storagep(),mat,rEntries_p->sym);
612 std::vector<real_t>::iterator it=rEntries_p->values().begin();
613 std::vector<Matrix<real_t> >::iterator itm=rmEntries_p->values().begin();
614 for(; it!=rEntries_p->values().end(); it++, itm++)
615 {
616 mat(r,c)=*it;
617 *itm = mat;
618 }
619 delete rEntries_p;
620 rEntries_p=0;
621 strucType_=_matrix;
622 nbOfComponents=dims;
623 return;
624 }
625 else
626 {
627 Matrix<complex_t> mat(nbr, nbc, 0.);
628 cmEntries_p = new LargeMatrix<Matrix<complex_t> >(cEntries_p->storagep(),mat,cEntries_p->sym);
629 std::vector<complex_t>::iterator it=cEntries_p->values().begin();
630 std::vector<Matrix<complex_t> >::iterator itm=cmEntries_p->values().begin();
631 for(; it!=cEntries_p->values().end(); it++, itm++)
632 {
633 mat(r,c)=*it;
634 *itm = mat;
635 }
636 delete cEntries_p;
637 cEntries_p=0;
638 strucType_=_matrix;
639 nbOfComponents=dims;
640 return;
641 }
642 }
643
644 //current entry is matrix of matrices
645 std::vector<dimen_t>::const_iterator itr, itc;
646 if(rmEntries_p!=0)
647 {
648 Matrix<real_t> mat(nbr, nbc, 0.);
649 std::vector<Matrix<real_t> >::iterator it=rmEntries_p->values().begin();
650 for(; it!=rmEntries_p->values().end(); it++)
651 {
652 Matrix<real_t>::iterator itv=it->begin();
653 for(dimen_t r=0; r<nbr; r++)
654 {
655 dimen_t i=rowPos[r];
656 if(i!=0)
657 for(dimen_t c=0; c<nbc; c++)
658 {
659 dimen_t j=colPos[c];
660 if(j!=0) { mat(i,j)=*itv; itv++;}
661 }
662 }
663 *it = mat;
664 }
665 nbOfComponents=dims;
666 return;
667 }
668 if(cmEntries_p!=0)
669 {
670 Matrix<complex_t> mat(nbr, nbc, 0.);
671 std::vector<Matrix<complex_t> >::iterator it=cmEntries_p->values().begin();
672 for(; it!=cmEntries_p->values().end(); it++)
673 {
674 Matrix<complex_t>::iterator itv=it->begin();
675 for(dimen_t r=0; r<nbr; r++)
676 {
677 dimen_t i=rowPos[r];
678 if(i!=0)
679 for(dimen_t c=0; c<nbc; c++)
680 {
681 dimen_t j=colPos[c];
682 if(j!=0) { mat(i,j)=*itv; itv++;}
683 }
684 }
685 *it = mat;
686 }
687 nbOfComponents=dims;
688 return;
689 }
690 }
691
692 /*!assign MatrixEntry m to current MatrixEntry
693 num_r : row dof numbers of MatrixEntry m related to current MatrixEntry
694 num_c : col dof numbers of MatrixEntry m related to current MatrixEntry
695 if num_r (resp. num_c) is void, it means that the row (resp. col) dof numbers of MatrixEntry m is the same as current MatrixEntry
696 */
assign(const MatrixEntry & m,const std::vector<number_t> & num_r,const std::vector<number_t> & num_c)697 void MatrixEntry::assign(const MatrixEntry& m, const std::vector<number_t>& num_r, const std::vector<number_t>& num_c)
698 {
699 if(m.valueType_ == _real && valueType_ == _real) //real case
700 {
701 if(rEntries_p != 0)
702 {
703 if(m.rEntries_p != 0) {rEntries_p->assign(*m.rEntries_p, num_r, num_c); return;}
704 where("MatrixEntry::assign");
705 error("entry_inconsistent_structures");
706 }
707 if(rmEntries_p != 0)
708 {
709 if(m.rmEntries_p != 0) {rmEntries_p->assign(*m.rmEntries_p, num_r, num_c); return;}
710 where("MatrixEntry::assign");
711 error("entry_inconsistent_structures");
712 }
713 where("MatrixEntry::assign");
714 error("null_pointer", "real Entries_p");
715 }
716
717 //complex case
718 if(cEntries_p != 0)
719 {
720 if(m.rEntries_p != 0) {cEntries_p->assign(*m.rEntries_p, num_r, num_c); return;}
721 if(m.cEntries_p != 0) {cEntries_p->assign(*m.cEntries_p, num_r, num_c); return;}
722 where("MatrixEntry::assign");
723 error("entry_inconsistent_structures");
724 }
725 if(cmEntries_p != 0)
726 {
727 if(m.rmEntries_p != 0) {cmEntries_p->assign(*m.rmEntries_p, num_r, num_c); return;}
728 if(m.cmEntries_p != 0) {cmEntries_p->assign(*m.cmEntries_p, num_r, num_c); return;}
729 where("MatrixEntry::assign");
730 error("entry_inconsistent_structures");
731 }
732 where("MatrixEntry::assign");
733 error("null_pointer", "complex Entries_p");
734 }
735
736
737
738 /*--------------------------------------------------------------------------------------------------------------------
739 in/out operations
740 --------------------------------------------------------------------------------------------------------------------*/
741
742 // print entry
viewStorage(std::ostream & out) const743 void MatrixEntry::viewStorage(std::ostream& out) const
744 {
745 if(rEntries_p != 0) rEntries_p->viewStorage(out);
746 if(cEntries_p != 0) cEntries_p->viewStorage(out);
747 if(rmEntries_p != 0) rmEntries_p->viewStorage(out);
748 if(cmEntries_p != 0) cmEntries_p->viewStorage(out);
749 }
750
751 // save matrix entries to file (dense or Matlab format)
saveToFile(const string_t & fn,StorageType st,bool encode) const752 void MatrixEntry::saveToFile(const string_t& fn, StorageType st, bool encode) const
753 {
754 if(rEntries_p != 0) rEntries_p->saveToFile(fn, st, encode);
755 if(cEntries_p != 0) cEntries_p->saveToFile(fn, st, encode);
756 if(rmEntries_p != 0) rmEntries_p->saveToFile(fn, st, encode);
757 if(cmEntries_p != 0) cmEntries_p->saveToFile(fn, st, encode);
758 }
759
760 /*--------------------------------------------------------------------------------------------------------------------
761 algebraic operations
762 --------------------------------------------------------------------------------------------------------------------*/
operator *=(const real_t & r)763 MatrixEntry& MatrixEntry::operator*=(const real_t& r)
764 {
765 if(rEntries_p != 0) *rEntries_p *= r;
766 if(cEntries_p != 0) *cEntries_p *= r;
767 if(rmEntries_p != 0) *rmEntries_p *= r;
768 if(cmEntries_p != 0) *cmEntries_p *= r;
769 return *this;
770 }
771
operator *=(const complex_t & c)772 MatrixEntry& MatrixEntry::operator*=(const complex_t& c)
773 {
774 if(rEntries_p != 0)
775 {
776 cEntries_p = new LargeMatrix<complex_t>(*rEntries_p);
777 delete rEntries_p;
778 rEntries_p=0;
779 }
780 if(cEntries_p != 0) *cEntries_p *= c;
781 if(rmEntries_p != 0)
782 {
783 cmEntries_p = new LargeMatrix<Matrix<complex_t> >(*rmEntries_p);
784 delete rmEntries_p;
785 rmEntries_p=0;
786 }
787 if(cmEntries_p != 0) *cmEntries_p *= c;
788 valueType_=_complex;
789 return *this;
790 }
791
operator /=(const real_t & r)792 MatrixEntry& MatrixEntry::operator/=(const real_t& r)
793 {
794 return (*this) *= (1. / r);
795 }
796
operator /=(const complex_t & c)797 MatrixEntry& MatrixEntry::operator/=(const complex_t& c)
798 {
799 return (*this) *= (1. / c);
800 }
801
802 //+= and -= operation for same storage ans same structure !!!
operator +=(const MatrixEntry & m)803 MatrixEntry& MatrixEntry::operator+=(const MatrixEntry& m)
804 {
805 if(strucType_ != m.strucType_)
806 {
807 where("MatrixEntry::operator+=");
808 error("entry_mismatch_structures", words("structure",strucType_), words("structure", m.strucType_));
809 }
810 if(storagep() != m.storagep())
811 {
812 where("MatrixEntry::operator+=");
813 error("matrixentry_mismatch_storages");
814 }
815
816 if(rEntries_p != 0) //current is a scalar matrix
817 {
818 if(m.rEntries_p != 0) {*rEntries_p += *m.rEntries_p; return *this;}
819 if(m.cEntries_p != 0) //add a complex matrix to a real one
820 {
821 //copy rEntries_p to cEntries_p
822 cEntries_p = new LargeMatrix<complex_t>(*rEntries_p);
823 delete rEntries_p;
824 rEntries_p=0;
825 }
826 }
827 if(cEntries_p != 0 && m.cEntries_p != 0) {*cEntries_p += *m.cEntries_p; return *this;}
828 if(rmEntries_p != 0) //current is a scalar matrix
829 {
830 if(m.rmEntries_p != 0) {*rmEntries_p += *m.rmEntries_p; return *this;}
831 if(m.cmEntries_p != 0) //add a complex matrix to a real one
832 {
833 //copy rEntries_p to cEntries_p
834 cmEntries_p = new LargeMatrix<Matrix<complex_t> >(*rmEntries_p);
835 delete rmEntries_p;
836 rmEntries_p=0;
837 }
838 }
839 if(cmEntries_p != 0 && m.cmEntries_p != 0) {*cmEntries_p += *m.cmEntries_p;}
840 return *this;
841 }
842
operator -=(const MatrixEntry & m)843 MatrixEntry& MatrixEntry::operator-=(const MatrixEntry& m)
844 {
845 if(strucType_ != m.strucType_)
846 {
847 where("MatrixEntry::operator-=");
848 error("entry_mismatch_structures", words("structure",strucType_), words("structure", m.strucType_));
849 }
850 if(storagep() != m.storagep())
851 {
852 where("MatrixEntry::operator-=");
853 error("matrixentry_mismatch_storages");
854 }
855
856 if(rEntries_p != 0) //current is a scalar matrix
857 {
858 if(m.rEntries_p != 0) {*rEntries_p -= *m.rEntries_p; return *this;}
859 if(m.cEntries_p != 0) //add a complex matrix to a real one
860 {
861 //copy rEntries_p to cEntries_p
862 cEntries_p = new LargeMatrix<complex_t>(*rEntries_p);
863 delete rEntries_p;
864 rEntries_p=0;
865 }
866 }
867 if(cEntries_p != 0 && m.cEntries_p != 0) {*cEntries_p -= *m.cEntries_p; return *this;}
868 if(rmEntries_p != 0) //current is a scalar matrix
869 {
870 if(m.rmEntries_p != 0) {*rmEntries_p -= *m.rmEntries_p; return *this;}
871 if(m.cmEntries_p != 0) //add a complex matrix to a real one
872 {
873 //copy rEntries_p to cEntries_p
874 cmEntries_p = new LargeMatrix<Matrix<complex_t> >(*rmEntries_p);
875 delete rmEntries_p;
876 rmEntries_p=0;
877 }
878 }
879 if(cmEntries_p != 0 && m.cmEntries_p != 0) {*cmEntries_p -= *m.cmEntries_p;}
880 return *this;
881 }
882
883 /*!
884 add MatrixEntry m to current MatrixEntry with scalar multiplication
885 num_r : row dof numbers of MatrixEntry m related to current MatrixEntry
886 num_c : col dof numbers of MatrixEntry m related to current MatrixEntry
887 if num_r (resp. num_c) is void, it means that the row (resp. col) dof numbers of MatrixEntry m is the same as current MatrixEntry
888 */
889
add(const MatrixEntry & m,const std::vector<number_t> & num_r,const std::vector<number_t> & num_c,complex_t a)890 void MatrixEntry::add(const MatrixEntry& m, const std::vector<number_t>& num_r, const std::vector<number_t>& num_c, complex_t a)
891 {
892 if(a.imag() == 0 && m.valueType_ == _real && valueType_ == _real) //real case
893 {
894 if(rEntries_p != 0)
895 {
896 if(m.rEntries_p != 0) {rEntries_p->add(*m.rEntries_p, num_r, num_c, a.real()); return;}
897 where("MatrixEntry::add");
898 error("entry_inconsistent_structures");
899 }
900 if(rmEntries_p != 0)
901 {
902 if(m.rmEntries_p != 0) {rmEntries_p->add(*m.rmEntries_p, num_r, num_c, a.real()); return;}
903 where("MatrixEntry::add");
904 error("entry_inconsistent_structures");
905 }
906 where("MatrixEntry::add");
907 error("null_pointer", "real Entries_p");
908 }
909
910 //complex case
911 if(cEntries_p != 0)
912 {
913 if(m.rEntries_p != 0) {cEntries_p->add(*m.rEntries_p, num_r, num_c, a); return;}
914 if(m.cEntries_p != 0) {cEntries_p->add(*m.cEntries_p, num_r, num_c, a); return;}
915 where("MatrixEntry::add");
916 error("entry_inconsistent_structures");
917 }
918 if(cmEntries_p != 0)
919 {
920 if(m.rmEntries_p != 0) {cmEntries_p->add(*m.rmEntries_p, num_r, num_c, a); return;}
921 if(m.cmEntries_p != 0) {cmEntries_p->add(*m.cmEntries_p, num_r, num_c, a); return;}
922 where("MatrixEntry::add");
923 error("entry_inconsistent_structures");
924 }
925 where("MatrixEntry::add");
926 error("null_pointer", "complex Entries_p");
927 }
928
929 //add entries (itb to ite) to current MatrixEntry (has to be consistent, no check)
930 template<typename iterator>
add(iterator & itb,iterator & ite)931 void MatrixEntry::add(iterator& itb, iterator& ite)
932 {
933 if(rEntries_p != 0) {rEntries_p->add(itb,ite); return;}
934 if(rmEntries_p != 0) {rmEntries_p->add(itb,ite); return;}
935 if(cEntries_p != 0) {cEntries_p->add(itb,ite); return;}
936 if(cmEntries_p != 0) {cmEntries_p->add(itb,ite); return;}
937 }
938
939 /*! combine cols of matrix : c2 = c2 + a *c1 (indices start from 1)
940 if updatestorage is true, the storage is dynamically updated (very expansive operation !!!)
941 */
addColToCol(number_t c1,number_t c2,complex_t a,bool updateStorage)942 void MatrixEntry::addColToCol(number_t c1, number_t c2, complex_t a, bool updateStorage)
943 {
944 if(a==complex_t(0)) return; //nothing to add
945 if(c1<1 || c1>nbOfCols() || c2<1 || c2>nbOfCols()) return; //index out of bounds
946
947 if(rEntries_p != 0) {rEntries_p->addColToCol(c1,c2,a.real(), updateStorage); return;}
948 if(rmEntries_p != 0) {rmEntries_p->addColToCol(c1,c2,a.real(), updateStorage); return;}
949 if(cEntries_p != 0) {cEntries_p->addColToCol(c1,c2,a, updateStorage); return;}
950 if(cmEntries_p != 0) {cmEntries_p->addColToCol(c1,c2,a, updateStorage); return;}
951 }
952
953 /*! combine rows of matrix : r2 = rc2 + a *r1 (indices start from 1)
954 if updatestorage is true, the storage is dynamically updated (very expansive operation !!!)
955 */
addRowToRow(number_t r1,number_t r2,complex_t a,bool updateStorage)956 void MatrixEntry::addRowToRow(number_t r1, number_t r2, complex_t a, bool updateStorage)
957 {
958 if(a==complex_t(0)) return; //nothing to add
959 if(r1<1 || r1>nbOfRows() || r2<1 || r2>nbOfRows()) return; //index out of bounds
960
961 if(rEntries_p != 0) {rEntries_p->addRowToRow(r1,r2,a.real(), updateStorage); return;}
962 if(rmEntries_p != 0) {rmEntries_p->addRowToRow(r1,r2,a.real(), updateStorage); return;}
963 if(cEntries_p != 0) {cEntries_p->addRowToRow(r1,r2,a, updateStorage); return;}
964 if(cmEntries_p != 0) {cmEntries_p->addRowToRow(r1,r2,a, updateStorage); return;}
965 }
966
967 /*! copy in current matrix values of mat located at mat_adrs at position cur_adrs
968 it is assumed that mat and current matrix are consistent
969 in structure type scalar/scalar or matrix/matrix
970 in value type real/real or complex/complex
971 if not do conversion before
972 it is also assumed that mat_adrs and cur_adrs have the same size (addresses map!)
973 */
copyVal(const MatrixEntry & mat,const std::vector<number_t> & mat_adrs,const std::vector<number_t> & cur_adrs)974 void MatrixEntry::copyVal(const MatrixEntry& mat, const std::vector<number_t>& mat_adrs,const std::vector<number_t>& cur_adrs)
975 {
976 if (rEntries_p != 0 && mat.rEntries_p!=0) {rEntries_p->copyVal(*mat.rEntries_p, mat_adrs, cur_adrs); return;}
977 if (cEntries_p != 0 && mat.cEntries_p!=0) {cEntries_p->copyVal(*mat.cEntries_p, mat_adrs, cur_adrs); return;}
978 if (rmEntries_p != 0 && mat.rmEntries_p!=0) {rmEntries_p->copyVal(*mat.rmEntries_p, mat_adrs, cur_adrs); return;}
979 if (cmEntries_p != 0 && mat.cmEntries_p!=0) {cmEntries_p->copyVal(*mat.cmEntries_p, mat_adrs, cur_adrs); return;}
980 where("MatrixEntry::copyVal");
981 error("entry_inconsistent_structures");
982 }
983
984
985 /*! partial norm of column c, only components in range [r1,r2], say
986 sqrt( sum_{r1 <= r <= r2} Mrc^2 )
987 */
partialNormOfCol(number_t c,number_t r1,number_t r2) const988 real_t MatrixEntry::partialNormOfCol(number_t c, number_t r1, number_t r2) const
989 {
990 if(rEntries_p != 0) return rEntries_p->partialNormOfCol(c,r1,r2);
991 if(rmEntries_p != 0) return rmEntries_p->partialNormOfCol(c,r1,r2);
992 if(cEntries_p != 0) return cEntries_p->partialNormOfCol(c,r1,r2);
993 if(cmEntries_p != 0) return cmEntries_p->partialNormOfCol(c,r1,r2);
994 return 0.;
995 }
996
997 // Frobenius norm
norm2() const998 real_t MatrixEntry::norm2() const
999 {
1000 if(rEntries_p != 0) return rEntries_p->norm2();
1001 if(rmEntries_p != 0) return rmEntries_p->norm2();
1002 if(cEntries_p != 0) return cEntries_p->norm2();
1003 if(cmEntries_p != 0) return cmEntries_p->norm2();
1004 return 0.;
1005 }
1006
1007 // infinite norm
norminfty() const1008 real_t MatrixEntry::norminfty() const
1009 {
1010 if(rEntries_p != 0) return rEntries_p->norminfty();
1011 if(rmEntries_p != 0) return rmEntries_p->norminfty();
1012 if(cEntries_p != 0) return cEntries_p->norminfty();
1013 if(cmEntries_p != 0) return cmEntries_p->norminfty();
1014 return 0.;
1015 }
1016
1017 // product of MatrixEntry
operator *(const MatrixEntry & mA,const MatrixEntry & mB)1018 MatrixEntry operator*(const MatrixEntry& mA,const MatrixEntry& mB)
1019 {
1020 if(mA.nbOfCols()!= mB.nbOfRows() || mA.nbOfComponents.second != mB.nbOfComponents.first)
1021 {
1022 where("MatrixEntry * MatrixEntry");
1023 error("entry_inconsistent_structures");
1024 }
1025 ValueType vt=_real;
1026 if(mA.valueType_==_complex || mB.valueType_==_complex) vt=_complex;
1027 StrucType st=_scalar;
1028 dimen_t nbrs=mA.nbOfComponents.first, nbcs=mB.nbOfComponents.second;
1029 if(nbrs!=1 || nbcs!=1) st=_matrix;
1030 MatrixEntry mR(vt,st,0,dimPair(nbrs,nbcs),_noSymmetry);
1031
1032 switch(st)
1033 {
1034 case _scalar :
1035 switch(vt)
1036 {
1037 case _real : mR.rEntries_p = new LargeMatrix<real_t>(0,_noSymmetry);
1038 multMatrixMatrix<real_t, real_t, real_t>(*mA.rEntries_p,*mB.rEntries_p, *mR.rEntries_p);
1039 return mR;
1040 case _complex :
1041 {
1042 if(mA.rEntries_p!=0)
1043 {
1044 mR.cEntries_p = new LargeMatrix<complex_t>(0,_noSymmetry);
1045 multMatrixMatrix<real_t, complex_t, complex_t>(*mA.rEntries_p, *mB.cEntries_p, *mR.cEntries_p);
1046 return mR;
1047 }
1048 if(mB.rEntries_p!=0)
1049 {
1050 mR.cEntries_p = new LargeMatrix<complex_t>(0,_noSymmetry);
1051 multMatrixMatrix<complex_t, real_t, complex_t>(*mA.cEntries_p, *mB.rEntries_p, *mR.cEntries_p);
1052 return mR;
1053 }
1054 else
1055 {
1056 mR.cEntries_p = new LargeMatrix<complex_t>(0,_noSymmetry);
1057 multMatrixMatrix<complex_t,complex_t, complex_t>(*mA.cEntries_p, *mB.cEntries_p, *mR.cEntries_p);
1058 return mR;
1059 }
1060 }
1061 default : error("matrixentry_abnormal_type", words("value", vt));
1062 }
1063 // case _matrix :
1064 // switch(vt)
1065 // {
1066 // case _real :
1067 // {
1068 // mR.rmEntries_p = new LargeMatrix<Matrix<real_t> >(0, dimPair(nbrs,nbcs),_noSymmetry);
1069 // multMatrixMatrix<Matrix<real_t>,Matrix<real_t>,Matrix<real_t> >(*mA.rmEntries_p, *mB.rmEntries_p, *mR.rmEntries_p);
1070 // return mR;
1071 // }
1072 // case _complex :
1073 // {
1074 // if(mA.rmEntries_p!=0)
1075 // {
1076 // mR.cmEntries_p = new LargeMatrix<Matrix<complex_t> >(0, dimPair(nbrs,nbcs),_noSymmetry);
1077 // multMatrixMatrix<Matrix<real_t>,Matrix<complex_t>,Matrix<complex_t> >(*mA.rmEntries_p, *mB.cmEntries_p, *mR.cmEntries_p);
1078 // return mR;
1079 // }
1080 // if(mB.rmEntries_p!=0)
1081 // {
1082 // mR.cmEntries_p = new LargeMatrix<Matrix<complex_t> >(0, dimPair(nbrs,nbcs),_noSymmetry);
1083 // multMatrixMatrix<Matrix<complex_t>,Matrix<real_t>,Matrix<complex_t> >(*mA.cmEntries_p, *mB.rmEntries_p, *mR.cmEntries_p);
1084 // return mR;
1085 // }
1086 // else
1087 // {
1088 // mR.cmEntries_p = new LargeMatrix<Matrix<complex_t> >(0, dimPair(nbrs,nbcs),_noSymmetry);
1089 // multMatrixMatrix<Matrix<complex_t>,Matrix<complex_t>,Matrix<complex_t> >(*mA.cmEntries_p, *mB.cmEntries_p, *mR.cmEntries_p);
1090 // return mR;
1091 // }
1092 // }
1093 // default : error("matrixentry_abnormal_type", words("value", vt));
1094 // }
1095 default : error("matrixentry_abnormal_type", words("structure", st));
1096 }
1097
1098 return mR;
1099 }
1100
1101 //! return the conjugate of a matrix entry
conj(const MatrixEntry & me)1102 MatrixEntry conj(const MatrixEntry & me)
1103 {
1104 if(me.rEntries_p != 0 || me.rmEntries_p != 0) {return me;}
1105 MatrixEntry mecj=me;
1106 if(mecj.cEntries_p!=0) mecj.cEntries_p->toConj();
1107 if(mecj.cmEntries_p!=0) mecj.cmEntries_p->toConj();
1108 return mecj;
1109 }
1110
1111 /*--------------------------------------------------------------------------------------------------------------------
1112 factorization operations
1113 --------------------------------------------------------------------------------------------------------------------*/
1114 //factorize matrix entry as LU,
luFactorize(bool withPermutation)1115 void MatrixEntry::luFactorize(bool withPermutation)
1116 {
1117 if(rEntries_p != 0) {rEntries_p->luFactorize(withPermutation); return;}
1118 if(cEntries_p != 0) {cEntries_p->luFactorize(withPermutation); return;}
1119 if(rmEntries_p != 0)
1120 {
1121 where("MatrixEntry::luFactorize");
1122 error("matrixentry_matrixofmatrices_not_handled");
1123 }
1124 if(cmEntries_p != 0)
1125 {
1126 where("MatrixEntry::luFactorize");
1127 error("matrixentry_matrixofmatrices_not_handled");
1128 }
1129 where("MatrixEntry::luFactorize");
1130 error("null_pointer", "xxEntries_p");
1131 }
1132 //factorize matrix entry as LDLt,
ldltFactorize()1133 void MatrixEntry::ldltFactorize()
1134 {
1135 if(rEntries_p != 0) {rEntries_p->ldltFactorize(); return;}
1136 if(cEntries_p != 0) {cEntries_p->ldltFactorize(); return;}
1137 if(rmEntries_p != 0)
1138 {
1139 where("MatrixEntry::ldltFactorize");
1140 error("matrixentry_matrixofmatrices_not_handled");
1141 }
1142 if(cmEntries_p != 0)
1143 {
1144 where("MatrixEntry::ldltFactorize");
1145 error("matrixentry_matrixofmatrices_not_handled");
1146 }
1147 where("MatrixEntry::ldltFactorize");
1148 error("null_pointer", "xxEntries_p");
1149 }
1150
1151 //factorize matrix entry as LDLt,
ldlstarFactorize()1152 void MatrixEntry::ldlstarFactorize()
1153 {
1154 if(rEntries_p != 0) {rEntries_p->ldlstarFactorize(); return;}
1155 if(cEntries_p != 0) {cEntries_p->ldlstarFactorize(); return;}
1156 if(rmEntries_p != 0)
1157 {
1158 where("MatrixEntry::ldlstarFactorize");
1159 error("matrixentry_matrixofmatrices_not_handled");
1160 }
1161 if(cmEntries_p != 0)
1162 {
1163 where("MatrixEntry::ldlstarFactorize");
1164 error("matrixentry_matrixofmatrices_not_handled");
1165 }
1166 where("MatrixEntry::ldlstarFactorize");
1167 error("null_pointer", "xxEntries_p");
1168 }
1169
1170
1171 //incomplete factorization operations
1172 //incomplete factorize matrix entry as LU,
iluFactorize()1173 void MatrixEntry::iluFactorize()
1174 {
1175 if(rEntries_p != 0) {rEntries_p->iluFactorize(); return;}
1176 if(cEntries_p != 0) {cEntries_p->iluFactorize(); return;}
1177 if(rmEntries_p != 0)
1178 {
1179 where("MatrixEntry::iluFactorize");
1180 error("matrixentry_matrixofmatrices_not_handled");
1181 }
1182 if(cmEntries_p != 0)
1183 {
1184 where("MatrixEntry::iluFactorize");
1185 error("matrixentry_matrixofmatrices_not_handled");
1186 }
1187 where("MatrixEntry::iluFactorize");
1188 error("null_pointer", "xxEntries_p");
1189 }
1190
1191 //incomplete factorize matrix entry as LDLt,
ildltFactorize()1192 void MatrixEntry::ildltFactorize()
1193 {
1194 if(rEntries_p != 0) {rEntries_p->ildltFactorize(); return;}
1195 if(cEntries_p != 0) {cEntries_p->ildltFactorize(); return;}
1196 if(rmEntries_p != 0)
1197 {
1198 where("MatrixEntry::ildltFactorize");
1199 error("matrixentry_matrixofmatrices_not_handled");
1200 }
1201 if(cmEntries_p != 0)
1202 {
1203 where("MatrixEntry::ildltFactorize");
1204 error("matrixentry_matrixofmatrices_not_handled");
1205 }
1206 where("MatrixEntry::ildltFactorize");
1207 error("null_pointer", "xxEntries_p");
1208 }
1209
1210 //incomplete factorize matrix entry as LDL*,
ildlstarFactorize()1211 void MatrixEntry::ildlstarFactorize()
1212 {
1213 if(rEntries_p != 0) {rEntries_p->ildlstarFactorize(); return;}
1214 if(cEntries_p != 0) {cEntries_p->ildlstarFactorize(); return;}
1215 if(rmEntries_p != 0)
1216 {
1217 where("MatrixEntry::ildlstarFactorize");
1218 error("matrixentry_matrixofmatrices_not_handled");
1219 }
1220 if(cmEntries_p != 0)
1221 {
1222 where("MatrixEntry::ildlstarFactorize");
1223 error("matrixentry_matrixofmatrices_not_handled");
1224 }
1225 where("MatrixEntry::ildlstarFactorize");
1226 error("null_pointer", "xxEntries_p");
1227 }
1228
1229 //incomplete factorize matrix entry as LLt,
illtFactorize()1230 void MatrixEntry::illtFactorize()
1231 {
1232 if(rEntries_p != 0) {rEntries_p->illtFactorize(); return;}
1233 if(cEntries_p != 0) {cEntries_p->illtFactorize(); return;}
1234 if(rmEntries_p != 0)
1235 {
1236 where("MatrixEntry::illtFactorize");
1237 error("matrixentry_matrixofmatrices_not_handled");
1238 }
1239 if(cmEntries_p != 0)
1240 {
1241 where("MatrixEntry::illtFactorize");
1242 error("matrixentry_matrixofmatrices_not_handled");
1243 }
1244 where("MatrixEntry::illtFactorize");
1245 error("null_pointer", "xxEntries_p");
1246 }
1247
1248 //incomplete factorize matrix entry as LL*,
illstarFactorize()1249 void MatrixEntry::illstarFactorize()
1250 {
1251 if(rEntries_p != 0) {rEntries_p->illstarFactorize(); return;}
1252 if(cEntries_p != 0) {cEntries_p->illstarFactorize(); return;}
1253 if(rmEntries_p != 0)
1254 {
1255 where("MatrixEntry::illstarFactorize");
1256 error("matrixentry_matrixofmatrices_not_handled");
1257 }
1258 if(cmEntries_p != 0)
1259 {
1260 where("MatrixEntry::illstarFactorize");
1261 error("matrixentry_matrixofmatrices_not_handled");
1262 }
1263 where("MatrixEntry::illstarFactorize");
1264 error("null_pointer", "xxEntries_p");
1265 }
1266 //factorize matrix using umfpack
umfpackFactorize()1267 void MatrixEntry::umfpackFactorize()
1268 {
1269 if(rEntries_p != 0) {rEntries_p->umfpackFactorize(); return;}
1270 if(cEntries_p != 0) {cEntries_p->umfpackFactorize(); return;}
1271 if(rmEntries_p != 0)
1272 {
1273 where("MatrixEntry::umfpackFactorize");
1274 error("matrixentry_matrixofmatrices_not_handled");
1275 }
1276 if(cmEntries_p != 0)
1277 {
1278 where("MatrixEntry::umfpackFactorize");
1279 error("matrixentry_matrixofmatrices_not_handled");
1280 }
1281 where("MatrixEntry::umfpackFactorize");
1282 error("null_pointer", "xxEntries_p");
1283 }
1284
1285 //solve linear system using LDLt factorization
ldltSolve(const VectorEntry & B,VectorEntry & X)1286 void MatrixEntry::ldltSolve(const VectorEntry& B, VectorEntry& X)
1287 {
1288 if(rEntries_p != 0) //scalar real matrix
1289 {
1290 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->ldltSolve(*B.rEntries_p, *X.rEntries_p); return;}
1291 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->ldltSolve(*B.cEntries_p, *X.cEntries_p); return;}
1292 where("MatrixEntry::ldltSolve");
1293 error("entry_inconsistent_structures");
1294 }
1295 if(cEntries_p != 0) //scalar complex matrix
1296 {
1297 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->ldltSolve(*B.rEntries_p, *X.cEntries_p); return;}
1298 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->ldltSolve(*B.cEntries_p, *X.cEntries_p); return;}
1299 where("MatrixEntry::ldltSolve");
1300 error("entry_inconsistent_structures");
1301 }
1302 if(rmEntries_p != 0)
1303 {
1304 where("MatrixEntry::ldltSolve");
1305 error("matrixentry_matrixofmatrices_not_handled");
1306 }
1307 if(cmEntries_p != 0)
1308 {
1309 where("MatrixEntry::ldltSolve");
1310 error("matrixentry_matrixofmatrices_not_handled");
1311 }
1312 where("MatrixEntry::ldltSolve");
1313 error("null_pointer", "xxEntries_p");
1314 }
1315
1316 //solve linear system using LDL* factorization
ldlstarSolve(const VectorEntry & B,VectorEntry & X)1317 void MatrixEntry::ldlstarSolve(const VectorEntry& B, VectorEntry& X)
1318 {
1319 if(rEntries_p != 0) //scalar real matrix
1320 {
1321 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->ldlstarSolve(*B.rEntries_p, *X.rEntries_p); return;}
1322 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->ldlstarSolve(*B.rEntries_p, *X.rEntries_p); return;}
1323 where("MatrixEntry::ldlstarSolve");
1324 error("entry_inconsistent_structures");
1325 }
1326 if(cEntries_p != 0) //scalar complex matrix
1327 {
1328 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->ldlstarSolve(*B.rEntries_p, *X.cEntries_p); return;}
1329 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->ldlstarSolve(*B.cEntries_p, *X.cEntries_p); return;}
1330 where("MatrixEntry::ldlstarSolve");
1331 error("entry_inconsistent_structures");
1332 }
1333 if(rmEntries_p != 0)
1334 {
1335 where("MatrixEntry::ldlstarSolve");
1336 error("matrixentry_matrixofmatrices_not_handled");
1337 }
1338 if(cmEntries_p != 0)
1339 {
1340 where("MatrixEntry::ldlstarSolve");
1341 error("matrixentry_matrixofmatrices_not_handled");
1342 }
1343 where("MatrixEntry::ldlstarSolve");
1344 error("null_pointer", "xxEntries_p");
1345 }
1346
1347 //solve linear system using LLt factorization
lltSolve(const VectorEntry & B,VectorEntry & X)1348 void MatrixEntry::lltSolve(const VectorEntry& B, VectorEntry& X)
1349 {
1350 if(rEntries_p != 0) //scalar real matrix
1351 {
1352 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->lltSolve(*B.rEntries_p, *X.rEntries_p); return;}
1353 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->lltSolve(*B.cEntries_p, *X.cEntries_p); return;}
1354 where("MatrixEntry::ldltSolve");
1355 error("entry_inconsistent_structures");
1356 }
1357 if(cEntries_p != 0) //scalar complex matrix
1358 {
1359 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->lltSolve(*B.rEntries_p, *X.cEntries_p); return;}
1360 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->lltSolve(*B.cEntries_p, *X.cEntries_p); return;}
1361 where("MatrixEntry::lltSolve");
1362 error("entry_inconsistent_structures");
1363 }
1364 if(rmEntries_p != 0)
1365 {
1366 where("MatrixEntry::lltSolve");
1367 error("matrixentry_matrixofmatrices_not_handled");
1368 }
1369 if(cmEntries_p != 0)
1370 {
1371 where("MatrixEntry::lltSolve");
1372 error("matrixentry_matrixofmatrices_not_handled");
1373 }
1374 where("MatrixEntry::lltSolve");
1375 error("null_pointer", "xxEntries_p");
1376 }
1377
1378 //solve linear system using LU factorization
luSolve(const VectorEntry & B,VectorEntry & X)1379 void MatrixEntry::luSolve(const VectorEntry& B, VectorEntry& X)
1380 {
1381 if(rEntries_p != 0) //scalar real matrix
1382 {
1383 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->luSolve(*B.rEntries_p, *X.rEntries_p); return;}
1384 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->luSolve(*B.cEntries_p, *X.cEntries_p); return;}
1385 where("MatrixEntry::luSolve");
1386 error("entry_inconsistent_structures");
1387 }
1388 if(cEntries_p != 0) //scalar complex matrix
1389 {
1390 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->luSolve(*B.rEntries_p, *X.cEntries_p); return;}
1391 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->luSolve(*B.cEntries_p, *X.cEntries_p); return;}
1392 where("MatrixEntry::luSolve");
1393 error("entry_inconsistent_structures");
1394 }
1395 if(rmEntries_p != 0)
1396 {
1397 where("MatrixEntry::luSolve");
1398 error("matrixentry_matrixofmatrices_not_handled");
1399 }
1400 if(cmEntries_p != 0)
1401 {
1402 where("MatrixEntry::luSolve");
1403 error("matrixentry_matrixofmatrices_not_handled");
1404 }
1405 where("MatrixEntry::luSolve");
1406 error("null_pointer", "xxEntries_p");
1407 }
1408
1409 //solve linear system using umfpack LU factorization
umfluSolve(const VectorEntry & B,VectorEntry & X)1410 void MatrixEntry::umfluSolve(const VectorEntry& B, VectorEntry& X)
1411 {
1412 if(rEntries_p != 0) //scalar real matrix
1413 {
1414 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->umfluSolve(*B.rEntries_p, *X.rEntries_p); return;}
1415 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->umfluSolve(*B.cEntries_p, *X.cEntries_p); return;}
1416 where("MatrixEntry::umfluSolve");
1417 error("entry_inconsistent_structures");
1418 }
1419 if(cEntries_p != 0) //scalar complex matrix
1420 {
1421 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->umfluSolve(*B.rEntries_p, *X.cEntries_p); return;}
1422 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->umfluSolve(*B.cEntries_p, *X.cEntries_p); return;}
1423 where("MatrixEntry::umfluSolve");
1424 error("entry_inconsistent_structures");
1425 }
1426 if(rmEntries_p != 0)
1427 {
1428 where("MatrixEntry::umfluSolve");
1429 error("matrixentry_matrixofmatrices_not_handled");
1430 }
1431 if(cmEntries_p != 0)
1432 {
1433 where("MatrixEntry::umfluSolve");
1434 error("matrixentry_matrixofmatrices_not_handled");
1435 }
1436 where("MatrixEntry::umfluSolve");
1437 error("null_pointer", "xxEntries_p");
1438 }
1439
1440 //solve linear system using Sor Diagonal Solver
sorDiagonalSolve(const VectorEntry & B,VectorEntry & X,const real_t w)1441 void MatrixEntry::sorDiagonalSolve(const VectorEntry& B, VectorEntry& X, const real_t w)
1442 {
1443 if(rEntries_p != 0) //scalar real matrix
1444 {
1445 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->sorDiagonalSolve(*B.rEntries_p, *X.rEntries_p, w); return;}
1446 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->sorDiagonalSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1447 where("MatrixEntry::sorDiagonalSolver");
1448 error("entry_inconsistent_structures");
1449 }
1450 if(cEntries_p != 0) //scalar complex matrix
1451 {
1452 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorDiagonalSolve(*B.rEntries_p, *X.cEntries_p, w); return;}
1453 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorDiagonalSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1454 where("MatrixEntry::sorDiagonalSolver");
1455 error("entry_inconsistent_structures");
1456 }
1457 if(rmEntries_p != 0)
1458 {
1459 where("MatrixEntry::sorDiagonalSolver");
1460 error("matrixentry_matrixofmatrices_not_handled");
1461 }
1462 if(cmEntries_p != 0)
1463 {
1464 where("MatrixEntry::sorDiagonalSolver");
1465 error("matrixentry_matrixofmatrices_not_handled");
1466 }
1467 where("MatrixEntry::sorDiagonalSolver");
1468 error("null_pointer", "xxEntries_p");
1469 }
1470 //solve linear system using Sor Upper Solver
sorDiagonalMatrixVector(const VectorEntry & B,VectorEntry & X,const real_t w)1471 void MatrixEntry::sorDiagonalMatrixVector(const VectorEntry& B, VectorEntry& X, const real_t w)
1472 {
1473 if(rEntries_p != 0) //scalar real matrix
1474 {
1475 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->sorDiagonalMatrixVector(*B.rEntries_p, *X.rEntries_p, w); return;}
1476 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->sorDiagonalMatrixVector(*B.cEntries_p, *X.cEntries_p, w); return;}
1477 where("MatrixEntry::sorDiagonalMatrixVector");
1478 error("entry_inconsistent_structures");
1479 }
1480 if(cEntries_p != 0) //scalar complex matrix
1481 {
1482 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorDiagonalMatrixVector(*B.rEntries_p, *X.cEntries_p, w); return;}
1483 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorDiagonalMatrixVector(*B.cEntries_p, *X.cEntries_p, w); return;}
1484 where("MatrixEntry::sorDiagonalMatrixVector");
1485 error("entry_inconsistent_structures");
1486 }
1487 if(rmEntries_p != 0)
1488 {
1489 where("MatrixEntry::sorDiagonalMatrixVector");
1490 error("matrixentry_matrixofmatrices_not_handled");
1491 }
1492 if(cmEntries_p != 0)
1493 {
1494 where("MatrixEntry::sorDiagonalMatrixVector");
1495 error("matrixentry_matrixofmatrices_not_handled");
1496 }
1497 where("MatrixEntry::sorDiagonalMatrixVector");
1498 error("null_pointer", "xxEntries_p");
1499 }
1500
1501 //solve linear system using Sor Upper Solver
sorUpperSolve(const VectorEntry & B,VectorEntry & X,const real_t w)1502 void MatrixEntry::sorUpperSolve(const VectorEntry& B, VectorEntry& X, const real_t w)
1503 {
1504 if(rEntries_p != 0) //scalar real matrix
1505 {
1506 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->sorUpperSolve(*B.rEntries_p, *X.rEntries_p, w); return;}
1507 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->sorUpperSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1508 where("MatrixEntry::sorUpperSolver");
1509 error("entry_inconsistent_structures");
1510 }
1511 if(cEntries_p != 0) //scalar complex matrix
1512 {
1513 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorUpperSolve(*B.rEntries_p, *X.cEntries_p, w); return;}
1514 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorUpperSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1515 where("MatrixEntry::sorUpperSolver");
1516 error("entry_inconsistent_structures");
1517 }
1518 if(rmEntries_p != 0)
1519 {
1520 where("MatrixEntry::sorUpperSolver");
1521 error("matrixentry_matrixofmatrices_not_handled");
1522 }
1523 if(cmEntries_p != 0)
1524 {
1525 where("MatrixEntry::sorUpperSolver");
1526 error("matrixentry_matrixofmatrices_not_handled");
1527 }
1528 where("MatrixEntry::sorUpperSolver");
1529 error("null_pointer", "xxEntries_p");
1530 }
1531
1532 //solve linear system using Sor Upper Solver
sorLowerSolve(const VectorEntry & B,VectorEntry & X,const real_t w)1533 void MatrixEntry::sorLowerSolve(const VectorEntry& B, VectorEntry& X, const real_t w)
1534 {
1535 if(rEntries_p != 0) //scalar real matrix
1536 {
1537 if(B.rEntries_p != 0 && X.rEntries_p != 0) {rEntries_p->sorLowerSolve(*B.rEntries_p, *X.rEntries_p, w); return;}
1538 if(B.cEntries_p != 0 && X.cEntries_p != 0) {rEntries_p->sorLowerSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1539 where("MatrixEntry::sorLowerSolver");
1540 error("entry_inconsistent_structures");
1541 }
1542 if(cEntries_p != 0) //scalar complex matrix
1543 {
1544 if(B.rEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorLowerSolve(*B.rEntries_p, *X.cEntries_p, w); return;}
1545 if(B.cEntries_p != 0 && X.cEntries_p != 0) {cEntries_p->sorLowerSolve(*B.cEntries_p, *X.cEntries_p, w); return;}
1546 where("MatrixEntry::sorLowerSolver");
1547 error("entry_inconsistent_structures");
1548 }
1549 if(rmEntries_p != 0)
1550 {
1551 where("MatrixEntry::sorLowerSolver");
1552 error("matrixentry_matrixofmatrices_not_handled");
1553 }
1554 if(cmEntries_p != 0)
1555 {
1556 where("MatrixEntry::sorLowerSolver");
1557 error("matrixentry_matrixofmatrices_not_handled");
1558 }
1559 where("MatrixEntry::sorLowerSolver");
1560 error("null_pointer", "xxEntries_p");
1561 }
1562
operator <<(std::ostream & out,const MatrixEntry & mat)1563 std::ostream& operator<<(std::ostream& out, const MatrixEntry& mat)
1564 {
1565 mat.print(out);
1566 return out;
1567 }
1568
1569 //---------------------------------------------------------------------------------------------
1570 //! matrix * vector (consistent structure)
1571 //---------------------------------------------------------------------------------------------
operator *(const MatrixEntry & mat,const VectorEntry & vec)1572 VectorEntry operator*(const MatrixEntry& mat, const VectorEntry& vec)
1573 {
1574 VectorEntry res;
1575 multMatrixVector(mat,vec,res);
1576 return res;
1577 }
1578
multMatrixVector(const MatrixEntry & mat,const VectorEntry & vec,VectorEntry & res)1579 void multMatrixVector(const MatrixEntry& mat, const VectorEntry& vec, VectorEntry& res)
1580 {
1581 StrucType stm=mat.strucType_, stv=vec.strucType_;
1582 if ((stm==_scalar && stv!=_scalar) || (stm==_matrix && stv!=_vector))
1583 {
1584 where("MatrixEntry * VectorEntry");
1585 error("entry_inconsistent_structures");
1586 }
1587 number_t nv=1;
1588 if (stm==_matrix)
1589 {
1590 nv=mat.nbOfComponents.first;
1591 if(mat.nbOfComponents.second!=vec.nbOfComponents)
1592 {
1593 where("MatrixEntry * VectorEntry");
1594 error("entry_mismatch_dims", mat.nbOfComponents.second, vec.nbOfComponents);
1595 }
1596 }
1597 if (mat.nbOfCols()!=vec.size())
1598 {
1599 where("MatrixEntry * VectorEntry");
1600 error("entry_mismatch_dims", mat.nbOfCols(), vec.size());
1601 }
1602 ValueType vtm=mat.valueType_, vtv=vec.valueType_, vtr=_real;
1603 if (vtm==_complex || vtv==_complex) vtr=_complex;
1604
1605 //reallocate res if not suited
1606 if (res.valueType_!=vtr || res.strucType_!=stm || res.size()!=mat.nbOfRows() ||res.nbOfComponents !=nv )
1607 res=VectorEntry(vtr, stm, mat.nbOfRows(),nv);
1608
1609 if (stm==_scalar)
1610 {
1611 if (vtm==_real && vtv==_real) *res.rEntries_p = *mat.rEntries_p * *vec.rEntries_p;
1612 if (vtm==_complex && vtv==_complex) *res.cEntries_p = *mat.cEntries_p * *vec.cEntries_p;
1613 if (vtm==_complex && vtv==_real) *res.cEntries_p = *mat.cEntries_p * cmplx(*vec.rEntries_p);
1614 if (vtm==_real && vtv==_complex)
1615 {
1616 *res.cEntries_p = Vector<complex_t>(*mat.rEntries_p * real(*vec.cEntries_p));
1617 *res.cEntries_p += complex_t(0.,1.)* Vector<complex_t>(*mat.rEntries_p * imag(*vec.cEntries_p));
1618 }
1619 }
1620 else
1621 {
1622 if (vtm==_real && vtv==_real) *res.rvEntries_p = *mat.rmEntries_p * *vec.rvEntries_p;
1623 if (vtm==_complex && vtv==_complex) *res.cvEntries_p = *mat.cmEntries_p * *vec.cvEntries_p;
1624 if (vtm==_complex && vtv==_real) *res.cvEntries_p = *mat.cmEntries_p * cmplx(*vec.rvEntries_p);
1625 if (vtm==_real && vtv==_complex)
1626 {
1627 *res.cvEntries_p = Vector<Vector<complex_t> >(*mat.rmEntries_p * real(*vec.cvEntries_p));
1628 *res.cvEntries_p += complex_t(0.,1.)* Vector<Vector<complex_t> >(*mat.rmEntries_p * imag(*vec.cvEntries_p));
1629 }
1630 }
1631 }
1632
1633 //---------------------------------------------------------------------------------------------
1634 //! vector * matrix (consistent structure)
1635 //---------------------------------------------------------------------------------------------
operator *(const VectorEntry & vec,const MatrixEntry & mat)1636 VectorEntry operator*(const VectorEntry& vec, const MatrixEntry& mat)
1637 {
1638 VectorEntry res;
1639 multVectorMatrix(vec,mat,res);
1640 return res;
1641 }
1642
multVectorMatrix(const MatrixEntry & mat,const VectorEntry & vec,VectorEntry & res)1643 void multVectorMatrix(const MatrixEntry& mat, const VectorEntry& vec, VectorEntry& res)
1644 {
1645 multVectorMatrix(vec, mat, res);
1646 }
1647
multVectorMatrix(const VectorEntry & vec,const MatrixEntry & mat,VectorEntry & res)1648 void multVectorMatrix(const VectorEntry& vec, const MatrixEntry& mat, VectorEntry& res)
1649 {
1650 StrucType stm=mat.strucType_, stv=vec.strucType_;
1651 if ((stm==_scalar && stv!=_scalar) || (stm==_matrix && stv!=_vector))
1652 {
1653 where("VectorEntry * MatrixEntry");
1654 error("entry_inconsistent_structures");
1655 }
1656 number_t nu=1;
1657 if (stm==_matrix)
1658 {
1659 nu=mat.nbOfComponents.second;
1660 if (mat.nbOfComponents.first!=vec.nbOfComponents)
1661 {
1662 where("VectorEntry * MatrixEntry");
1663 error("entry_mismatch_dims", vec.nbOfComponents, mat.nbOfComponents.first);
1664 }
1665 }
1666 if (mat.nbOfRows()!=vec.size())
1667 {
1668 where("VectorEntry * MatrixEntry");
1669 error("entry_mismatch_dims", vec.size(), mat.nbOfRows());
1670 }
1671 ValueType vtm=mat.valueType_, vtv=vec.valueType_, vtr=_real;
1672 if (vtm==_complex || vtv==_complex) vtr=_complex;
1673
1674 //reallocate res if not suited
1675 if (res.valueType_!=vtr || res.strucType_!=stm || res.size()!=mat.nbOfCols() ||res.nbOfComponents !=nu )
1676 res=VectorEntry(vtr, stm, mat.nbOfCols(),nu);
1677
1678 if (stm==_scalar)
1679 {
1680 if (vtm==_real && vtv==_real) *res.rEntries_p = *vec.rEntries_p * *mat.rEntries_p;
1681 if (vtm==_complex && vtv==_complex) *res.cEntries_p = *vec.cEntries_p * *mat.cEntries_p;
1682 if (vtm==_complex && vtv==_real) *res.cEntries_p = cmplx(*vec.rEntries_p) * *mat.cEntries_p;
1683 if (vtm==_real && vtv==_complex)
1684 {
1685 *res.cEntries_p = Vector<complex_t>(real(*vec.cEntries_p) * *mat.rEntries_p);
1686 *res.cEntries_p += complex_t(0.,1.)* Vector<complex_t>(imag(*vec.cEntries_p) * *mat.rEntries_p);
1687 }
1688 }
1689 else
1690 {
1691 if (vtm==_real && vtv==_real) *res.rvEntries_p = *vec.rvEntries_p * *mat.rmEntries_p;
1692 if (vtm==_complex && vtv==_complex) *res.cvEntries_p = *vec.cvEntries_p * *mat.cmEntries_p;
1693 if (vtm==_complex && vtv==_real) *res.cvEntries_p = cmplx(*vec.rvEntries_p) * *mat.cmEntries_p;
1694 if (vtm==_real && vtv==_complex)
1695 {
1696 *res.cvEntries_p = Vector<Vector<complex_t> >(real(*vec.cvEntries_p) * *mat.rmEntries_p);
1697 *res.cvEntries_p += complex_t(0.,1.)* Vector<Vector<complex_t> >(imag(*vec.cvEntries_p) * *mat.rmEntries_p);
1698 }
1699 }
1700 }
1701
1702
1703 //---------------------------------------------------------------------------------------------
1704 /*!QR factorization of rectangular matrix pxn with p<=n using Housolder method
1705 generic algorithm using a column algorithm with dynamic storage creation of matrix results
1706 mat : matrix to factorize
1707 matR : upper triangular matrix p x n stored as ColCsStorage
1708 matQ : unitary matrix of size p x p stored as RowCsStorage
1709 computeQ : if true the matrix Q is computed else not
1710 rhs : right hand side vector pointer (if 0 not reduction for rhs)
1711 withColPermutation : if true, column may be permuted (more stable factorization), may be forced by algorithm
1712 numcol_p : renumbering of columns if they have been permuted (pointer)
1713 stop : iteration number when the algorithm stops: stop = nbr when algorithm exits normally */
1714 //---------------------------------------------------------------------------------------------
QR(const MatrixEntry & mat,MatrixEntry & matR,bool computeQ,MatrixEntry & matQ,VectorEntry * rhs,bool & withColPermutation,std::vector<number_t> * & numcol,number_t & stop)1715 void QR(const MatrixEntry& mat, MatrixEntry& matR, bool computeQ, MatrixEntry& matQ, VectorEntry* rhs,
1716 bool& withColPermutation, std::vector<number_t>*& numcol, number_t& stop)
1717 {
1718 //initialization
1719 matR.clear();
1720 matQ.clear();
1721 ValueType vtm=mat.valueType_; StrucType stm=mat.strucType_; dimPair nbc=mat.nbOfComponents;
1722 matR.valueType_ = matQ.valueType_ = vtm;
1723 matR.strucType_ = matQ.strucType_ = stm;
1724 matR.nbOfComponents = matQ.nbOfComponents = nbc;
1725 if(rhs!=0)
1726 {
1727 if(rhs->strucType_ != _scalar)
1728 {
1729 where("QR(MatrixEntry, ...)");
1730 error("scalar_rhs_only");
1731 }
1732
1733 }
1734
1735 std::vector<real_t>* rsmb=0;
1736 std::vector<complex_t>* csmb=0;
1737
1738 //call QR(LargeMatrix,...)
1739 if(stm == _scalar)
1740 {
1741 switch(vtm)
1742 {
1743 case _real :
1744 {
1745 if(rhs!= 0)
1746 {
1747 if(rhs->valueType_ == _real) QR(*mat.rEntries_p, matR.rEntries_p, computeQ, matQ.rEntries_p, rhs->rEntries_p,
1748 withColPermutation, numcol, stop); //QR factorisation using Housholder method
1749 else QR(*mat.rEntries_p, matR.rEntries_p, computeQ, matQ.rEntries_p, rhs->cEntries_p,
1750 withColPermutation, numcol, stop); //QR factorisation using Housholder method
1751 }
1752 else QR(*mat.rEntries_p, matR.rEntries_p, computeQ, matQ.rEntries_p, rsmb,
1753 withColPermutation, numcol, stop); //QR factorisation using Housholder method
1754 }
1755 break;
1756 default : //complex case
1757 {
1758 if(rhs!=0 && rhs->valueType_ == _real) rhs->toComplex(); //convert rhs to complex
1759 if(rhs!=0) csmb = rhs->cEntries_p;
1760 QR(*mat.cEntries_p, matR.cEntries_p, computeQ, matQ.cEntries_p, csmb,
1761 withColPermutation, numcol, stop); //QR factorisation using Housholder method
1762 }
1763 }
1764 }
1765 else
1766 {
1767 where("QR(MatrixEntry, ...)");
1768 error("matrixentry_matrixofmatrices_not_handled");
1769 }
1770 }
1771
1772 //-----------------------------------------------------------------------------------------------------------------------------
1773 /*! solve an pxp upper triangular system
1774 mat : pxp upper triangular matrix with its diagonal coeffs = 1,
1775 matR : rectangular matrix p x m, understood as a list of right hand side vectors of size p (if 0 no computation for matR)
1776 rhs : a unique right hand side vector pointer (if 0 no computation for rhs)
1777
1778 At the end, rhs contains the vector x solution of mat * x = rhs and matR contains the vectors x1, x2, ...xm solutions of mat * xj = matRj
1779 Note: at the end, matR is stored using a cs column storage */
1780 //-----------------------------------------------------------------------------------------------------------------------------
QRSolve(const MatrixEntry & mat,MatrixEntry * matR,VectorEntry * rhs)1781 void QRSolve(const MatrixEntry& mat, MatrixEntry* matR, VectorEntry* rhs)
1782 {
1783 if(matR==0 && rhs==0) return; //nothing to do !!!
1784 ValueType vtm=mat.valueType_; StrucType stm=mat.strucType_;
1785 ValueType vtr=rhs->valueType_;
1786 //call QRSolve(LargeMatrix,...)
1787 if(stm == _scalar)
1788 {
1789 switch(vtm)
1790 {
1791 case _real :
1792 {
1793 LargeMatrix<real_t>* lm=0;
1794 std::vector<real_t>* sm=0;
1795 if(matR!=0) lm= matR->rEntries_p;
1796 if(rhs!=0)
1797 {
1798 if(vtr==_real) QRSolve(*mat.rEntries_p, lm, rhs->rEntries_p);
1799 else // move matrix to complex because QR does not work yet with real matrix and complex vector
1800 {
1801 MatrixEntry cmat=mat; cmat.toComplex();
1802 LargeMatrix<complex_t>* lmc=0;
1803 if(matR!=0)
1804 {
1805 matR->toComplex();
1806 lmc= matR->cEntries_p;
1807 }
1808 QRSolve(*cmat.cEntries_p, lmc, rhs->cEntries_p);
1809 if(matR!=0) matR->toReal(); //come back to real
1810 }
1811 }
1812 else QRSolve(*mat.rEntries_p, lm, sm);
1813 }
1814 break;
1815 default : //complex case
1816 {
1817 LargeMatrix<complex_t>* lm=0;
1818 std::vector<complex_t>* sm=0;
1819 if(matR!=0) lm= matR->cEntries_p;
1820 if(rhs!=0)
1821 {
1822 if(vtr==_complex) QRSolve(*mat.cEntries_p, lm, rhs->cEntries_p);
1823 else
1824 {
1825 rhs->toComplex();
1826 QRSolve(*mat.cEntries_p, lm, rhs->cEntries_p);
1827 }
1828 }
1829 else QRSolve(*mat.cEntries_p, lm, sm);
1830 }
1831 }
1832 }
1833 else
1834 {
1835 where("QR(MatrixEntry, ...)");
1836 error("matrixentry_matrixofmatrices_not_handled");
1837 }
1838 }
1839
1840 // Gauss solver (only in scalar)
gaussSolve(MatrixEntry & mat,VectorEntry & b,VectorEntry & x)1841 void gaussSolve(MatrixEntry& mat, VectorEntry& b, VectorEntry& x)
1842 {
1843 ValueType vtm=mat.valueType_;
1844 ValueType vtb=b.valueType_;
1845 if(mat.strucType_ != _scalar)
1846 {
1847 where("gaussSolve(MatrixEntry, ...)");
1848 error("matrixentry_matrixofmatrices_not_handled");
1849 }
1850 if(vtm==_real)
1851 {
1852 if(vtb==_real)
1853 {
1854 x=b;
1855 gaussSolve(*mat.rEntries_p,*x.rEntries_p);
1856 return;
1857 }
1858 else
1859 {
1860 x=b;
1861 std::vector<std::vector<real_t> > rhss(2);
1862 rhss[0]=real(*b.cEntries_p);
1863 rhss[1]=imag(*b.cEntries_p);
1864 gaussSolve(*mat.rEntries_p,rhss);
1865 *x.cEntries_p=Vector<real_t>(rhss[0])+complex_t(0,1)*Vector<real_t>(rhss[1]);
1866 return;
1867 }
1868 }
1869 else
1870 {
1871 if(vtb==_real)
1872 {
1873 x=b;
1874 x.toComplex();
1875 gaussSolve(*mat.cEntries_p,*x.cEntries_p);
1876 return;
1877 }
1878 else
1879 {
1880 x=b;
1881 gaussSolve(*mat.cEntries_p,*x.cEntries_p);
1882 return;
1883 }
1884 }
1885 }
1886
1887 // umfpack solver (only in scalar representation)
1888 // return the reciprocal condition numer
umfpackSolve(MatrixEntry & mat,VectorEntry & b,VectorEntry & x,real_t & rcond)1889 void umfpackSolve(MatrixEntry& mat, VectorEntry& b, VectorEntry& x, real_t& rcond)
1890 {
1891 #ifdef XLIFEPP_WITH_UMFPACK
1892 ValueType vtm=mat.valueType_;
1893 ValueType vtb=b.valueType_;
1894 if(mat.strucType_ != _scalar)
1895 {
1896 where("umfpackSolve(MatrixEntry, ...)");
1897 error("matrixentry_matrixofmatrices_not_handled");
1898 }
1899 x=b; //allocate x with the type of b
1900 if(vtm==_real)
1901 {
1902 if(vtb==_real)
1903 {
1904 rcond=mat.rEntries_p->umfpackSolve(*b.rEntries_p, *x.rEntries_p);
1905 return;
1906 }
1907 else
1908 {
1909 rcond=mat.rEntries_p->umfpackSolve(*b.cEntries_p, *x.cEntries_p);
1910 return;
1911 }
1912 }
1913 else
1914 {
1915 if(vtb==_real)
1916 {
1917 x.toComplex(); // now, x has complex scalar entries
1918 rcond=mat.cEntries_p->umfpackSolve(*b.rEntries_p, *x.cEntries_p);
1919 return;
1920 }
1921 else
1922 {
1923 rcond=mat.cEntries_p->umfpackSolve(*b.cEntries_p, *x.cEntries_p);
1924 return;
1925 }
1926 }
1927 #else
1928 error("xlifepp_without_umfpack");
1929 #endif // XLIFEPP_WITH_UMFPACK
1930 }
1931
1932 // umfpack solver with multiple right hand side (only in scalar representation)
1933 // xs pointers have to be already allocated
1934 // return the reciprocal condition number
umfpackSolve(MatrixEntry & mat,std::vector<VectorEntry * > & bs,std::vector<VectorEntry * > & xs,real_t & rcond)1935 void umfpackSolve(MatrixEntry& mat, std::vector<VectorEntry*>& bs, std::vector<VectorEntry*>& xs, real_t& rcond)
1936 {
1937 #ifdef XLIFEPP_WITH_UMFPACK
1938 ValueType vtm=mat.valueType_;
1939 if(mat.strucType_ != _scalar)
1940 {
1941 where("umfpackSolve(MatrixEntry, ...)");
1942 error("matrixentry_matrixofmatrices_not_handled");
1943 }
1944 number_t ns=bs.size();
1945 if(ns==0)
1946 {
1947 where("umfpackSolve(MatrixEntry, ...)");
1948 error("no_rhs");
1949 }
1950
1951 //prepare rhs bs
1952 std::vector<VectorEntry*> cbs=bs; //copy rhs pointers
1953 ValueType vtbs=_real;
1954 for(number_t k=0; k<ns && vtbs==_real; k++) vtbs = bs[k]->valueType_; // detects if at least one rhs is complex
1955 if(vtbs==_complex || vtm==_complex) //move real rhs to complex rhs
1956 {
1957 for(number_t k=0; k<ns ; k++)
1958 {
1959 if(bs[k]->valueType_==_real) //allocate new complex VectorEntry
1960 {
1961 cbs[k]= new VectorEntry(complex_t(0), bs[k]->size());
1962 *cbs[k]+=*bs[k]; //copy real bs[k]
1963 }
1964 }
1965 }
1966 //prepare results xs
1967 for(number_t k=0; k<ns; k++) *xs[k]=*cbs[k];
1968
1969 if(vtm==_real)
1970 {
1971 if(vtbs==_real)
1972 {
1973 std::vector<std::vector<real_t>* > vb(ns,0), vx(ns,0);
1974 for(number_t k=0;k<ns; k++)
1975 {
1976 vb[k]=bs[k]->rEntries_p;
1977 vx[k]=xs[k]->rEntries_p;
1978 }
1979 rcond=mat.rEntries_p->umfpackSolve(vb,vx);
1980 }
1981 else
1982 {
1983 std::vector<std::vector<complex_t>* > vb(ns,0), vx(ns,0);
1984 for(number_t k=0;k<ns; k++)
1985 {
1986 vb[k]=bs[k]->cEntries_p;
1987 vx[k]=xs[k]->cEntries_p;
1988 }
1989 rcond=mat.rEntries_p->umfpackSolve(vb,vx);
1990 }
1991 }
1992 else //complex case
1993 {
1994 std::vector<std::vector<complex_t>* > vb(ns,0), vx(ns,0);
1995 for(number_t k=0;k<ns; k++)
1996 {
1997 vb[k]=bs[k]->cEntries_p;
1998 vx[k]=xs[k]->cEntries_p;
1999 }
2000 rcond=mat.cEntries_p->umfpackSolve(vb,vx);
2001 }
2002
2003 // deallocate allocated complex rhs
2004 if(vtbs==_complex || vtm==_complex)
2005 {
2006 for(number_t k=0; k<ns ; k++)
2007 {
2008 if(bs[k]->valueType_==_real) delete cbs[k]; //deallocate new complex VectorEntry
2009 }
2010 }
2011 #else
2012 error("xlifepp_without_umfpack");
2013 #endif // XLIFEPP_WITH_UMFPACK
2014 }
2015
2016 /*! factorize matrix as LU or LDLt or LDL* along matrix property
2017 if ft=_noFactorisation, type of factorization is searched
2018 if matrix is symmetric ldlt factorisation is used
2019 if matrix is self-adjoint ldlstar factorisation is used
2020 note that factorisation may be failed because there is no pivoting strategy (except for definite symmetric matrix!)
2021 if matrix is skew-adjoint ldlstar factorisation may be worked if the diagonal is non zero
2022 if matrix is skew-symmetric (diagonal is zero!) ldlt failed in any case !
2023 For the moment LU factorisation is used in case of a skew-adjoint or a skew-symmetric matrix
2024 in future, for specific algorithm for skew symmetric or skew adjoint matrices see following papers :
2025 Bunch J.R. Stable Algorithms for Solving Symmetric and Skew-Symmetric Systems, Bull. Austral. Math. Soc., vol 26, 107-119, 1982
2026 Lau T., Numerical Solution of Skew-Symmetric Linear Systems, Master Thesis, University of British Columbia, 2007
2027
2028 If umfPack is available, it is used when ft is not specified
2029 if withPermution = true, LU with row permutation will be used to deal with dense matrices
2030 */
factorize(MatrixEntry & A,MatrixEntry & Af,FactorizationType ft,bool withPermutation)2031 void factorize(MatrixEntry& A, MatrixEntry& Af, FactorizationType ft, bool withPermutation)
2032 {
2033 FactorizationType fac = ft;
2034
2035 if (&Af != &A)
2036 {
2037 Af.clear(); //copy A to Af
2038 Af=A;
2039 }
2040
2041 if (ft == _noFactorization) //search factorization type
2042 {
2043 fac = _lu;
2044 if (Af.symmetry() == _symmetric) fac = _ldlt;
2045 if (Af.symmetry() == _selfAdjoint) fac = _ldlstar;
2046 #ifdef XLIFEPP_WITH_UMFPACK
2047 fac=_umfpack;
2048 #endif // XLIFEPP_WITH_UMFPACK
2049 }
2050
2051 if (fac!=_umfpack && Af.storageType() == _cs) Af.toSkyline(); //convert entries to skyline storage
2052
2053 //check factorization type and storage consistancy, because we use autofactorization
2054 if (Af.accessType()==_sym && fac==_lu)
2055 {//error("structure_not_handled_in_factorization", words("factorization type",_lu), words("access type",_sym));
2056 fac=_ldlt;
2057 warning("free_warning","as Matrix has a symmetric storage access, use ldlt instead of lu");
2058 }
2059
2060 std::cout<<" factorise matrix "<<Af.nbOfRows()<<" x "<<Af.nbOfCols()<<" using ";
2061 switch(fac)
2062 {
2063 case _ldlt :
2064 case _llt :
2065 std::cout<<"L(D)Lt (skyline) "<<eol;
2066 Af.ldltFactorize();
2067 break;
2068 case _ldlstar :
2069 case _llstar :
2070 std::cout<<"L(D)L* (skyline) "<<eol;
2071 Af.ldlstarFactorize();
2072 break;
2073 case _lu :
2074 std::cout<<"LU (skyline) "<<eol;
2075 Af.luFactorize(withPermutation);
2076 break;
2077 case _umfpack :
2078 std::cout<<"umfpack (compressed sparse column) "<<eol;
2079 Af.umfpackFactorize();
2080 break;
2081 default :
2082 error("wrong_factorization_type",words("factorization type",fac));
2083 }
2084 }
2085
2086 //! factorize matrix as LU or LDLt or LDL*, not preserving A
factorize(MatrixEntry & A,FactorizationType ft,bool withPermutation)2087 void factorize(MatrixEntry& A, FactorizationType ft, bool withPermutation) { factorize(A,A,ft,withPermutation); }
2088
iFactorize(MatrixEntry & A,MatrixEntry & Af,FactorizationType ift)2089 void iFactorize(MatrixEntry& A, MatrixEntry& Af, FactorizationType ift)
2090 {
2091 FactorizationType ifac = ift;
2092
2093 if (&Af != &A)
2094 {
2095 Af.clear(); //copy A to Af
2096 Af=A;
2097 }
2098 if (ift == _noFactorization) //search factorization type
2099 {
2100 ifac = _ilu;
2101 if (Af.symmetry() == _symmetric) ifac = _ildlt;
2102 if (Af.symmetry() == _selfAdjoint) ifac = _ildlstar;
2103 }
2104 std::cout<<" factorise matrix "<<Af.nbOfRows()<<" x "<<Af.nbOfCols()<<" using ";
2105 switch(ifac)
2106 {
2107 case _ildlt :
2108 std::cout<<"iLDLt (cs) "<<eol;
2109 Af.ildltFactorize();
2110 break;
2111 case _illt :
2112 std::cout<<"iLLt (cs) "<<eol;
2113 Af.illtFactorize();
2114 break;
2115 case _ildlstar :
2116 std::cout<<"iLDL* (cs) "<<eol;
2117 Af.ildlstarFactorize();
2118 break;
2119 case _illstar :
2120 std::cout<<"LL* (cs) "<<eol;
2121 Af.illstarFactorize();
2122 break;
2123 case _ilu :
2124 std::cout<<"iLU (Cs) "<<eol;
2125 Af.iluFactorize();
2126 break;
2127 default :
2128 error("wrong_factorization_type",words("factorization type",ifac));
2129 }
2130 }
2131
2132 //! incomplete factorize matrix as ILU (or iLDLt or iLDL*), not preserving A
iFactorize(MatrixEntry & A,FactorizationType ift)2133 void iFactorize(MatrixEntry& A, FactorizationType ift) { iFactorize(A,A,ift); }
2134 //solve linear system when matrix is already factorized
factSolve(MatrixEntry & A,const VectorEntry & B)2135 VectorEntry factSolve(MatrixEntry& A, const VectorEntry& B)
2136 {
2137 trace_p->push("factSolve(MatrixEntry, VectorEntry)");
2138 if (A.factorization() == _noFactorization) error("term_not_factorized");
2139 VectorEntry X = B;
2140 ValueType vtX = _real;
2141 if(B.valueType_==_complex || A.valueType()==_complex) vtX=_complex;
2142 if(B.valueType_!=vtX) X.toComplex();
2143 switch(A.factorization())
2144 {
2145 case _ildlt :
2146 case _ldlt :
2147 A.ldltSolve(B, X);
2148 break;
2149 case _ldlstar :
2150 A.ldlstarSolve(B, X);
2151 break;
2152 case _illt :
2153 case _llt :
2154 A.lltSolve(B, X);
2155 break;
2156 case _lu :
2157 case _ilu :
2158 A.luSolve(B, X);
2159 break;
2160 case _umfpack :
2161 A.umfluSolve(B,X);
2162 break;
2163 default :
2164 error("wrong_factorization_type", words("factorization type",A.factorization()));
2165 }
2166 trace_p->pop();
2167 return X;
2168 }
2169
2170
2171 //-----------------------------------------------------------------------------------------------------------------------------
2172 /*! Resolve an eigen problem with different method
2173 * This function is a wrapper of different eigenSolvers of class LargeMatrix (e.g: eigenDavidsonSolver, eigenKrylovSchurSolver, ...)
2174 * \param[in] eigCompMode enumeration of different eigenSolver(davidson, krylovSchur). By default, it should be KrylovSchur
2175 * \param[in] nev The number of eigen values and eigenSolver searched for
2176 * \param[in] tol Tolerance
2177 * \param[in] which Specification of which eigen values are returned. Largest-LM, Smallest-SM
2178 * \param[in] sigma shift value used in shift mode. In case of real shift, the real part of sigma will be used
2179 * \param[in] isRealShift Specify if real shift is used
2180 * \param[in] isShift Specify if real or complex shift is used */
eigenSolve(EigenComputationalMode eigCompMode,number_t nev,real_t tol,string_t which,complex_t sigma,bool isRealShift,bool isShift)2181 std::vector<std::pair<complex_t, VectorEntry* > > MatrixEntry::eigenSolve(EigenComputationalMode eigCompMode, number_t nev,
2182 real_t tol, string_t which, complex_t sigma, bool isRealShift, bool isShift)
2183 {
2184 real_t realShift = real(sigma);
2185 complex_t cplxShift = sigma;
2186 FactorizationType fac = _noFactorization;
2187 bool isInverted = false;
2188 LargeMatrix<real_t>* prA = 0;
2189 LargeMatrix<complex_t>* pcA = 0;
2190 std::vector<std::pair<complex_t,Vector<complex_t> > > eigenVec;
2191
2192 if (0 != rEntries_p) //scalar real matrix
2193 {
2194 LargeMatrix<real_t>* pB = 0;
2195 if (isShift)
2196 {
2197 prA = new LargeMatrix<real_t>(_idMatrix, rEntries_p->storageType(), rEntries_p->accessType(),
2198 rEntries_p->nbRows, rEntries_p->nbCols, -realShift);
2199 prA->toStorage(rEntries_p->storagep());
2200 *prA += *rEntries_p;
2201 if (_skyline != prA->storageType())
2202 {
2203 LargeMatrix<real_t>* tmp = new LargeMatrix<real_t>(*prA, true);
2204 tmp->toSkyline();
2205 delete prA;
2206 prA = tmp;
2207 }
2208
2209 if (_symmetric == prA->sym)
2210 {
2211 prA->ldltFactorize();
2212 fac = _ldlt;
2213 }
2214 else
2215 {
2216 prA->luFactorize();
2217 fac = _lu;
2218 }
2219 isInverted = true;
2220 }
2221 else
2222 {
2223 if ("SM" == which)
2224 {
2225 prA = new LargeMatrix<real_t>(*rEntries_p, true);
2226 if (_skyline != prA->storageType()) prA->toSkyline();
2227 if (_symmetric == prA->sym)
2228 {
2229 prA->ldltFactorize();
2230 fac = _ldlt;
2231 }
2232 else
2233 {
2234 prA->luFactorize();
2235 fac = _lu;
2236 }
2237 isInverted = true;
2238 }
2239 else prA = rEntries_p;
2240 }
2241
2242 switch (eigCompMode)
2243 {
2244 case _davidson:
2245 eigenDavidsonSolve<real_t>(prA, pB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2246 break;
2247 default:
2248 eigenKrylovSchurSolve<real_t>(prA, pB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2249 break;
2250 }
2251
2252 if ( prA != rEntries_p) delete prA;
2253 }
2254
2255 if (0 != cEntries_p) //scalar complex matrix
2256 {
2257 LargeMatrix<complex_t>* pB = 0;
2258 if (isShift) //shift != 0
2259 {
2260 if (isRealShift) cplxShift = complex_t(realShift,0);
2261 pcA = new LargeMatrix<complex_t>(_idMatrix, cEntries_p->storageType(), cEntries_p->accessType(),
2262 cEntries_p->nbRows, cEntries_p->nbCols, -cplxShift);
2263 pcA->toStorage(cEntries_p->storagep());
2264 *pcA += *cEntries_p;
2265 if (_skyline != pcA->storageType())
2266 {
2267 LargeMatrix<complex_t>* tmp = new LargeMatrix<complex_t>(*pcA, true);
2268 tmp->toSkyline();
2269 delete pcA;
2270 pcA = tmp;
2271 }
2272
2273 if (_selfAdjoint == pcA->sym)
2274 {
2275 pcA->ldlstarFactorize();
2276 fac = _ldlstar;
2277 }
2278 else if (_symmetric == pcA->sym)
2279 {
2280 pcA->ldltFactorize();
2281 fac = _ldlt;
2282 }
2283 else
2284 {
2285 pcA->luFactorize();
2286 fac = _lu;
2287 }
2288 isInverted = true;
2289 }
2290 else
2291 {
2292 if ("SM" == which)
2293 {
2294 pcA = new LargeMatrix<complex_t>(*cEntries_p, true);
2295 if (_skyline != pcA->storageType()) pcA->toSkyline();
2296 if (_selfAdjoint == pcA->sym)
2297 {
2298 pcA->ldlstarFactorize();
2299 fac = _ldlstar;
2300 }
2301 else if (_symmetric == pcA->sym)
2302 {
2303 pcA->ldltFactorize();
2304 fac = _ldlt;
2305 }
2306 else
2307 {
2308 pcA->luFactorize();
2309 fac = _lu;
2310 }
2311 }
2312 else pcA = cEntries_p;
2313 }
2314
2315 switch (eigCompMode)
2316 {
2317 case _davidson :
2318 eigenDavidsonSolve<complex_t>(pcA, pB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2319 break;
2320 default:
2321 eigenKrylovSchurSolve<complex_t>(pcA, pB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2322 break;
2323 }
2324
2325 if ( pcA != cEntries_p) delete pcA;
2326 }
2327
2328 if(0 != rmEntries_p)
2329 {
2330 where("eigenSolve(MatrixEntry, ...)");
2331 error("matrixentry_matrixofmatrices_not_handled");
2332 }
2333 if(0 != cmEntries_p)
2334 {
2335 where("eigenSolve(MatrixEntry, ...)");
2336 error("matrixentry_matrixofmatrices_not_handled");
2337 }
2338
2339 std::vector<std::pair<complex_t, VectorEntry*> > res;
2340 for (number_t i = 0; i < eigenVec.size(); ++i)
2341 {
2342 if (isShift)
2343 {
2344 if (0 != rEntries_p) res.push_back(std::make_pair(realShift + 1.0/eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2345 else res.push_back(std::make_pair(cplxShift + 1.0/eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2346 }
2347 else
2348 {
2349 if ("SM" == which) res.push_back(std::make_pair(1.0/eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2350 else res.push_back(std::make_pair(eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2351 }
2352 }
2353
2354 return (res);
2355 }
2356
2357
2358 //-----------------------------------------------------------------------------------------------------------------------------
2359 /*! Resolve an eigen problem with different method
2360 * This function is a wrapper of different eigenSolvers of class LargeMatrix (e.g: eigenDavidsonSolver, eigenKrylovSchurSolver, ...)
2361 * \param[in] pB MatrixEntry containing the matrix B in the eigen problem A*X = lambda*B*X
2362 * \param[in] eigCompMode Computation mode of eigensolver
2363 * \param[in] nev The number of eigen values and eigenSolver searched for
2364 * \param[in] tol Tolerance
2365 * \param[in] which Specification of which eigen values are returned. Largest-LM, Smallest-SM
2366 * \param[in] sigma shift value used in shift mode. In case of real shift, the real part of sigma will be used
2367 * \param[in] isRealShift Specify if real shift is used
2368 * \param[in] isShift Specify if real or complex shift is used */
eigenSolve(const MatrixEntry * pB,EigenComputationalMode eigCompMode,number_t nev,real_t tol,string_t which,complex_t sigma,bool isRealShift,bool isShift)2369 std::vector<std::pair<complex_t, VectorEntry* > > MatrixEntry::eigenSolve(const MatrixEntry* pB, EigenComputationalMode eigCompMode,
2370 number_t nev, real_t tol, string_t which, complex_t sigma, bool isRealShift, bool isShift)
2371 {
2372 real_t realShift = real(sigma);
2373 complex_t cplxShift = sigma;
2374 FactorizationType fac = _noFactorization;
2375 bool isInverted = false;
2376 LargeMatrix<real_t>* prA = rEntries_p, *prB = pB->rEntries_p;
2377 LargeMatrix<complex_t>* pcA = cEntries_p, *pcB = pB->cEntries_p;
2378 std::vector<std::pair<complex_t,Vector<complex_t> > > eigenVec;
2379
2380 if ((0 != rEntries_p) && (0 != pB->rEntries_p)) //scalar real matrix
2381 {
2382 if (isShift) // shift != 0
2383 {
2384 LargeMatrix<real_t>* tmpB = new LargeMatrix<real_t>(*(pB->rEntries_p));
2385 *tmpB *= -realShift;
2386 prA = addMatrixMatrixSkyline(*rEntries_p, *tmpB);
2387
2388 if (_symmetric == prA->sym)
2389 {
2390 prA->ldltFactorize();
2391 fac = _ldlt;
2392 }
2393 else
2394 {
2395 prA->luFactorize();
2396 fac = _lu;
2397 }
2398 isInverted = true;
2399 delete tmpB;
2400 }
2401 else
2402 {
2403 if ("SM" == which)
2404 {
2405 if (_skyline != rEntries_p->storageType()) prA = new LargeMatrix<real_t>(*rEntries_p, true);
2406 else prA = new LargeMatrix<real_t>(*rEntries_p);
2407 if (_skyline != prA->storageType()) prA->toSkyline();
2408 if (_symmetric == prA->sym)
2409 {
2410 prA->ldltFactorize();
2411 fac = _ldlt;
2412 }
2413 else
2414 {
2415 prA->luFactorize();
2416 fac = _lu;
2417 }
2418 isInverted = true;
2419 }
2420 else
2421 {
2422 prA = rEntries_p;
2423 if (_krylovSchur == eigCompMode)
2424 {
2425 if (_skyline != pB->rEntries_p->storageType())
2426 {
2427 prB = new LargeMatrix<real_t>(*(pB->rEntries_p), true);
2428 prB->toSkyline();
2429 }
2430 else prB = new LargeMatrix<real_t>(*(pB->rEntries_p));
2431
2432 if (_symmetric == prB->sym)
2433 {
2434 prB->ldltFactorize();
2435 fac = _ldlt;
2436 }
2437 else
2438 {
2439 prB->luFactorize();
2440 fac = _lu;
2441 }
2442 isInverted = true;
2443 }
2444 }
2445 }
2446
2447 switch (eigCompMode)
2448 {
2449 case _davidson :
2450 eigenDavidsonSolve<real_t>(prA, prB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2451 break;
2452 default:
2453 eigenKrylovSchurSolve<real_t>(prA, prB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2454 break;
2455 }
2456
2457 if (prA != rEntries_p) delete prA;
2458 if (prB != pB->rEntries_p) delete prB;
2459 }
2460
2461 if ((0 != cEntries_p) && (0 != pB->cEntries_p)) //scalar complex matrix
2462 {
2463 if (isShift)
2464 {
2465 LargeMatrix<complex_t>* tmpB = new LargeMatrix<complex_t>(*(pB->cEntries_p));
2466 if (isRealShift) *tmpB *= -realShift;
2467 else *tmpB *= -cplxShift;
2468 pcA = addMatrixMatrixSkyline(*cEntries_p, *tmpB);
2469 if (_selfAdjoint == pcA->sym)
2470 {
2471 pcA->ldlstarFactorize();
2472 fac = _ldlstar;
2473 }
2474 else if (_symmetric == pcA->sym)
2475 {
2476 pcA->ldltFactorize();
2477 fac = _ldlt;
2478 }
2479 else
2480 {
2481 pcA->luFactorize();
2482 fac = _lu;
2483 }
2484 isInverted = true;
2485 delete tmpB;
2486 }
2487 else
2488 {
2489 if ("SM" == which)
2490 {
2491 if (_skyline != cEntries_p->storageType()) pcA = new LargeMatrix<complex_t>(*cEntries_p, true);
2492 else pcA = new LargeMatrix<complex_t>(*cEntries_p);
2493 if (_skyline != pcA->storageType()) pcA->toSkyline();
2494 if (_selfAdjoint == pcA->sym)
2495 {
2496 pcA->ldlstarFactorize();
2497 fac = _ldlstar;
2498 }
2499 else if (_symmetric == pcA->sym)
2500 {
2501 pcA->ldltFactorize();
2502 fac = _ldlt;
2503 }
2504 else
2505 {
2506 pcA->luFactorize();
2507 fac = _lu;
2508 }
2509 isInverted = true;
2510 }
2511 else
2512 {
2513 pcA = cEntries_p;
2514 if (_krylovSchur == eigCompMode)
2515 {
2516 if (_skyline != pB->cEntries_p->storageType())
2517 {
2518 pcB = new LargeMatrix<complex_t>(*(pB->cEntries_p), true);
2519 pcB->toSkyline();
2520 }
2521 else pcB = new LargeMatrix<complex_t>(*(pB->cEntries_p));
2522
2523 if (_selfAdjoint == pcB->sym)
2524 {
2525 pcB->ldlstarFactorize();
2526 fac = _ldlstar;
2527 }
2528 else if (_symmetric == pcB->sym)
2529 {
2530 pcB->ldltFactorize();
2531 fac = _ldlt;
2532 }
2533 else
2534 {
2535 pcB->luFactorize();
2536 fac = _lu;
2537 }
2538 isInverted = true;
2539 }
2540 }
2541 }
2542
2543 switch (eigCompMode)
2544 {
2545 case _davidson :
2546 eigenDavidsonSolve<complex_t>(pcA, pcB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2547 break;
2548 default:
2549 eigenKrylovSchurSolve<complex_t>(pcA, pcB, eigenVec, nev, tol, which, isInverted, fac, isShift);
2550 break;
2551 }
2552
2553 if (pcA != cEntries_p) delete pcA;
2554 if (pcB != pB->cEntries_p) delete pcB;
2555 }
2556
2557 if((0 != rmEntries_p) || (0 != pB->rmEntries_p))
2558 {
2559 where("eigenSolve(MatrixEntry, ...)");
2560 error("matrixentry_matrixofmatrices_not_handled");
2561 }
2562 if((0 != cmEntries_p) || (0 != pB->cmEntries_p))
2563 {
2564 where("eigenSolve(MatrixEntry, ...)");
2565 error("matrixentry_matrixofmatrices_not_handled");
2566 }
2567
2568 std::vector<std::pair<complex_t, VectorEntry*> > res;
2569 for (number_t i = 0; i < eigenVec.size(); ++i)
2570 {
2571 if (isShift)
2572 {
2573 if (0 != rEntries_p) res.push_back(std::make_pair(realShift + 1.0/eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2574 else res.push_back(std::make_pair(cplxShift + 1.0/eigenVec[i].first,new VectorEntry(eigenVec[i].second)));
2575 }
2576 else
2577 {
2578 if ("SM" == which) res.push_back(std::make_pair(1.0/eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2579 else res.push_back(std::make_pair(eigenVec[i].first, new VectorEntry(eigenVec[i].second)));
2580 }
2581 }
2582
2583 return (res);
2584 }
2585
2586 } //end of namespace xlifepp
2587