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