G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsSparseMatrix.h
Go to the documentation of this file.
1 
14 # pragma once
15 
16 // Assumes that Eigen library has been already included
17 
18 namespace gismo
19 {
20 
32 template<typename T>
33 class gsSparseEntries : public std::vector<gsEigen::Triplet<T,index_t> >
34 {
35 public:
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;
40 public:
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)
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 
53 protected:
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 
66 
67 
74 template<typename T, int _Options, typename _Index>
76 {
77  typedef gsEigen::SparseMatrix<T,_Options,_Index> SparseMatrix;
78  static const int IsRowMajor = SparseMatrix::IsRowMajor;
79 
80 public:
82  : m_values(NULL), m_indices(NULL),
83  m_end(NULL) , m_outer(0)
84  { }
85 
86  gsSparseMatrixIter(const SparseMatrix& mat, const _Index outer)
87  : m_outer(outer)
88  {
89  const _Index oind = mat.outerIndexPtr()[outer];
90  m_values = mat.valuePtr() + oind;
91  m_indices = mat.innerIndexPtr() + oind;
92  m_end = mat.isCompressed() ?
93  mat.innerIndexPtr() + mat.outerIndexPtr()[outer+1] :
94  mat.innerIndexPtr() + oind + mat.innerNonZeroPtr()[outer];
95  }
96 
97  inline gsSparseMatrixIter& operator++()
98  { ++m_values; ++m_indices; return *this; }
99 
100  inline const T& value() const { return *m_values; }
101  inline T& valueRef() { return const_cast<T&>(*m_values); }
102 
103  inline _Index index() const { return *m_indices; }
104  inline _Index outer() const { return m_outer; }
105  inline _Index row() const { return IsRowMajor ? m_outer : index(); }
106  inline _Index col() const { return IsRowMajor ? index() : m_outer; }
107 
108  inline operator bool() const { return (m_indices < m_end); }
109 
110 protected:
111  const T * m_values;
112  const _Index * m_indices;
113  const _Index * m_end;
114  _Index m_outer;
115 };
116 
137 // Export the result to a file: saveAsBitmap(...);
138 
139 template<typename T, int _Options, typename _Index>
140 class gsSparseMatrix : public gsEigen::SparseMatrix<T,_Options,_Index>
141 {
142 public:
143  typedef gsEigen::SparseMatrix<T,_Options,_Index> Base;
144 
146 
147  // Type pointing to a block of the sparse matrix
148  typedef typename gsEigen::Block<Base> Block;
149 
150  // Type pointing to a const block of the sparse matrix
151  typedef typename gsEigen::Block<const Base> constBlock;
152 
153  // Type pointing to a block view of the sparse matrix
155 
156  // Type pointing to a block view of the sparse matrix
158 
160  typedef memory::shared_ptr<gsSparseMatrix> Ptr;
161 
163  typedef memory::unique_ptr<gsSparseMatrix> uPtr;
164 
167  typedef typename gsEigen::SparseSelfAdjointView<Base, Lower> fullView;
168 
171  typedef typename gsEigen::SparseSelfAdjointView<const Base, Lower> constFullView;
172 
173 public:
174  gsSparseMatrix() ;
175 
176  gsSparseMatrix(_Index rows, _Index cols) ;
177 
179  template<typename OtherDerived>
180  gsSparseMatrix(const gsEigen::EigenBase<OtherDerived>& other) : Base(other) { }
181 
183  template<typename OtherDerived, unsigned int UpLo>
184  gsSparseMatrix(const gsEigen::SparseSelfAdjointView<OtherDerived, UpLo>& other)
185  : Base(other) { }
186 
188  template<typename OtherDerived>
189  gsSparseMatrix(const gsEigen::MatrixBase<OtherDerived>& other) : Base(other) { }
190 
192  template<typename OtherDerived>
193  gsSparseMatrix(const gsEigen::SparseMatrixBase<OtherDerived>& other) : Base(other) { }
194 
196  template<typename OtherDerived>
197  gsSparseMatrix(const gsEigen::ReturnByValue<OtherDerived>& other) : Base(other) { }
198 
199 #if !EIGEN_HAS_RVALUE_REFERENCES
200  // swap assignment operator
201  gsSparseMatrix & operator=(gsSparseMatrix other)
202  {
203  this->swap(other);
204  return *this;
205  }
206 
207  template<typename OtherDerived, int a>
208  gsSparseMatrix & operator=(const gsEigen::SparseSymmetricPermutationProduct<OtherDerived, a>& other)
209  {
210  this->Base::operator=(other);
211  return *this;
212  }
213 #else
214 # ifdef _MSC_VER
215  template <class EigenExpr>
216  gsSparseMatrix& operator= (const EigenExpr & other)
217  {
218  this->Base::operator=(other);
219  return *this;
220  }
221 # else
222  using Base::operator=;
223 # endif
224 
225  // Avoid default keyword for MSVC<2013
226  // https://msdn.microsoft.com/en-us/library/hh567368.aspx
227  gsSparseMatrix(const gsSparseMatrix& other) : Base(other)
228  { Base::operator=(other); }
229  gsSparseMatrix& operator= (const gsSparseMatrix & other)
230  { Base::operator=(other); return *this; }
231 
232  gsSparseMatrix(gsSparseMatrix&& other)
233  { gsSparseMatrix::operator=(std::forward<gsSparseMatrix>(other)); }
234 
235  gsSparseMatrix & operator=(gsSparseMatrix&& other)
236  {
237  this->swap(other);
238  other.clear();
239  return *this;
240  }
241 
242 #endif
243 
250  {
251  uPtr m(new gsSparseMatrix);
252  m->swap(*this);
253  return m;
254  }
255 
258  inline iterator begin(const index_t outer) const { return iterator(*this,outer);}
259 
260  void clear()
261  {
262  this->resize(0,0);
263  this->data().squeeze();
264  }
265 
266  std::pair<index_t,index_t> dim() const
267  { return std::make_pair(this->rows(), this->cols() ); }
268 
269  void reservePerColumn(const index_t nz)
270  {
271  Base::reserve(gsVector<index_t>::Constant(this->outerSize(), nz));
272  }
273 
274  void setFrom( gsSparseEntries<T> const & entries) ;
275 
276  inline T at (_Index i, _Index j ) const { return this->coeff(i,j); }
277  inline T & at (_Index i, _Index j ) { return this->coeffRef(i,j); }
278 
279  inline T operator () (_Index i, _Index j ) const { return this->coeff(i,j); }
280  inline T & operator () (_Index i, _Index j ) { return this->coeffRef(i,j); }
281 
284  inline void addTo(_Index i, _Index j, const T val)
285  {
286  if (0!=val) this->coeffRef(i,j) += val;
287  }
288 
291  inline void insertTo(_Index i, _Index j, const T val)
292  {
293  if (0!=val)
294  this->insert(i,j) = val;
295  }
296 
299  const gsVector<index_t> & colSizes)
300  {
301  return BlockView(*this, rowSizes, colSizes);
302  }
303 
306  const gsVector<index_t> & colSizes) const
307  {
308  return constBlockView(*this, rowSizes, colSizes);
309  }
310 
315  {
316  if ( this->isCompressed() )
317  {
318  gsWarn<<"nonZerosPerCol(): Uncompressing the gsSparseMatrix.\n";
319  this->uncompress();
320  }
321  return gsAsConstVector<_Index>(this->innerNonZeroPtr(),this->innerSize());
322  }
323 
324  std::string printSparsity() const
325  {
326  std::ostringstream os;
327  os <<"Sparsity: "<< std::fixed << std::setprecision(2)
328  <<(double)100*this->nonZeros()/this->size() <<'%'<<", nnz: "<<this->size() <<"\n";
329  for (index_t i = 0; i!=this->rows(); ++i)
330  {
331  for (index_t j = 0; j!=this->cols(); ++j)
332  os<< ( 0 == this->coeff(i,j) ? "\u00B7" : "x");
333  os<<"\n";
334  }
335  return os.str();
336  }
337 
338  void rrefInPlace();
339 
343  template<class container>
344  container innerOf(const container & outer) const
345  {
346  std::vector<bool> v(this->innerSize(), false);
348  for (typename container::const_iterator k =
349  outer.begin(); k!=outer.end(); ++k )
350  for( mIt = this->begin(*k); mIt; ++mIt)
351  v[mIt.index()] = (0!=mIt.value());
352 
353  container inner;
354  inner.reserve( std::count(v.begin(), v.end(), true) );
355  std::vector<bool>::iterator it = std::find(v.begin(),v.end(), true);
356  while (v.end() != it)
357  {
358  inner.push_back(std::distance(v.begin(),it));
359  it = std::find(++it,v.end(), true);
360  }
361  return inner;
362  }
363 
366  template<class container>
367  gsMatrix<T> multiplyBy(const container & inner,
368  const container & outer,
369  const gsMatrix<T> & other)
370  {
371  // todo: better implementation
372  return submatrix(inner,outer) * other;
373  }
374 
377  template<class container>
378  gsMatrix<T> submatrix(const container & inner,
379  const container & outer) const
380  {
381  const index_t nr = inner.size();
382  const index_t nc = outer.size();
383  gsMatrix<T> result(nr, nc);
384  result.setZero();
385  for (index_t c=0; c!=nc; ++c)
386  {
387  iterator it = begin(outer[c]); //sorted iteration
388  for (index_t r=0; r!=nr && it;)
389  {
390 
391  while(it && inner[r] > it.index()) ++it;
392  if (it) while(r!=nr && inner[r] < it.index()) ++r;
393  if (r!=nr)
394  {
395  result(r,c) = it.value();
396  ++r; ++it;
397  }
398  }
399  }
400  return result;
401  }
402 
403  gsVector<index_t> nonZerosPerInner(index_t upto = std::numeric_limits<index_t>::max()) const
404  {
405  upto = math::min(upto, this->outerSize());
406  gsVector<index_t> nz(upto);
407  index_t * v = nz.data();
408  for (index_t i = 0; i != upto; ++i, ++v)
409  *v = this->innerVector(i).nonZeros();
410  return nz;
411  }
412 
414  gsSparseMatrix kron(const gsSparseMatrix& other) const
415  {
416  const index_t r = this->rows(), c = this->cols();
417  const index_t ro = other.rows(), co = other.cols();
418  gsSparseMatrix result(r*ro, c*co);
419  if (0 == result.size()) return result;
420  result.reserve(this->nonZerosPerInner()
421  .kron(other.nonZerosPerInner()));
422 
423  iterator it1, it2;
424  for (index_t k1=0; k1 != (gsSparseMatrix::IsRowMajor?r:c); ++k1)
425  for (it1 = this->begin(k1); it1; ++it1)
426  for (index_t k2=0; k2 != (gsSparseMatrix::IsRowMajor?ro:co); ++k2)
427  for (it2 = other.begin(k2); it2; ++it2)
428  {
429  const index_t i = it1.row() * ro + it2.row();
430  const index_t j = it1.col() * co + it2.col();
431  result.insert(i,j) = it1.value() * it2.value();
432  }
433  result.makeCompressed();
434  return result;
435  }
436 
437 private:
438 
439  /*
440  The inherited setZero() destroys column-nonzeros structure and
441  can make further computations very slow. Almost equivalent to
442  M.setZero() is:
443  M = gsSparseMatrix(M.rows(), M.cols());
444 
445  void setZero();
446  */
447 
448 }; // class gsSparseMatrix
449 
450 
451 //template<class T>
452 //inline void gsSparseEntries<T>::add( int const& i, int const& j, const T & value)
453 // { this->push_back( Triplet(i,j,value) ); }
454 
455 
456 template<typename T, int _Options, typename _Index> inline
457 gsSparseMatrix<T, _Options, _Index>::gsSparseMatrix() : Base() { }
458 
459 template<typename T, int _Options, typename _Index> inline
460 gsSparseMatrix<T, _Options, _Index>::gsSparseMatrix(_Index rows, _Index cols) : Base(rows,cols) { }
461 
462 template<typename T, int _Options, typename _Index> inline
463 void gsSparseMatrix<T, _Options, _Index>::setFrom( gsSparseEntries<T> const & entries)
464 { this->setFromTriplets(entries.begin(),entries.end() ); }
465 
466 template<typename T, int _Options, typename _Index> void
467 gsSparseMatrix<T, _Options, _Index>::rrefInPlace()
468 {
469  gsMatrix<T,1,Dynamic> R;
470  index_t c_i, c_j;
471  const index_t nr = this->rows();
472  const index_t nc = this->cols();
473 
474  gsVector<index_t> piv(nr);
475 
476  for (index_t i = 0; i!=nr; ++i)
477  {
478  // pull row(i)
479  R = this->row(i);
480  for (index_t j = 0; j!=i; ++j)
481  {
482  c_j = piv[j];
483  if (c_j != nc )
484  R.tail(nc-c_j) -= R.at(c_j) * this->row(j).tail(nc-c_j);
485  }
486 
487  // store row pivot
488  c_i = 0; while (c_i!= nc && 0 == R.at(c_i)) ++c_i;
489  piv[i] = c_i;
490  if (c_i == nc ) continue;
491  R.tail(nc-c_i-1).array() /= R.at(c_i);
492  R.at(c_i) = 1;
493  // push row(i)
494  this->row(i) = R.sparseView();
495  }
496 
497  // sort rows wrt pivots
498  bool didSwap;
499  c_i = nr - 1; // last swap done
500  do
501  {
502  didSwap = false;
503  c_j = c_i;
504 
505  for( index_t i=0; i != c_j; i++)
506  if( piv[i] > piv[i+1] )
507  {
508  std::swap(piv[i], piv[i+1]);
509  //this->row(i).swap(this->row(i+1));
510  didSwap = true;
511  c_i = i;
512  }
513  } while(didSwap);
514 
515  // todo: precompute nz (piv[nz])
516 
517  // lower part
518  for (index_t i = 0; i!=nr; ++i)
519  {
520  // pull row(i)
521  R = this->row(i);
522  c_i = piv[i];
523  if (c_i == nc ) break;
524 
525  for (index_t j = i+1; j!=nr; ++j) // nr - zr
526  {
527  c_j = piv[j];
528  if ( c_j == nc ) break;
529  R.tail(nc-c_j) -= R.at(c_j) * this->row(j).tail(nc-c_j);
530  }
531  // push row(i)
532  this->row(i) = R.sparseView();
533  }
534 }
535 
536 #ifdef GISMO_WITH_PYBIND11
537 
541  namespace py = pybind11;
542 
543  template<typename T>
544  void pybind11_init_gsSparseMatrix(pybind11::module &m, const std::string & typestr)
545  {
546  using Class = gsSparseMatrix<T>;
547  std::string pyclass_name = std::string("gsSparseMatrix") + typestr;
548  py::class_<Class>(m, pyclass_name.c_str(), py::buffer_protocol(), py::dynamic_attr())
549  // Constructors
550  .def(py::init<>())
551  .def(py::init<index_t, index_t>())
552  // Member functions
553  .def("size", &Class::size)
554  .def("rows", &Class::rows)
555  .def("cols", &Class::cols)
556  // .def("transpose", &Class::transpose)
557  // .def("addTo", &Class::addTo)
558  // .def("insertTo", &Class::insertTo)
559  .def("toDense", &Class::toDense)
560  ;
561  }
562 
563 #endif // GISMO_WITH_PYBIND11
564 
565 } // namespace gismo
566 
567 
568 namespace gsEigen { namespace internal {
569 template<typename T, int _Options, typename _Index>
570 struct traits<gismo::gsSparseMatrix<T,_Options,_Index> >:
571 gsEigen::internal::traits<gsEigen::SparseMatrix<T,_Options,_Index> > { };
572 } }
573 
574 /* *****************************************************************
575 #ifdef GISMO_BUILD_LIB
576 #ifdef gsMatrix_EXPORT
577 #undef EXTERN_CLASS_TEMPLATE
578 #define EXTERN_CLASS_TEMPLATE CLASS_TEMPLATE_INST
579 #endif
580 namespace gismo
581 {
582 EXTERN_CLASS_TEMPLATE gsSparseMatrix<real_t>;
583 }
584 #endif
585 // *****************************************************************
586 */
container innerOf(const container &outer) const
Definition: gsSparseMatrix.h:344
gsEigen::SparseSelfAdjointView< Base, Lower > fullView
Definition: gsSparseMatrix.h:167
Class that provides a container for triplets (i,j,value) to be filled in a sparse matrix...
Definition: gsSparseMatrix.h:33
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:298
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:258
T distance(gsMatrix< T > const &A, gsMatrix< T > const &B, index_t i=0, index_t j=0, bool cols=false)
compute a distance between the point number in the set and the point number &lt;j&gt; in the set ; by def...
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition: gsSparseMatrix.h:249
memory::unique_ptr< gsSparseMatrix > uPtr
Unique pointer for gsSparseMatrix.
Definition: gsSparseMatrix.h:163
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:305
gsSparseMatrix(const gsEigen::SparseSelfAdjointView< OtherDerived, UpLo > &other)
This constructor allows constructing a gsSparseMatrix from a selfadjoint view.
Definition: gsSparseMatrix.h:184
#define index_t
Definition: gsConfig.h:32
gsSparseMatrix(const gsEigen::ReturnByValue< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition: gsSparseMatrix.h:197
gsSparseMatrix(const gsEigen::MatrixBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition: gsSparseMatrix.h:189
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition: gsSparseMatrix.h:140
gsAsConstVector< _Index > nonZerosPerCol()
Definition: gsSparseMatrix.h:314
gsEigen::SparseSelfAdjointView< const Base, Lower > constFullView
Definition: gsSparseMatrix.h:171
gsMatrix< T > multiplyBy(const container &inner, const container &outer, const gsMatrix< T > &other)
Definition: gsSparseMatrix.h:367
#define gsWarn
Definition: gsDebug.h:50
Iterator over the non-zero entries of a sparse matrix.
Definition: gsSparseMatrix.h:75
memory::shared_ptr< gsSparseMatrix > Ptr
Shared pointer for gsSparseMatrix.
Definition: gsSparseMatrix.h:160
void addTo(_Index i, _Index j, const T val)
Definition: gsSparseMatrix.h:284
Represents a block-view of the given matrix.
Definition: gsMatrixBlockView.h:31
gsSparseMatrix(const gsEigen::SparseMatrixBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from another sparse expression.
Definition: gsSparseMatrix.h:193
Creates a mapped object or data pointer to a const vector without copying data.
Definition: gsLinearAlgebra.h:130
gsSparseMatrix kron(const gsSparseMatrix &other) const
Returns the Kronecker product of this with other.
Definition: gsSparseMatrix.h:414
void insertTo(_Index i, _Index j, const T val)
Definition: gsSparseMatrix.h:291
gsMatrix< T > submatrix(const container &inner, const container &outer) const
Definition: gsSparseMatrix.h:378
gsSparseMatrix(const gsEigen::EigenBase< OtherDerived > &other)
This constructor allows constructing a gsSparseMatrix from Eigen expressions.
Definition: gsSparseMatrix.h:180