G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsSparseMatrix.h
Go to the documentation of this file.
1
14# pragma once
15
16// Assumes that Eigen library has been already included
17
18namespace gismo
19{
20
32template<typename T>
33class gsSparseEntries : public std::vector<gsEigen::Triplet<T,index_t> >
34{
35public:
36 typedef gsEigen::Triplet<T,index_t> Triplet;
37 typedef std::vector<gsEigen::Triplet<T,index_t> > Base;
38
39 typedef typename Base::iterator iterator;
40public:
41
42 inline void add( int i, int j, T value )
43 { this->push_back( Triplet(i,j,value) ); }
44
45 inline void addSorted(int i, int j, T value = 0)
46 {
47 Triplet t(i,j,value);
48 iterator pos = std::lower_bound(Base::begin(), Base::end(), t, compTriplet );
49 if ( pos == Base::end() || (pos->row() != t.row() && pos->col() !=t.col()) )// If not found
50 Base::insert(pos, t);
51 }
52
53protected:
54 // comparison operator for triplet struct, used to introduce columnwise lex-ordering.
55 struct _compTriplet
56 {
57 bool operator() (const Triplet & left, const Triplet & right)
58 {
59 return (left.col() < right.col()) ||
60 (left.col() == right.col() && left.row() < right.row()) ;
61 }
62 } compTriplet ;
63
64};
65
72template<typename T, int _Options, typename _Index>
74{
75 typedef gsEigen::SparseMatrix<T,_Options,_Index> SparseMatrix;
76 static const int IsRowMajor = SparseMatrix::IsRowMajor;
77
78public:
80 : m_values(NULL), m_indices(NULL),
81 m_end(NULL) , m_outer(0)
82 { }
83
84 gsSparseMatrixIter(const SparseMatrix& mat, const _Index outer)
85 : m_outer(outer)
86 {
87 const _Index oind = mat.outerIndexPtr()[outer];
88 m_values = mat.valuePtr() + oind;
89 m_indices = mat.innerIndexPtr() + oind;
90 m_end = mat.isCompressed() ?
91 mat.innerIndexPtr() + mat.outerIndexPtr()[outer+1] :
92 mat.innerIndexPtr() + oind + mat.innerNonZeroPtr()[outer];
93 }
94
95 inline gsSparseMatrixIter& operator++()
96 { ++m_values; ++m_indices; return *this; }
97
98 inline const T& value() const { return *m_values; }
99 inline T& valueRef() { return const_cast<T&>(*m_values); }
100
101 inline _Index index() const { return *m_indices; }
102 inline _Index outer() const { return m_outer; }
103 inline _Index row() const { return IsRowMajor ? m_outer : index(); }
104 inline _Index col() const { return IsRowMajor ? index() : m_outer; }
105
106 inline operator bool() const { return (m_indices < m_end); }
107
108protected:
109 const T * m_values;
110 const _Index * m_indices;
111 const _Index * m_end;
112 _Index m_outer;
113};
114
135// Export the result to a file: saveAsBitmap(...);
136
137template<typename T, int _Options, typename _Index>
138class gsSparseMatrix : public gsEigen::SparseMatrix<T,_Options,_Index>
139{
140public:
141 typedef gsEigen::SparseMatrix<T,_Options,_Index> Base;
142
144
145 // Type pointing to a block of the sparse matrix
146 typedef typename gsEigen::Block<Base> Block;
147
148 // Type pointing to a const block of the sparse matrix
149 typedef typename gsEigen::Block<const Base> constBlock;
150
151 // Type pointing to a block view of the sparse matrix
153
154 // Type pointing to a block view of the sparse matrix
156
158 typedef memory::shared_ptr<gsSparseMatrix> Ptr;
159
161 typedef memory::unique_ptr<gsSparseMatrix> uPtr;
162
165 typedef typename gsEigen::SparseSelfAdjointView<Base, Lower> fullView;
166
169 typedef typename gsEigen::SparseSelfAdjointView<const Base, Lower> constFullView;
170
171public:
173
174 gsSparseMatrix(_Index rows, _Index cols) ;
175
177 template<typename OtherDerived>
178 gsSparseMatrix(const gsEigen::EigenBase<OtherDerived>& other) : Base(other) { }
179
181 template<typename OtherDerived, unsigned int UpLo>
182 gsSparseMatrix(const gsEigen::SparseSelfAdjointView<OtherDerived, UpLo>& other)
183 : Base(other) { }
184
186 template<typename OtherDerived>
187 gsSparseMatrix(const gsEigen::MatrixBase<OtherDerived>& other) : Base(other) { }
188
190 template<typename OtherDerived>
191 gsSparseMatrix(const gsEigen::SparseMatrixBase<OtherDerived>& other) : Base(other) { }
192
194 template<typename OtherDerived>
195 gsSparseMatrix(const gsEigen::ReturnByValue<OtherDerived>& other) : Base(other) { }
196
197#if !EIGEN_HAS_RVALUE_REFERENCES
198 // swap assignment operator
199 gsSparseMatrix & operator=(gsSparseMatrix other)
200 {
201 this->swap(other);
202 return *this;
203 }
204
205 template<typename OtherDerived, int a>
206 gsSparseMatrix & operator=(const gsEigen::SparseSymmetricPermutationProduct<OtherDerived, a>& other)
207 {
208 this->Base::operator=(other);
209 return *this;
210 }
211#else
212# ifdef _MSC_VER
213 template <class EigenExpr>
214 gsSparseMatrix& operator= (const EigenExpr & other)
215 {
216 this->Base::operator=(other);
217 return *this;
218 }
219# else
220 using Base::operator=;
221# endif
222
223 // Avoid default keyword for MSVC<2013
224 // https://msdn.microsoft.com/en-us/library/hh567368.aspx
225 gsSparseMatrix(const gsSparseMatrix& other) : Base(other)
226 { Base::operator=(other); }
227 gsSparseMatrix& operator= (const gsSparseMatrix & other)
228 { Base::operator=(other); return *this; }
229
230 gsSparseMatrix(gsSparseMatrix&& other)
231 { gsSparseMatrix::operator=(std::forward<gsSparseMatrix>(other)); }
232
233 gsSparseMatrix & operator=(gsSparseMatrix&& other)
234 {
235 this->swap(other);
236 other.clear();
237 return *this;
238 }
239
240#endif
241
248 {
249 uPtr m(new gsSparseMatrix);
250 m->swap(*this);
251 return m;
252 }
253
256 inline iterator begin(const index_t outer) const { return iterator(*this,outer);}
257
258 void clear()
259 {
260 this->resize(0,0);
261 this->data().squeeze();
262 }
263
264 std::pair<index_t,index_t> dim() const
265 { return std::make_pair(this->rows(), this->cols() ); }
266
267 void reservePerColumn(const index_t nz)
268 {
269 Base::reserve(gsVector<index_t>::Constant(this->outerSize(), nz));
270 }
271
272 void setFrom( gsSparseEntries<T> const & entries) ;
273
274 inline T at (_Index i, _Index j ) const { return this->coeff(i,j); }
275 inline T & at (_Index i, _Index j ) { return this->coeffRef(i,j); }
276
277 inline T operator () (_Index i, _Index j ) const { return this->coeff(i,j); }
278 inline T & operator () (_Index i, _Index j ) { return this->coeffRef(i,j); }
279
282 inline void addTo(_Index i, _Index j, const T val)
283 {
284 if (0!=val) this->coeffRef(i,j) += val;
285 }
286
289 inline void insertTo(_Index i, _Index j, const T val)
290 {
291 if (0!=val)
292 this->insert(i,j) = val;
293 }
294
295 inline bool isExplicitZero(_Index row, _Index col) const
296 {
297 const _Index outer = gsSparseMatrix::IsRowMajor ? row : col;
298 const _Index inner = gsSparseMatrix::IsRowMajor ? col : row;
299 const _Index end = this->m_innerNonZeros ?
300 this->m_outerIndex[outer] + this->m_innerNonZeros[outer] : this->m_outerIndex[outer+1];
301 const _Index id = this->m_data.searchLowerIndex(this->m_outerIndex[outer], end-1, inner);
302 return !((id<end) && ( this->m_data.index(id)==inner));
303 }
304
306 inline void insertExplicitZero(_Index row, _Index col)
307 {
308 GISMO_ASSERT(row>=0 && row<this->rows() && col>=0 && col<this->cols(), "Invalid row/col index.");
309 const _Index outer = gsSparseMatrix::IsRowMajor ? row : col;
310 const _Index inner = gsSparseMatrix::IsRowMajor ? col : row;
311 const _Index start = this->m_outerIndex[outer];
312 const _Index end = this->m_innerNonZeros ?
313 this->m_outerIndex[outer] + this->m_innerNonZeros[outer] : this->m_outerIndex[outer+1];
314 if(end<=start)
315 { this->insert(row,col); return; }
316 const _Index p = this->m_data.searchLowerIndex(start,end-1,inner);
317 if(! ((p<end) && (this->m_data.index(p)==inner)) )
318 this->insert(row,col);
319 }
320
321 inline T& coeffUpdate(_Index row, _Index col)
322 {
323 GISMO_ASSERT(row>=0 && row<this->rows() && col>=0 && col<this->cols(), "Invalid row/col index.");
324 const _Index outer = gsSparseMatrix::IsRowMajor ? row : col;
325 _Index start = this->m_outerIndex[outer];
326 _Index end = this->m_innerNonZeros ? this->m_outerIndex[outer] + this->m_innerNonZeros[outer]
327 : this->m_outerIndex[outer+1];
328 const _Index inner = gsSparseMatrix::IsRowMajor ? col : row;
329 const _Index p = this->m_data.searchLowerIndex(start,end-1,inner);
330 if((p<end) && (this->m_data.index(p)==inner))
331 return this->m_data.value(p);
332 GISMO_ERROR("(row,col) = ("<< row <<","<<col<<") is not in the matrix (sparsity pattern).");
333 }
334
337 const gsVector<index_t> & colSizes)
338 {
339 return BlockView(*this, rowSizes, colSizes);
340 }
341
344 const gsVector<index_t> & colSizes) const
345 {
346 return constBlockView(*this, rowSizes, colSizes);
347 }
348
353 {
354 if ( this->isCompressed() )
355 {
356 gsWarn<<"nonZerosPerCol(): Uncompressing the gsSparseMatrix.\n";
357 this->uncompress();
358 }
359 return gsAsConstVector<_Index>(this->innerNonZeroPtr(),this->innerSize());
360 }
361
362 std::string printSparsity() const
363 {
364 std::ostringstream os;
365 os <<"Sparsity: "<< std::fixed << std::setprecision(2)
366 <<(double)100*this->nonZeros()/this->size() <<'%'<<", nnz: "<<this->size() <<"\n";
367 for (index_t i = 0; i!=this->rows(); ++i)
368 {
369 for (index_t j = 0; j!=this->cols(); ++j)
370 os << ( isExplicitZero(i,j) ? "\u00B7" :
371 ( 0 == this->coeff(i,j) ? "o" : "x") );
372 os<<"\n";
373 }
374 return os.str();
375 }
376
378 //template<typename InputIterator>
379 //void setPattern(const InputIterator& begin, const InputIterator& end)
380
382
386 template<class container>
387 container innerOf(const container & outer) const
388 {
389 std::vector<bool> v(this->innerSize(), false);
391 for (typename container::const_iterator k =
392 outer.begin(); k!=outer.end(); ++k )
393 for( mIt = this->begin(*k); mIt; ++mIt)
394 v[mIt.index()] = (0!=mIt.value());
395
396 container inner;
397 inner.reserve( std::count(v.begin(), v.end(), true) );
398 std::vector<bool>::iterator it = std::find(v.begin(),v.end(), true);
399 while (v.end() != it)
400 {
401 inner.push_back(std::distance(v.begin(),it));
402 it = std::find(++it,v.end(), true);
403 }
404 return inner;
405 }
406
409 template<class container>
410 gsMatrix<T> multiplyBy(const container & inner,
411 const container & outer,
412 const gsMatrix<T> & other)
413 {
414 // todo: better implementation
415 return submatrix(inner,outer) * other;
416 }
417
420 template<class container>
421 gsMatrix<T> submatrix(const container & inner,
422 const container & outer) const
423 {
424 const index_t nr = inner.size();
425 const index_t nc = outer.size();
426 gsMatrix<T> result(nr, nc);
427 result.setZero();
428 for (index_t c=0; c!=nc; ++c)
429 {
430 iterator it = begin(outer[c]); //sorted iteration
431 for (index_t r=0; r!=nr && it;)
432 {
433
434 while(it && inner[r] > it.index()) ++it;
435 if (it) while(r!=nr && inner[r] < it.index()) ++r;
436 if (r!=nr)
437 {
438 result(r,c) = it.value();
439 ++r; ++it;
440 }
441 }
442 }
443 return result;
444 }
445
446 gsVector<index_t> nonZerosPerInner(index_t upto = std::numeric_limits<index_t>::max()) const
447 {
448 upto = math::min(upto, this->outerSize());
449 gsVector<index_t> nz(upto);
450 index_t * v = nz.data();
451 for (index_t i = 0; i != upto; ++i, ++v)
452 *v = this->innerVector(i).nonZeros();
453 return nz;
454 }
455
458 {
459 const index_t r = this->rows(), c = this->cols();
460 const index_t ro = other.rows(), co = other.cols();
461 gsSparseMatrix result(r*ro, c*co);
462 if (0 == result.size()) return result;
463 result.reserve(this->nonZerosPerInner()
464 .kron(other.nonZerosPerInner()));
465
466 iterator it1, it2;
467 for (index_t k1=0; k1 != (gsSparseMatrix::IsRowMajor?r:c); ++k1)
468 for (it1 = this->begin(k1); it1; ++it1)
469 for (index_t k2=0; k2 != (gsSparseMatrix::IsRowMajor?ro:co); ++k2)
470 for (it2 = other.begin(k2); it2; ++it2)
471 {
472 const index_t i = it1.row() * ro + it2.row();
473 const index_t j = it1.col() * co + it2.col();
474 result.insert(i,j) = it1.value() * it2.value();
475 }
476 result.makeCompressed();
477 return result;
478 }
479
480private:
481
482 /*
483 The inherited setZero() destroys column-nonzeros structure and
484 can make further computations very slow. Almost equivalent to
485 M.setZero() is:
486 M = gsSparseMatrix(M.rows(), M.cols());
487
488 void setZero();
489 */
490
491}; // class gsSparseMatrix
492
493
494//template<class T>
495//inline void gsSparseEntries<T>::add( int const& i, int const& j, const T & value)
496// { this->push_back( Triplet(i,j,value) ); }
497
498
499template<typename T, int _Options, typename _Index> inline
500gsSparseMatrix<T, _Options, _Index>::gsSparseMatrix() : Base() { }
501
502template<typename T, int _Options, typename _Index> inline
503gsSparseMatrix<T, _Options, _Index>::gsSparseMatrix(_Index rows, _Index cols) : Base(rows,cols) { }
504
505template<typename T, int _Options, typename _Index> inline
506void gsSparseMatrix<T, _Options, _Index>::setFrom( gsSparseEntries<T> const & entries)
507{ this->setFromTriplets(entries.begin(),entries.end() ); }
508
509template<typename T, int _Options, typename _Index> void
511{
513 index_t c_i, c_j;
514 const index_t nr = this->rows();
515 const index_t nc = this->cols();
516
517 gsVector<index_t> piv(nr);
518
519 for (index_t i = 0; i!=nr; ++i)
520 {
521 // pull row(i)
522 R = this->row(i);
523 for (index_t j = 0; j!=i; ++j)
524 {
525 c_j = piv[j];
526 if (c_j != nc )
527 R.tail(nc-c_j) -= R.at(c_j) * this->row(j).tail(nc-c_j);
528 }
529
530 // store row pivot
531 c_i = 0; while (c_i!= nc && 0 == R.at(c_i)) ++c_i;
532 piv[i] = c_i;
533 if (c_i == nc ) continue;
534 R.tail(nc-c_i-1).array() /= R.at(c_i);
535 R.at(c_i) = 1;
536 // push row(i)
537 this->row(i) = R.sparseView();
538 }
539
540 // sort rows wrt pivots
541 bool didSwap;
542 c_i = nr - 1; // last swap done
543 do
544 {
545 didSwap = false;
546 c_j = c_i;
547
548 for( index_t i=0; i != c_j; i++)
549 if( piv[i] > piv[i+1] )
550 {
551 std::swap(piv[i], piv[i+1]);
552 //this->row(i).swap(this->row(i+1));
553 didSwap = true;
554 c_i = i;
555 }
556 } while(didSwap);
557
558 // todo: precompute nz (piv[nz])
559
560 // lower part
561 for (index_t i = 0; i!=nr; ++i)
562 {
563 // pull row(i)
564 R = this->row(i);
565 c_i = piv[i];
566 if (c_i == nc ) break;
567
568 for (index_t j = i+1; j!=nr; ++j) // nr - zr
569 {
570 c_j = piv[j];
571 if ( c_j == nc ) break;
572 R.tail(nc-c_j) -= R.at(c_j) * this->row(j).tail(nc-c_j);
573 }
574 // push row(i)
575 this->row(i) = R.sparseView();
576 }
577}
578
579#ifdef GISMO_WITH_PYBIND11
580
584 template<typename T>
585 void pybind11_init_gsSparseMatrix(pybind11::module &m, const std::string & typestr)
586 {
587 using Class = gsSparseMatrix<T>;
588 std::string pyclass_name = std::string("gsSparseMatrix") + typestr;
589 pybind11::class_<Class>(m, pyclass_name.c_str(), pybind11::buffer_protocol(), pybind11::dynamic_attr())
590 // Constructors
591 .def(pybind11::init<>())
592 .def(pybind11::init<index_t, index_t>())
593 // Member functions
594 .def("size", &Class::size)
595 .def("rows", &Class::rows)
596 .def("cols", &Class::cols)
597 // .def("transpose", &Class::transpose)
598 // .def("addTo", &Class::addTo)
599 // .def("insertTo", &Class::insertTo)
600 .def("toDense", &Class::toDense)
601 ;
602 }
603
604#endif // GISMO_WITH_PYBIND11
605
606} // namespace gismo
607
608
609namespace gsEigen { namespace internal {
610template<typename T, int _Options, typename _Index>
611struct traits<gismo::gsSparseMatrix<T,_Options,_Index> >:
612gsEigen::internal::traits<gsEigen::SparseMatrix<T,_Options,_Index> > { };
613} }
614
615/* *****************************************************************
616#ifdef GISMO_BUILD_LIB
617#ifdef gsMatrix_EXPORT
618#undef EXTERN_CLASS_TEMPLATE
619#define EXTERN_CLASS_TEMPLATE CLASS_TEMPLATE_INST
620#endif
621namespace gismo
622{
623EXTERN_CLASS_TEMPLATE gsSparseMatrix<real_t>;
624}
625#endif
626// *****************************************************************
627*/
Creates a mapped object or data pointer to a const vector without copying data.
Definition gsAsMatrix.h:285
Represents a block-view of the given matrix.
Definition gsMatrixBlockView.h:32
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition gsMatrix.h:211
Class that provides a container for triplets (i,j,value) to be filled in a sparse matrix.
Definition gsSparseMatrix.h:34
Iterator over the non-zero entries of a sparse matrix.
Definition gsSparseMatrix.h:74
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
gsSparseMatrix kron(const gsSparseMatrix &other) const
Returns the Kronecker product of this with other.
Definition gsSparseMatrix.h:457
gsSparseMatrix(const gsEigen::MatrixBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition gsSparseMatrix.h:187
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition gsSparseMatrix.h:247
gsMatrix< T > multiplyBy(const container &inner, const container &outer, const gsMatrix< T > &other)
Definition gsSparseMatrix.h:410
gsAsConstVector< _Index > nonZerosPerCol()
Definition gsSparseMatrix.h:352
gsSparseMatrix(const gsEigen::ReturnByValue< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition gsSparseMatrix.h:195
memory::shared_ptr< gsSparseMatrix > Ptr
Shared pointer for gsSparseMatrix.
Definition gsSparseMatrix.h:158
constBlockView blockView(const gsVector< index_t > &rowSizes, const gsVector< index_t > &colSizes) const
Return a const block view of the matrix with rowSizes and colSizes.
Definition gsSparseMatrix.h:343
gsMatrix< T > submatrix(const container &inner, const container &outer) const
Definition gsSparseMatrix.h:421
memory::unique_ptr< gsSparseMatrix > uPtr
Unique pointer for gsSparseMatrix.
Definition gsSparseMatrix.h:161
iterator begin(const index_t outer) const
Returns an iterator to the first non-zero elemenent of column \ a outer (or row outer if the matrix i...
Definition gsSparseMatrix.h:256
void insertExplicitZero(_Index row, _Index col)
Adds an explicit zero, only if (row,col) is not in the matrix.
Definition gsSparseMatrix.h:306
void addTo(_Index i, _Index j, const T val)
Definition gsSparseMatrix.h:282
void rrefInPlace()
Allocates the sparsity pattern.
Definition gsSparseMatrix.h:510
gsEigen::SparseSelfAdjointView< Base, Lower > fullView
Definition gsSparseMatrix.h:165
gsSparseMatrix(const gsEigen::SparseSelfAdjointView< OtherDerived, UpLo > &other)
This constructor allows constructing a gsSparseMatrix from a selfadjoint view.
Definition gsSparseMatrix.h:182
gsSparseMatrix(const gsEigen::SparseMatrixBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from another sparse expression.
Definition gsSparseMatrix.h:191
container innerOf(const container &outer) const
Definition gsSparseMatrix.h:387
BlockView blockView(const gsVector< index_t > &rowSizes, const gsVector< index_t > &colSizes)
Return a block view of the matrix with rowSizes and colSizes.
Definition gsSparseMatrix.h:336
gsEigen::SparseSelfAdjointView< const Base, Lower > constFullView
Definition gsSparseMatrix.h:169
void insertTo(_Index i, _Index j, const T val)
Definition gsSparseMatrix.h:289
gsSparseMatrix(const gsEigen::EigenBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition gsSparseMatrix.h:178
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
The G+Smo namespace, containing all definitions for the library.