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