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 RowDenseStorage.cpp
19   \authors D. Martin, E. Lunéville, NGUYEN Manh Ha, N. Kielbasiewicz
20   \since 21 jun 2011
21   \date 21 feb 2013
22 
23   \brief Implementation of xlifepp::RowDenseStorage class and functionnalities
24 */
25 
26 #include "RowDenseStorage.hpp"
27 #include "utils.h"
28 #include <functional>
29 
30 namespace xlifepp
31 {
32 /*---------------------------------------------------------------------------------------
33   Constructors, destructor
34   ---------------------------------------------------------------------------------------*/
35 // default constructor
RowDenseStorage(string_t id)36 RowDenseStorage::RowDenseStorage(string_t id)
37   : DenseStorage(_row, id) {}
38 
39 // constructor for square structure (number of rows)
RowDenseStorage(number_t nr,string_t id)40 RowDenseStorage::RowDenseStorage(number_t nr, string_t id)
41   : DenseStorage(_row, nr, id) {}
42 
43 // constructor for rectangular structure (number of rows/columns)
RowDenseStorage(number_t nr,number_t nc,string_t id)44 RowDenseStorage::RowDenseStorage(number_t nr, number_t nc, string_t id)
45   : DenseStorage(_row, nr, nc, id) {}
46 
47 // // constructor from a SymDenseStorage
48 // RowDenseStorage::RowDenseStorage(const SymDenseStorage& sd)
49 // : DenseStorage(_row, sd.numberOfRows()) {}
50 
51 // // constructor from a SymmDenseStorage
52 // RowDenseStorage::RowDenseStorage(const DualDenseStorage& dd)
53 // : DenseStorage(_row, dd.numberOfRows(), dd.numberOfColumns()) {}
54 
55 /*--------------------------------------------------------------------------------
56  access operator to position of (i,j) coefficients (return 0 if outside)
57  This DIRECT access to (i,j) pointer SHOULD NOT be used in matrix computation
58  where SEQUENTIAL access MUST ALWAYS be used and is only provided for tests.
59  SymType is not used !
60 --------------------------------------------------------------------------------*/
pos(number_t i,number_t j,SymType s) const61 number_t RowDenseStorage::pos(number_t i, number_t j, SymType s) const
62 {
63   if(i == 0 || i > nbRows_ || j == 0 || j > nbCols_) { return 0; }
64   else { return ((i - 1) * nbCols_ + j); }
65 }
66 
67 // access to submatrix adresses, useful for assembling matrices
68 // return the vector of adresses (relative number in storage) stored by row
positions(const std::vector<number_t> & rows,const std::vector<number_t> & cols,std::vector<number_t> & pos,bool errorOn,SymType sym) const69 void RowDenseStorage::positions(const std::vector<number_t>& rows, const std::vector<number_t>& cols,
70                                 std::vector<number_t>& pos, bool errorOn, SymType sym) const
71 {
72   number_t nbp = rows.size() * cols.size();
73   if(pos.size() != nbp) { pos.resize(nbp); }
74   std::vector<number_t>::iterator it_p = pos.begin();
75   for(std::vector<number_t>::const_iterator it_r = rows.begin(); it_r != rows.end(); it_r++)
76     for(std::vector<number_t>::const_iterator it_c = cols.begin(); it_c != cols.end(); it_c++, it_p++)
77     { *it_p = nbCols_ * (*it_r - 1) + *it_c; }
78 }
79 
80 // get (row indices, adress) of col c in set [r1,r2] ## SymType not used ##
getCol(SymType s,number_t c,number_t r1,number_t r2) const81 std::vector<std::pair<number_t, number_t> > RowDenseStorage::getCol(SymType s, number_t c, number_t r1, number_t r2) const
82 {
83     number_t nbr=r2;
84     if(nbr==0) nbr=nbRows_;
85     std::vector<std::pair<number_t, number_t> > rows(nbr-r1+1);
86     std::vector<std::pair<number_t, number_t> >::iterator itrow=rows.begin();
87     for(number_t i=r1;i<=nbr;i++,itrow++) *itrow=std::make_pair(i,(i - 1) * nbCols_+c);
88     return rows;
89 }
90 
91 // get (col indices, adress) of row r in set [c1,c2] ## SymType not used ##
getRow(SymType s,number_t r,number_t c1,number_t c2) const92 std::vector<std::pair<number_t, number_t> > RowDenseStorage::getRow(SymType s, number_t r, number_t c1, number_t c2) const
93 {
94     number_t nbc=c2;
95     if(nbc==0) nbc=nbCols_;
96     std::vector<std::pair<number_t, number_t> > cols(nbc-c1+1);
97     std::vector<std::pair<number_t, number_t> >::iterator itcol=cols.begin();
98     number_t a=(r - 1) * nbCols_+c1;
99     for(number_t j=c1;j<=nbc;j++, a++, itcol++) *itcol=std::make_pair(j,a);
100     return cols;
101 }
102 
103 // create a new scalar RowDense storage from current RowDense storage and submatrix sizes
toScalar(dimen_t nbr,dimen_t nbc)104 RowDenseStorage* RowDenseStorage::toScalar(dimen_t nbr, dimen_t nbc)
105 {
106     return new RowDenseStorage(nbr*nbRows_, nbc*nbCols_, stringId+"_scalar");
107 }
108 
109 /*--------------------------------------------------------------------------------
110  template Matrix x Vector & Vector x Matrix multiplications and specializations
111  result vector has to be sized before
112 --------------------------------------------------------------------------------*/
113 template<typename M, typename V, typename R>
multMatrixVector(const std::vector<M> & m,V * vp,R * rp) const114 void RowDenseStorage::multMatrixVector(const std::vector<M>& m, V* vp, R* rp) const
115 {
116   typename std::vector<M>::const_iterator itm = m.begin() + 1;
117   V* vpe=vp+nbCols_;
118   R* rpe=rp+nbRows_;
119   rowMatrixVector(itm, vp, vpe, rp, rpe);
120 }
121 
122 template<typename M, typename V, typename R>
multMatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const123 void RowDenseStorage::multMatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
124 {
125   //trace_p->push("RowDenseStorage::multMatrixVector");
126   typename std::vector<M>::const_iterator itm = m.begin() + 1;
127   typename std::vector<V>::const_iterator itvb = v.begin(), itve = v.end();
128   typename std::vector<R>::iterator it_rb = r.begin(), it_re = r.end();
129   #ifndef XLIFEPP_WITH_OMP
130   rowMatrixVector(itm, itvb, itve, it_rb, it_re);
131   #else
132   if(Environment::parallelOn()) parallelRowMatrixVector(itm, v, r);
133   else rowMatrixVector(itm, itvb, itve, it_rb, it_re);
134   #endif // XLIFEPP_WITH_OMP
135   //trace_p->pop();
136 }
137 
138 template<typename M, typename V, typename R>
multVectorMatrix(const std::vector<M> & m,V * vp,R * rp) const139 void RowDenseStorage::multVectorMatrix(const std::vector<M>& m, V* vp, R* rp) const
140 {
141   typename std::vector<M>::const_iterator itm = m.begin() + 1;
142   V* vpe=vp+nbCols_;
143   R* rpe=rp+nbRows_;
144   rowVectorMatrix(itm, vp, vpe, rp, rpe);
145 }
146 
147 template<typename M, typename V, typename R>
multVectorMatrix(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const148 void RowDenseStorage::multVectorMatrix(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
149 {
150   //trace_p->push("RowDenseStorage::multMatrixVector");
151   typename std::vector<M>::const_iterator itm = m.begin() + 1;
152   typename std::vector<V>::const_iterator itvb = v.begin(), itve = v.end();
153   typename std::vector<R>::iterator it_rb = r.begin(), it_re = r.end();
154   #ifndef XLIFEPP_WITH_OMP
155   rowVectorMatrix(itm, itvb, itve, it_rb, it_re);
156   #else
157   if(Environment::parallelOn()) parallelMultVectorMatrix(m,v,r);
158   else rowVectorMatrix(itm, itvb, itve, it_rb, it_re);
159   #endif // XLIFEPP_WITH_OMP
160   //trace_p->pop();
161 }
162 
163 // parallel Matrix * Vector (specific)
164 template<typename M, typename V, typename R>
parallelMultVectorMatrix(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const165 void RowDenseStorage::parallelMultVectorMatrix(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
166 {
167      #ifdef XLIFEPP_WITH_OMP
168      //trace_p->push("RowDenseStorage::parallelMultMatrixVector");
169      number_t nr=nbOfRows(), nc=nbOfColumns();
170      number_t nt = 1;
171      #pragma omp parallel for lastprivate(nt)
172       for (number_t i = 0; i < 1; i++)
173         {nt = omp_get_num_threads();}
174 
175      number_t dr = nr/nt;
176      if(dr==0 || nt==1 || !Environment::parallelOn()) //do not use parallel computation
177      {
178          typename std::vector<M>::const_iterator itm = m.begin() + 1;
179          typename std::vector<V>::const_iterator itvb = v.begin(), itve = v.end();
180          typename std::vector<R>::iterator it_rb = r.begin(), it_re = r.end();
181          rowVectorMatrix(itm, itvb, itve, it_rb, it_re);
182          //trace_p->pop();
183          return;
184      }
185      std::vector<std::vector<R> > res(nt, std::vector<R>(nc, 0.*(v[0]*m[1])));  //nt temporary res vector
186      #pragma omp parallel for
187      for(number_t t=0; t<nt; ++t)  //partial product in parallel
188      {
189          typename std::vector<M>::const_iterator itm = m.begin() + ( 1 + t*dr*nc);
190          typename std::vector<R>::iterator itrb = res[t].begin(), itre = res[t].end(), itr;
191          typename std::vector<V>::const_iterator itvb = v.begin()+ t*dr, itve = itvb + dr, itv;
192          if(t==nt-1) itve=v.end();
193          for(itv = itvb; itv != itve; ++itv)
194            for(itr = itrb; itr != itre; ++itr, ++itm)  *itr += *itm * *itv;
195      }
196      typename std::vector<R>::iterator itrb = r.begin(), itre = r.end(), itr;
197      typename std::vector<R>::iterator itrp;
198      for(itr = itrb; itr != itre; ++itr) { *itr *= 0; }
199      for(number_t t=0; t<nt; ++t) //accumulate in serial
200      {
201          itrp = res[t].begin();
202          for(itr=itrb; itr!=itre; ++itr, ++itrp) *itr+=*itrp;
203      }
204      //trace_p->pop();
205      #endif // XLIFEPP_WITH_OMP
206 }
207 
208 /*-----------------------------------------------------------------------
209               triangular part matrix * vector
210 --------------------------------------------------------------------------*/
211 
212 template<typename M, typename V, typename R>
lowerMatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const213 void RowDenseStorage::lowerMatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
214 {
215     r.assign(nbRows_,R(0));  //to reset to 0
216     typename std::vector<M>::const_iterator itmb=m.begin()+1, itm;
217     typename std::vector<V>::const_iterator itv=v.begin();
218     #ifdef XLIFEPP_WITH_OMP
219     #pragma omp parallel for firstprivate(itv,itm) schedule(dynamic)
220     #endif // XLIFEPP_WITH_OMP
221     for(number_t i=0;i<nbRows_; i++)
222        {
223            itv=v.begin();
224            itm=itmb+i*nbCols_;
225            R ri=R(0);
226            for(number_t j=0;j<=std::min(i,nbCols_-1);j++, ++itv, ++itm) ri+= *itm * *itv;
227            r[i]=ri;
228        }
229 }
230 
231 template<typename M, typename V, typename R>
lowerD1MatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const232 void RowDenseStorage::lowerD1MatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
233 {
234     r.assign(nbRows_,R(0));  //to reset to 0
235     typename std::vector<M>::const_iterator itmb=m.begin()+1, itm;
236     typename std::vector<V>::const_iterator itv=v.begin();
237     #ifdef XLIFEPP_WITH_OMP
238     #pragma omp parallel for firstprivate(itv,itm) schedule(dynamic)
239     #endif // XLIFEPP_WITH_OMP
240     for(number_t i=0;i<nbRows_; i++)
241        {
242 
243            itv=v.begin();
244            itm=itmb+i*nbCols_;
245            R ri=R(0);
246            for(number_t j=0;j<std::min(i,nbCols_);j++, ++itv, ++itm) ri+= *itm * *itv;
247            if(i<nbCols_) ri+=*itv;
248            r[i]=ri;
249        }
250 }
251 
252 template<typename M, typename V, typename R>
upperMatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const253 void RowDenseStorage::upperMatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
254 {
255     r.assign(nbRows_,R(0));  //to reset to 0
256     typename std::vector<M>::const_iterator itmb=m.begin()+1, itm;
257     typename std::vector<V>::const_iterator itv=v.begin();
258     #ifdef XLIFEPP_WITH_OMP
259     #pragma omp parallel for firstprivate(itv,itm) schedule(dynamic)
260     #endif // XLIFEPP_WITH_OMP
261     for(number_t i=0;i<std::min(nbRows_,nbCols_); i++)
262        {
263            itv=v.begin()+i;
264            itm=itmb+(i*nbCols_+i);
265            R ri=R(0);
266            for(number_t j=i;j<nbCols_;j++, ++itv, ++itm) ri+= *itm * *itv;
267            r[i]=ri;
268        }
269 }
270 
271 template<typename M, typename V, typename R>
upperD1MatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const272 void RowDenseStorage::upperD1MatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
273 {
274     r.assign(nbRows_,R(0));  //to reset to 0
275     typename std::vector<M>::const_iterator itmb=m.begin()+1, itm;
276     typename std::vector<V>::const_iterator itv=v.begin();
277     #ifdef XLIFEPP_WITH_OMP
278     #pragma omp parallel for firstprivate(itv,itm) schedule(dynamic)
279     #endif // XLIFEPP_WITH_OMP
280     for(number_t i=0;i<std::min(nbRows_,nbCols_); i++)
281        {
282            itv=v.begin()+i;
283            R ri=*itv; itv++;
284            itm=itmb+(i*nbCols_+i+1);
285            for(number_t j=i+1;j<nbCols_;j++, ++itv, ++itm) ri+= *itm * *itv;
286            r[i]=ri;
287        }
288 }
289 
290 template<typename M, typename V, typename R>
diagonalMatrixVector(const std::vector<M> & m,const std::vector<V> & v,std::vector<R> & r) const291 void RowDenseStorage::diagonalMatrixVector(const std::vector<M>& m, const std::vector<V>& v, std::vector<R>& r) const
292 {
293 
294     if(nbRows_>nbCols_) r.assign(nbRows_,R(0));  //to reset to 0
295     else r.resize(nbRows_);
296     typename std::vector<M>::const_iterator itm=m.begin()+1;
297     typename std::vector<V>::const_iterator itv=v.begin();
298     typename std::vector<R>::iterator itr=r.begin();
299     for(number_t i=0;i<std::min(nbRows_,nbCols_);i++, ++itv,++itr, itm+=nbCols_) *itr = *itm * *itv;
300 }
301 
302 
303 /*--------------------------------------------------------------------------------
304  print RowDense matrix to ostream, according to type of values of matrix
305  printScalarEntries is defined in DenseStorage class
306 --------------------------------------------------------------------------------*/
printEntries(std::ostream & os,const std::vector<real_t> & m,number_t vb,const SymType sym) const307 void RowDenseStorage::printEntries(std::ostream& os, const std::vector<real_t>& m, number_t vb, const SymType sym) const
308 {
309   std::vector<real_t>::const_iterator itm = m.begin() + 1;
310   printScalarEntries(itm, nbRows_, nbCols_, entriesPerRow,
311                        entryWidth, entryPrec, "row", vb, os);
312 }
313 
printEntries(std::ostream & os,const std::vector<complex_t> & m,number_t vb,const SymType sym) const314 void RowDenseStorage::printEntries(std::ostream& os, const std::vector<complex_t>& m, number_t vb, const SymType sym) const
315 {
316   std::vector<complex_t>::const_iterator itm = m.begin() + 1;
317   printScalarEntries(itm, nbRows_, nbCols_, entriesPerRow / 2,
318                      2 * entryWidth + 1, entryPrec, "row", vb, os);
319 }
320 
printEntries(std::ostream & os,const std::vector<Vector<real_t>> & m,number_t vb,const SymType sym) const321 void RowDenseStorage::printEntries(std::ostream& os, const std::vector< Vector<real_t> >& m, number_t vb, const SymType sym) const
322 {error("storage_novector", "ColDenseStorage::printEntries");}
323 
printEntries(std::ostream & os,const std::vector<Vector<complex_t>> & m,number_t vb,const SymType sym) const324 void RowDenseStorage::printEntries(std::ostream& os, const std::vector< Vector<complex_t> >& m, number_t vb, const SymType sym) const
325 {error("storage_novector", "ColDenseStorage::printEntries");}
326 
printEntries(std::ostream & os,const std::vector<Matrix<real_t>> & m,number_t vb,const SymType sym) const327 void RowDenseStorage::printEntries(std::ostream& os, const std::vector< Matrix<real_t> >& m, number_t vb, const SymType sym) const
328 {
329   std::vector< Matrix<real_t> >::const_iterator itm = m.begin() + 1;
330   printMatrixEntries(itm, nbRows_, nbCols_, "row", vb, os);
331 }
printEntries(std::ostream & os,const std::vector<Matrix<complex_t>> & m,number_t vb,const SymType sym) const332 void RowDenseStorage::printEntries(std::ostream& os, const std::vector< Matrix<complex_t> >& m, number_t vb, const SymType sym) const
333 {
334   std::vector< Matrix<complex_t> >::const_iterator itm = m.begin() + 1;
335   printMatrixEntries(itm, nbRows_, nbCols_, "row", vb, os);
336 }
337 
338 // Set the Diagonal with a specific value of DualDense and SymDense
339 template<typename T>
setDiagValueRowDense(std::vector<T> & v,const T m)340 void RowDenseStorage::setDiagValueRowDense(std::vector<T>& v, const T m)
341 {
342   typename std::vector<T>::iterator it = v.begin() + 1;
343   number_t diagSize = diagonalSize() + 1;
344   *it = m;
345   for (number_t k = 1; k < (diagSize - 1); k++) { it += diagSize; (*it) = m;}
346 }
347 
348 /*!
349   Add two matrices
350   \param m1 vector values_ of first matrix
351   \param m2 vector values_ of second matrix
352   \param r vector values_ of result matrix
353  */
354 template<typename M1, typename M2, typename R>
addMatrixMatrix(const std::vector<M1> & m1,const std::vector<M2> & m2,std::vector<R> & r) const355 void RowDenseStorage::addMatrixMatrix(const std::vector<M1>& m1, const std::vector<M2>& m2, std::vector<R>& r) const
356 {
357   trace_p->push("RowDenseStorage::addMatrixMatrix");
358   typename std::vector<M1>::const_iterator itm1 = m1.begin() + 1;
359   typename std::vector<M2>::const_iterator itm2 = m2.begin() + 1;
360   typename std::vector<R>::iterator it_rb = r.begin() + 1, it_re = r.end();
361   sumMatrixMatrix(itm1, itm2, it_rb, it_re);
362   trace_p->pop();
363 }
364 
365 /*!
366    Extract and convert matrix storage to UMFPack format (Matlab sparse matrix)
367    \param m1 vector values_ current matrix
368    \param colPtUmf vector column Pointer of UMFPack format
369    \param rowIdxUmf vector row Index of UMFPack format
370    \param resultUmf vector values of UMFPack format
371  */
372 template<typename M1, typename Idx>
toUmfPack(const std::vector<M1> & m1,std::vector<Idx> & colPtUmf,std::vector<Idx> & rowIdxUmf,std::vector<M1> & resultUmf) const373 void RowDenseStorage::toUmfPack(const std::vector<M1>& m1, std::vector<Idx>& colPtUmf, std::vector<Idx>& rowIdxUmf, std::vector<M1>& resultUmf) const
374 {
375     // Resize column pointer as dualCs's column pointer size
376     colPtUmf.clear();
377     colPtUmf.resize(nbCols_+1, Idx(0));
378 
379     // Because colPointer always begins with 0, so need to to count from the second position
380     typename std::vector<Idx>::iterator itbColPtUmf = colPtUmf.begin(), itColPtUmf;
381 
382     typename std::vector<M1>::const_iterator itbval = m1.begin()+1;
383     typename std::vector<M1>::const_iterator itval, iterange, itbrange;
384 
385     typename std::list<M1>::iterator itLVal;
386     std::list<number_t>::iterator itLRow;
387 
388     std::list<M1> listValues;
389     std::list<number_t> listRowIdx;
390 
391     std::vector<Idx> nbNzCol(nbCols_, Idx(0));
392     typename std::vector<Idx>::const_iterator itbNzCol = nbNzCol.begin(), iteNzCol = nbNzCol.end(), itNzCol;
393 
394     for (int_t rowIdx = nbRows_-1; rowIdx  >= 0; --rowIdx) {
395         itval = itbrange = itbval + rowIdx*nbCols_;
396         iterange = itbrange + nbCols_;
397 
398         while (itval != iterange) {
399             itval = std::find_if(itval, iterange, std::bind2nd(std::not_equal_to<M1>(), M1(0)));
400             if (itval != iterange){
401                 number_t pos = itval - itbrange;
402 
403                 ++nbNzCol[pos];
404                 itNzCol = itbNzCol + pos;
405                 itColPtUmf = itbColPtUmf + pos;
406 
407                 std::transform(itNzCol, iteNzCol, itColPtUmf, itColPtUmf+1, std::plus<Idx>());
408 
409                 itLRow = listRowIdx.begin() ;
410                 itLVal = listValues.begin();
411                 std::advance(itLRow, *itColPtUmf);
412                 std::advance(itLVal, *itColPtUmf);
413 
414                 listValues.insert(itLVal, *itval);
415                 listRowIdx.insert(itLRow, rowIdx);
416 
417                 ++itval;
418             }
419         }
420     }
421 
422     resultUmf.resize(listValues.size());
423     std::copy(listValues.begin(), listValues.end(), resultUmf.begin());
424 
425     rowIdxUmf.resize(listRowIdx.size());
426     std::copy(listRowIdx.begin(), listRowIdx.end(), rowIdxUmf.begin());
427 }
428 
429 } // end of namespace xlifepp
430 
431