SparseLU.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
5 // Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 
12 #ifndef EIGEN_SPARSE_LU_H
13 #define EIGEN_SPARSE_LU_H
14 
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 template <typename MatrixType_, typename OrderingType_ = COLAMDOrdering<typename MatrixType_::StorageIndex> > class SparseLU;
20 template <typename MappedSparseMatrixType> struct SparseLUMatrixLReturnType;
21 template <typename MatrixLType, typename MatrixUType> struct SparseLUMatrixUReturnType;
22 
23 template <bool Conjugate,class SparseLUType>
24 class SparseLUTransposeView : public SparseSolverBase<SparseLUTransposeView<Conjugate,SparseLUType> >
25 {
26 protected:
29 public:
30  typedef typename SparseLUType::Scalar Scalar;
31  typedef typename SparseLUType::StorageIndex StorageIndex;
33  typedef typename SparseLUType::OrderingType OrderingType;
34 
35  enum {
36  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
37  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
38  };
39 
42  this->m_sparseLU = view.m_sparseLU;
43  this->m_isInitialized = view.m_isInitialized;
44  }
45  void setIsInitialized(const bool isInitialized) {this->m_isInitialized = isInitialized;}
46  void setSparseLU(SparseLUType* sparseLU) {m_sparseLU = sparseLU;}
47  using APIBase::_solve_impl;
48  template<typename Rhs, typename Dest>
49  bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &X_base) const
50  {
51  Dest& X(X_base.derived());
52  eigen_assert(m_sparseLU->info() == Success && "The matrix should be factorized first");
53  EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
54  THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
55 
56 
57  // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
58  for(Index j = 0; j < B.cols(); ++j){
59  X.col(j) = m_sparseLU->colsPermutation() * B.const_cast_derived().col(j);
60  }
61  //Forward substitution with transposed or adjoint of U
62  m_sparseLU->matrixU().template solveTransposedInPlace<Conjugate>(X);
63 
64  //Backward substitution with transposed or adjoint of L
65  m_sparseLU->matrixL().template solveTransposedInPlace<Conjugate>(X);
66 
67  // Permute back the solution
68  for (Index j = 0; j < B.cols(); ++j)
69  X.col(j) = m_sparseLU->rowsPermutation().transpose() * X.col(j);
70  return true;
71  }
72  inline Index rows() const { return m_sparseLU->rows(); }
73  inline Index cols() const { return m_sparseLU->cols(); }
74 
75 private:
76  SparseLUType *m_sparseLU;
78 };
79 
80 
133 template <typename MatrixType_, typename OrderingType_>
134 class SparseLU : public SparseSolverBase<SparseLU<MatrixType_,OrderingType_> >, public internal::SparseLUImpl<typename MatrixType_::Scalar, typename MatrixType_::StorageIndex>
135 {
136  protected:
139  public:
140  using APIBase::_solve_impl;
141 
142  typedef MatrixType_ MatrixType;
143  typedef OrderingType_ OrderingType;
144  typedef typename MatrixType::Scalar Scalar;
148  typedef internal::MappedSuperNodalMatrix<Scalar, StorageIndex> SCMatrix;
152  typedef internal::SparseLUImpl<Scalar, StorageIndex> Base;
153 
154  enum {
155  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
156  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
157  };
158 
159  public:
160 
162  {
163  initperfvalues();
164  }
165  explicit SparseLU(const MatrixType& matrix)
166  : m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1)
167  {
168  initperfvalues();
169  compute(matrix);
170  }
171 
173  {
174  // Free all explicit dynamic pointers
175  }
176 
177  void analyzePattern (const MatrixType& matrix);
178  void factorize (const MatrixType& matrix);
179  void simplicialfactorize(const MatrixType& matrix);
180 
185  void compute (const MatrixType& matrix)
186  {
187  // Analyze
188  analyzePattern(matrix);
189  //Factorize
190  factorize(matrix);
191  }
192 
204  {
206  transposeView.setSparseLU(this);
207  transposeView.setIsInitialized(this->m_isInitialized);
208  return transposeView;
209  }
210 
211 
225  {
227  adjointView.setSparseLU(this);
228  adjointView.setIsInitialized(this->m_isInitialized);
229  return adjointView;
230  }
231 
232  inline Index rows() const { return m_mat.rows(); }
233  inline Index cols() const { return m_mat.cols(); }
235  void isSymmetric(bool sym)
236  {
237  m_symmetricmode = sym;
238  }
239 
247  {
249  }
257  {
259  }
260 
265  inline const PermutationType& rowsPermutation() const
266  {
267  return m_perm_r;
268  }
273  inline const PermutationType& colsPermutation() const
274  {
275  return m_perm_c;
276  }
278  void setPivotThreshold(const RealScalar& thresh)
279  {
280  m_diagpivotthresh = thresh;
281  }
282 
283 #ifdef EIGEN_PARSED_BY_DOXYGEN
290  template<typename Rhs>
291  inline const Solve<SparseLU, Rhs> solve(const MatrixBase<Rhs>& B) const;
292 #endif // EIGEN_PARSED_BY_DOXYGEN
293 
303  {
304  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
305  return m_info;
306  }
307 
311  std::string lastErrorMessage() const
312  {
313  return m_lastError;
314  }
315 
316  template<typename Rhs, typename Dest>
317  bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &X_base) const
318  {
319  Dest& X(X_base.derived());
320  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first");
321  EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
322  THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
323 
324  // Permute the right hand side to form X = Pr*B
325  // on return, X is overwritten by the computed solution
326  X.resize(B.rows(),B.cols());
327 
328  // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
329  for(Index j = 0; j < B.cols(); ++j)
330  X.col(j) = rowsPermutation() * B.const_cast_derived().col(j);
331 
332  //Forward substitution with L
333  this->matrixL().solveInPlace(X);
334  this->matrixU().solveInPlace(X);
335 
336  // Permute back the solution
337  for (Index j = 0; j < B.cols(); ++j)
338  X.col(j) = colsPermutation().inverse() * X.col(j);
339 
340  return true;
341  }
342 
354  {
355  using std::abs;
356  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
357  // Initialize with the determinant of the row matrix
358  Scalar det = Scalar(1.);
359  // Note that the diagonal blocks of U are stored in supernodes,
360  // which are available in the L part :)
361  for (Index j = 0; j < this->cols(); ++j)
362  {
363  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
364  {
365  if(it.index() == j)
366  {
367  det *= abs(it.value());
368  break;
369  }
370  }
371  }
372  return det;
373  }
374 
384  {
385  using std::log;
386  using std::abs;
387 
388  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
389  Scalar det = Scalar(0.);
390  for (Index j = 0; j < this->cols(); ++j)
391  {
392  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
393  {
394  if(it.row() < j) continue;
395  if(it.row() == j)
396  {
397  det += log(abs(it.value()));
398  break;
399  }
400  }
401  }
402  return det;
403  }
404 
410  {
411  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
412  // Initialize with the determinant of the row matrix
413  Index det = 1;
414  // Note that the diagonal blocks of U are stored in supernodes,
415  // which are available in the L part :)
416  for (Index j = 0; j < this->cols(); ++j)
417  {
418  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
419  {
420  if(it.index() == j)
421  {
422  if(it.value()<0)
423  det = -det;
424  else if(it.value()==0)
425  return 0;
426  break;
427  }
428  }
429  }
430  return det * m_detPermR * m_detPermC;
431  }
432 
438  {
439  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
440  // Initialize with the determinant of the row matrix
441  Scalar det = Scalar(1.);
442  // Note that the diagonal blocks of U are stored in supernodes,
443  // which are available in the L part :)
444  for (Index j = 0; j < this->cols(); ++j)
445  {
446  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
447  {
448  if(it.index() == j)
449  {
450  det *= it.value();
451  break;
452  }
453  }
454  }
455  return (m_detPermR * m_detPermC) > 0 ? det : -det;
456  }
457 
458  Index nnzL() const { return m_nnzL; }
459  Index nnzU() const { return m_nnzU; }
460 
461  protected:
462  // Functions
464  {
465  m_perfv.panel_size = 16;
466  m_perfv.relax = 1;
467  m_perfv.maxsuper = 128;
468  m_perfv.rowblk = 16;
469  m_perfv.colblk = 8;
470  m_perfv.fillfactor = 20;
471  }
472 
473  // Variables
477  std::string m_lastError;
478  NCMatrix m_mat; // The input (permuted ) matrix
479  SCMatrix m_Lstore; // The lower triangular matrix (supernodal)
481  PermutationType m_perm_c; // Column permutation
482  PermutationType m_perm_r ; // Row permutation
483  IndexVector m_etree; // Column elimination tree
484 
485  typename Base::GlobalLU_t m_glu;
486 
487  // SparseLU options
489  // values for performance
490  internal::perfvalues m_perfv;
491  RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
492  Index m_nnzL, m_nnzU; // Nonzeros in L and U factors
493  Index m_detPermR, m_detPermC; // Determinants of the permutation matrices
494  private:
495  // Disable copy constructor
496  SparseLU (const SparseLU& );
497 }; // End class SparseLU
498 
499 
500 
501 // Functions needed by the anaysis phase
512 template <typename MatrixType, typename OrderingType>
514 {
515 
516  //TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat.
517 
518  // Firstly, copy the whole input matrix.
519  m_mat = mat;
520 
521  // Compute fill-in ordering
522  OrderingType ord;
523  ord(m_mat,m_perm_c);
524 
525  // Apply the permutation to the column of the input matrix
526  if (m_perm_c.size())
527  {
528  m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers. FIXME : This vector is filled but not subsequently used.
529  // Then, permute only the column pointers
530  ei_declare_aligned_stack_constructed_variable(StorageIndex,outerIndexPtr,mat.cols()+1,mat.isCompressed()?const_cast<StorageIndex*>(mat.outerIndexPtr()):0);
531 
532  // If the input matrix 'mat' is uncompressed, then the outer-indices do not match the ones of m_mat, and a copy is thus needed.
533  if(!mat.isCompressed())
534  IndexVector::Map(outerIndexPtr, mat.cols()+1) = IndexVector::Map(m_mat.outerIndexPtr(),mat.cols()+1);
535 
536  // Apply the permutation and compute the nnz per column.
537  for (Index i = 0; i < mat.cols(); i++)
538  {
539  m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
540  m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i+1] - outerIndexPtr[i];
541  }
542  }
543 
544  // Compute the column elimination tree of the permuted matrix
545  IndexVector firstRowElt;
546  internal::coletree(m_mat, m_etree,firstRowElt);
547 
548  // In symmetric mode, do not do postorder here
549  if (!m_symmetricmode) {
550  IndexVector post, iwork;
551  // Post order etree
552  internal::treePostorder(StorageIndex(m_mat.cols()), m_etree, post);
553 
554 
555  // Renumber etree in postorder
556  Index m = m_mat.cols();
557  iwork.resize(m+1);
558  for (Index i = 0; i < m; ++i) iwork(post(i)) = post(m_etree(i));
559  m_etree = iwork;
560 
561  // Postmultiply A*Pc by post, i.e reorder the matrix according to the postorder of the etree
562  PermutationType post_perm(m);
563  for (Index i = 0; i < m; i++)
564  post_perm.indices()(i) = post(i);
565 
566  // Combine the two permutations : postorder the permutation for future use
567  if(m_perm_c.size()) {
568  m_perm_c = post_perm * m_perm_c;
569  }
570 
571  } // end postordering
572 
573  m_analysisIsOk = true;
574 }
575 
576 // Functions needed by the numerical factorization phase
577 
578 
597 template <typename MatrixType, typename OrderingType>
599 {
600  using internal::emptyIdxLU;
601  eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
602  eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices");
603 
604  m_isInitialized = true;
605 
606  // Apply the column permutation computed in analyzepattern()
607  // m_mat = matrix * m_perm_c.inverse();
608  m_mat = matrix;
609  if (m_perm_c.size())
610  {
611  m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers.
612  //Then, permute only the column pointers
613  const StorageIndex * outerIndexPtr;
614  if (matrix.isCompressed()) outerIndexPtr = matrix.outerIndexPtr();
615  else
616  {
617  StorageIndex* outerIndexPtr_t = new StorageIndex[matrix.cols()+1];
618  for(Index i = 0; i <= matrix.cols(); i++) outerIndexPtr_t[i] = m_mat.outerIndexPtr()[i];
619  outerIndexPtr = outerIndexPtr_t;
620  }
621  for (Index i = 0; i < matrix.cols(); i++)
622  {
623  m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
624  m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i+1] - outerIndexPtr[i];
625  }
626  if(!matrix.isCompressed()) delete[] outerIndexPtr;
627  }
628  else
629  { //FIXME This should not be needed if the empty permutation is handled transparently
630  m_perm_c.resize(matrix.cols());
631  for(StorageIndex i = 0; i < matrix.cols(); ++i) m_perm_c.indices()(i) = i;
632  }
633 
634  Index m = m_mat.rows();
635  Index n = m_mat.cols();
636  Index nnz = m_mat.nonZeros();
637  Index maxpanel = m_perfv.panel_size * m;
638  // Allocate working storage common to the factor routines
639  Index lwork = 0;
640  Index info = Base::memInit(m, n, nnz, lwork, m_perfv.fillfactor, m_perfv.panel_size, m_glu);
641  if (info)
642  {
643  m_lastError = "UNABLE TO ALLOCATE WORKING MEMORY\n\n" ;
644  m_factorizationIsOk = false;
645  return ;
646  }
647 
648  // Set up pointers for integer working arrays
649  IndexVector segrep(m); segrep.setZero();
650  IndexVector parent(m); parent.setZero();
651  IndexVector xplore(m); xplore.setZero();
652  IndexVector repfnz(maxpanel);
653  IndexVector panel_lsub(maxpanel);
654  IndexVector xprune(n); xprune.setZero();
655  IndexVector marker(m*internal::LUNoMarker); marker.setZero();
656 
657  repfnz.setConstant(-1);
658  panel_lsub.setConstant(-1);
659 
660  // Set up pointers for scalar working arrays
661  ScalarVector dense;
662  dense.setZero(maxpanel);
663  ScalarVector tempv;
664  tempv.setZero(internal::LUnumTempV(m, m_perfv.panel_size, m_perfv.maxsuper, /*m_perfv.rowblk*/m) );
665 
666  // Compute the inverse of perm_c
667  PermutationType iperm_c(m_perm_c.inverse());
668 
669  // Identify initial relaxed snodes
670  IndexVector relax_end(n);
671  if ( m_symmetricmode == true )
672  Base::heap_relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
673  else
674  Base::relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
675 
676 
677  m_perm_r.resize(m);
678  m_perm_r.indices().setConstant(-1);
679  marker.setConstant(-1);
680  m_detPermR = 1; // Record the determinant of the row permutation
681 
682  m_glu.supno(0) = emptyIdxLU; m_glu.xsup.setConstant(0);
683  m_glu.xsup(0) = m_glu.xlsub(0) = m_glu.xusub(0) = m_glu.xlusup(0) = Index(0);
684 
685  // Work on one 'panel' at a time. A panel is one of the following :
686  // (a) a relaxed supernode at the bottom of the etree, or
687  // (b) panel_size contiguous columns, <panel_size> defined by the user
688  Index jcol;
689  Index pivrow; // Pivotal row number in the original row matrix
690  Index nseg1; // Number of segments in U-column above panel row jcol
691  Index nseg; // Number of segments in each U-column
692  Index irep;
693  Index i, k, jj;
694  for (jcol = 0; jcol < n; )
695  {
696  // Adjust panel size so that a panel won't overlap with the next relaxed snode.
697  Index panel_size = m_perfv.panel_size; // upper bound on panel width
698  for (k = jcol + 1; k < (std::min)(jcol+panel_size, n); k++)
699  {
700  if (relax_end(k) != emptyIdxLU)
701  {
702  panel_size = k - jcol;
703  break;
704  }
705  }
706  if (k == n)
707  panel_size = n - jcol;
708 
709  // Symbolic outer factorization on a panel of columns
710  Base::panel_dfs(m, panel_size, jcol, m_mat, m_perm_r.indices(), nseg1, dense, panel_lsub, segrep, repfnz, xprune, marker, parent, xplore, m_glu);
711 
712  // Numeric sup-panel updates in topological order
713  Base::panel_bmod(m, panel_size, jcol, nseg1, dense, tempv, segrep, repfnz, m_glu);
714 
715  // Sparse LU within the panel, and below the panel diagonal
716  for ( jj = jcol; jj< jcol + panel_size; jj++)
717  {
718  k = (jj - jcol) * m; // Column index for w-wide arrays
719 
720  nseg = nseg1; // begin after all the panel segments
721  //Depth-first-search for the current column
722  VectorBlock<IndexVector> panel_lsubk(panel_lsub, k, m);
723  VectorBlock<IndexVector> repfnz_k(repfnz, k, m);
724  info = Base::column_dfs(m, jj, m_perm_r.indices(), m_perfv.maxsuper, nseg, panel_lsubk, segrep, repfnz_k, xprune, marker, parent, xplore, m_glu);
725  if ( info )
726  {
727  m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_DFS() ";
728  m_info = NumericalIssue;
729  m_factorizationIsOk = false;
730  return;
731  }
732  // Numeric updates to this column
733  VectorBlock<ScalarVector> dense_k(dense, k, m);
734  VectorBlock<IndexVector> segrep_k(segrep, nseg1, m-nseg1);
735  info = Base::column_bmod(jj, (nseg - nseg1), dense_k, tempv, segrep_k, repfnz_k, jcol, m_glu);
736  if ( info )
737  {
738  m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_BMOD() ";
739  m_info = NumericalIssue;
740  m_factorizationIsOk = false;
741  return;
742  }
743 
744  // Copy the U-segments to ucol(*)
745  info = Base::copy_to_ucol(jj, nseg, segrep, repfnz_k ,m_perm_r.indices(), dense_k, m_glu);
746  if ( info )
747  {
748  m_lastError = "UNABLE TO EXPAND MEMORY IN COPY_TO_UCOL() ";
749  m_info = NumericalIssue;
750  m_factorizationIsOk = false;
751  return;
752  }
753 
754  // Form the L-segment
755  info = Base::pivotL(jj, m_diagpivotthresh, m_perm_r.indices(), iperm_c.indices(), pivrow, m_glu);
756  if ( info )
757  {
758  m_lastError = "THE MATRIX IS STRUCTURALLY SINGULAR";
759 #ifndef EIGEN_NO_IO
760  std::ostringstream returnInfo;
761  returnInfo << " ... ZERO COLUMN AT ";
762  returnInfo << info;
763  m_lastError += returnInfo.str();
764 #endif
765  m_info = NumericalIssue;
766  m_factorizationIsOk = false;
767  return;
768  }
769 
770  // Update the determinant of the row permutation matrix
771  // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not directly the row pivot.
772  if (pivrow != jj) m_detPermR = -m_detPermR;
773 
774  // Prune columns (0:jj-1) using column jj
775  Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu);
776 
777  // Reset repfnz for this column
778  for (i = 0; i < nseg; i++)
779  {
780  irep = segrep(i);
781  repfnz_k(irep) = emptyIdxLU;
782  }
783  } // end SparseLU within the panel
784  jcol += panel_size; // Move to the next panel
785  } // end for -- end elimination
786 
787  m_detPermR = m_perm_r.determinant();
788  m_detPermC = m_perm_c.determinant();
789 
790  // Count the number of nonzeros in factors
791  Base::countnz(n, m_nnzL, m_nnzU, m_glu);
792  // Apply permutation to the L subscripts
793  Base::fixupL(n, m_perm_r.indices(), m_glu);
794 
795  // Create supernode matrix L
796  m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup);
797  // Create the column major upper sparse matrix U;
798  new (&m_Ustore) Map<SparseMatrix<Scalar, ColMajor, StorageIndex>> ( m, n, m_nnzU, m_glu.xusub.data(), m_glu.usub.data(), m_glu.ucol.data() );
799 
800  m_info = Success;
801  m_factorizationIsOk = true;
802 }
803 
804 template<typename MappedSupernodalType>
805 struct SparseLUMatrixLReturnType : internal::no_assignment_operator
806 {
807  typedef typename MappedSupernodalType::Scalar Scalar;
808  explicit SparseLUMatrixLReturnType(const MappedSupernodalType& mapL) : m_mapL(mapL)
809  { }
810  Index rows() const { return m_mapL.rows(); }
811  Index cols() const { return m_mapL.cols(); }
812  template<typename Dest>
814  {
815  m_mapL.solveInPlace(X);
816  }
817  template<bool Conjugate, typename Dest>
819  {
820  m_mapL.template solveTransposedInPlace<Conjugate>(X);
821  }
822 
824  ArrayXi colCount = ArrayXi::Ones(cols());
825  for (Index i = 0; i < cols(); i++) {
826  typename MappedSupernodalType::InnerIterator iter(m_mapL, i);
827  for (; iter; ++iter) {
828  if (iter.row() > iter.col()) {
829  colCount(iter.col())++;
830  }
831  }
832  }
834  sL.reserve(colCount);
835  for (Index i = 0; i < cols(); i++) {
836  sL.insert(i, i) = 1.0;
837  typename MappedSupernodalType::InnerIterator iter(m_mapL, i);
838  for (; iter; ++iter) {
839  if (iter.row() > iter.col()) {
840  sL.insert(iter.row(), iter.col()) = iter.value();
841  }
842  }
843  }
844  sL.makeCompressed();
845  return sL;
846  }
847 
848  const MappedSupernodalType& m_mapL;
849 };
850 
851 template<typename MatrixLType, typename MatrixUType>
852 struct SparseLUMatrixUReturnType : internal::no_assignment_operator
853 {
854  typedef typename MatrixLType::Scalar Scalar;
855  SparseLUMatrixUReturnType(const MatrixLType& mapL, const MatrixUType& mapU)
856  : m_mapL(mapL),m_mapU(mapU)
857  { }
858  Index rows() const { return m_mapL.rows(); }
859  Index cols() const { return m_mapL.cols(); }
860 
861  template<typename Dest> void solveInPlace(MatrixBase<Dest> &X) const
862  {
863  Index nrhs = X.cols();
864  // Backward solve with U
865  for (Index k = m_mapL.nsuper(); k >= 0; k--)
866  {
867  Index fsupc = m_mapL.supToCol()[k];
868  Index lda = m_mapL.colIndexPtr()[fsupc+1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
869  Index nsupc = m_mapL.supToCol()[k+1] - fsupc;
870  Index luptr = m_mapL.colIndexPtr()[fsupc];
871 
872  if (nsupc == 1)
873  {
874  for (Index j = 0; j < nrhs; j++)
875  {
876  X(fsupc, j) /= m_mapL.valuePtr()[luptr];
877  }
878  }
879  else
880  {
881  // FIXME: the following lines should use Block expressions and not Map!
882  Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
883  typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
884  U = A.template triangularView<Upper>().solve(U);
885  }
886 
887  for (Index j = 0; j < nrhs; ++j)
888  {
889  for (Index jcol = fsupc; jcol < fsupc + nsupc; jcol++)
890  {
891  typename MatrixUType::InnerIterator it(m_mapU, jcol);
892  for ( ; it; ++it)
893  {
894  Index irow = it.index();
895  X(irow, j) -= X(jcol, j) * it.value();
896  }
897  }
898  }
899  } // End For U-solve
900  }
901 
902  template<bool Conjugate, typename Dest> void solveTransposedInPlace(MatrixBase<Dest> &X) const
903  {
904  using numext::conj;
905  Index nrhs = X.cols();
906  // Forward solve with U
907  for (Index k = 0; k <= m_mapL.nsuper(); k++)
908  {
909  Index fsupc = m_mapL.supToCol()[k];
910  Index lda = m_mapL.colIndexPtr()[fsupc+1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
911  Index nsupc = m_mapL.supToCol()[k+1] - fsupc;
912  Index luptr = m_mapL.colIndexPtr()[fsupc];
913 
914  for (Index j = 0; j < nrhs; ++j)
915  {
916  for (Index jcol = fsupc; jcol < fsupc + nsupc; jcol++)
917  {
918  typename MatrixUType::InnerIterator it(m_mapU, jcol);
919  for ( ; it; ++it)
920  {
921  Index irow = it.index();
922  X(jcol, j) -= X(irow, j) * (Conjugate? conj(it.value()): it.value());
923  }
924  }
925  }
926  if (nsupc == 1)
927  {
928  for (Index j = 0; j < nrhs; j++)
929  {
930  X(fsupc, j) /= (Conjugate? conj(m_mapL.valuePtr()[luptr]) : m_mapL.valuePtr()[luptr]);
931  }
932  }
933  else
934  {
935  Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
936  typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
937  if(Conjugate)
938  U = A.adjoint().template triangularView<Lower>().solve(U);
939  else
940  U = A.transpose().template triangularView<Lower>().solve(U);
941  }
942  }// End For U-solve
943  }
944 
946  ArrayXi rowCount = ArrayXi::Zero(rows());
947  for (Index i = 0; i < cols(); i++) {
948  typename MatrixLType::InnerIterator iter(m_mapL, i);
949  for (; iter; ++iter) {
950  if (iter.row() <= iter.col()) {
951  rowCount(iter.row())++;
952  }
953  }
954  }
955 
957  sU.reserve(rowCount);
958  for (Index i = 0; i < cols(); i++) {
959  typename MatrixLType::InnerIterator iter(m_mapL, i);
960  for (; iter; ++iter) {
961  if (iter.row() <= iter.col()) {
962  sU.insert(iter.row(), iter.col()) = iter.value();
963  }
964  }
965  }
966  sU.makeCompressed();
967  const SparseMatrix<Scalar, RowMajor, Index> u = m_mapU; // convert to RowMajor
968  sU += u;
969  return sU;
970  }
971 
972  const MatrixLType& m_mapL;
973  const MatrixUType& m_mapU;
974 };
975 
976 } // End namespace Eigen
977 
978 #endif
Matrix3f m
const AbsReturnType abs() const
const LogReturnType log() const
int n
MatrixXcf A
MatrixXf B
#define eigen_assert(x)
Definition: Macros.h:902
#define ei_declare_aligned_stack_constructed_variable(TYPE, NAME, SIZE, BUFFER)
Definition: Memory.h:847
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
Matrix< float, 1, Dynamic > MatrixType
General-purpose arrays with easy API for coefficient-wise operations.
Definition: Array.h:49
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
static const ConstantReturnType Ones()
internal::traits< Derived >::StorageIndex StorageIndex
The type used to store indices.
Definition: DenseBase.h:58
static const ConstantReturnType Zero()
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:98
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
Convenience specialization of Stride to specify only an outer stride See class Map for some examples.
Definition: Stride.h:113
InverseReturnType inverse() const
const IndicesType & indices() const
EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
Derived & setConstant(Index size, const Scalar &val)
EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Derived & setZero(Index size)
constexpr void resize(Index rows, Index cols)
Pseudo expression representing a solving operation.
Definition: Solve.h:65
SparseLUType::MatrixType MatrixType
Definition: SparseLU.h:32
SparseLUType * m_sparseLU
Definition: SparseLU.h:76
void setSparseLU(SparseLUType *sparseLU)
Definition: SparseLU.h:46
SparseLUType::Scalar Scalar
Definition: SparseLU.h:30
bool _solve_impl(const MatrixBase< Rhs > &B, MatrixBase< Dest > &X_base) const
Definition: SparseLU.h:49
SparseSolverBase< SparseLUTransposeView< Conjugate, SparseLUType > > APIBase
Definition: SparseLU.h:27
SparseLUTransposeView & operator=(const SparseLUTransposeView &)
void setIsInitialized(const bool isInitialized)
Definition: SparseLU.h:45
SparseLUType::OrderingType OrderingType
Definition: SparseLU.h:33
SparseLUTransposeView(const SparseLUTransposeView &view)
Definition: SparseLU.h:41
SparseLUType::StorageIndex StorageIndex
Definition: SparseLU.h:31
Sparse supernodal LU factorization for general matrices.
Definition: SparseLU.h:135
SparseLU(const SparseLU &)
std::string m_lastError
Definition: SparseLU.h:477
Matrix< StorageIndex, Dynamic, 1 > IndexVector
Definition: SparseLU.h:150
void setPivotThreshold(const RealScalar &thresh)
Definition: SparseLU.h:278
Index cols() const
Definition: SparseLU.h:233
Scalar logAbsDeterminant() const
Definition: SparseLU.h:383
Index rows() const
Definition: SparseLU.h:232
Index nnzU() const
Definition: SparseLU.h:459
MatrixType::Scalar Scalar
Definition: SparseLU.h:144
bool m_factorizationIsOk
Definition: SparseLU.h:475
MatrixType::RealScalar RealScalar
Definition: SparseLU.h:145
PermutationType m_perm_c
Definition: SparseLU.h:481
SparseMatrix< Scalar, ColMajor, StorageIndex > NCMatrix
Definition: SparseLU.h:147
SparseLUMatrixUReturnType< SCMatrix, Map< SparseMatrix< Scalar, ColMajor, StorageIndex > > > matrixU() const
Definition: SparseLU.h:256
void factorize(const MatrixType &matrix)
Definition: SparseLU.h:598
Index m_detPermR
Definition: SparseLU.h:493
const PermutationType & rowsPermutation() const
Definition: SparseLU.h:265
NCMatrix m_mat
Definition: SparseLU.h:478
std::string lastErrorMessage() const
Definition: SparseLU.h:311
const SparseLUTransposeView< true, SparseLU< MatrixType_, OrderingType_ > > adjoint()
Definition: SparseLU.h:224
SparseLUMatrixLReturnType< SCMatrix > matrixL() const
Definition: SparseLU.h:246
SCMatrix m_Lstore
Definition: SparseLU.h:479
SparseSolverBase< SparseLU< MatrixType_, OrderingType_ > > APIBase
Definition: SparseLU.h:137
void compute(const MatrixType &matrix)
Definition: SparseLU.h:185
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: SparseLU.h:302
bool m_analysisIsOk
Definition: SparseLU.h:476
Scalar signDeterminant()
Definition: SparseLU.h:409
void initperfvalues()
Definition: SparseLU.h:463
bool _solve_impl(const MatrixBase< Rhs > &B, MatrixBase< Dest > &X_base) const
Definition: SparseLU.h:317
void simplicialfactorize(const MatrixType &matrix)
bool m_symmetricmode
Definition: SparseLU.h:488
Scalar absDeterminant()
Definition: SparseLU.h:353
internal::perfvalues m_perfv
Definition: SparseLU.h:490
Matrix< Scalar, Dynamic, 1 > ScalarVector
Definition: SparseLU.h:149
OrderingType_ OrderingType
Definition: SparseLU.h:143
Index m_detPermC
Definition: SparseLU.h:493
internal::MappedSuperNodalMatrix< Scalar, StorageIndex > SCMatrix
Definition: SparseLU.h:148
void analyzePattern(const MatrixType &matrix)
Definition: SparseLU.h:513
@ MaxColsAtCompileTime
Definition: SparseLU.h:156
Index nnzL() const
Definition: SparseLU.h:458
const Solve< SparseLU, Rhs > solve(const MatrixBase< Rhs > &B) const
PermutationMatrix< Dynamic, Dynamic, StorageIndex > PermutationType
Definition: SparseLU.h:151
MatrixType_ MatrixType
Definition: SparseLU.h:142
IndexVector m_etree
Definition: SparseLU.h:483
PermutationType m_perm_r
Definition: SparseLU.h:482
const SparseLUTransposeView< false, SparseLU< MatrixType_, OrderingType_ > > transpose()
Definition: SparseLU.h:203
void isSymmetric(bool sym)
Definition: SparseLU.h:235
const PermutationType & colsPermutation() const
Definition: SparseLU.h:273
Base::GlobalLU_t m_glu
Definition: SparseLU.h:485
RealScalar m_diagpivotthresh
Definition: SparseLU.h:491
Map< SparseMatrix< Scalar, ColMajor, StorageIndex > > m_Ustore
Definition: SparseLU.h:480
SparseLU(const MatrixType &matrix)
Definition: SparseLU.h:165
Scalar determinant()
Definition: SparseLU.h:437
MatrixType::StorageIndex StorageIndex
Definition: SparseLU.h:146
ComputationInfo m_info
Definition: SparseLU.h:474
internal::SparseLUImpl< Scalar, StorageIndex > Base
Definition: SparseLU.h:152
Index cols() const
Definition: SparseMatrix.h:167
Index rows() const
Definition: SparseMatrix.h:165
void reserve(Index reserveSize)
Definition: SparseMatrix.h:300
Scalar & insert(Index row, Index col)
A base class for sparse solvers.
Expression of a fixed-size or dynamic-size sub-vector.
Definition: VectorBlock.h:62
ComputationInfo
Definition: Constants.h:444
@ NumericalIssue
Definition: Constants.h:448
@ Success
Definition: Constants.h:446
const unsigned int RowMajorBit
Definition: Constants.h:68
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
Index LUnumTempV(Index &m, Index &w, Index &t, Index &b)
int coletree(const MatrixType &mat, IndexVector &parent, IndexVector &firstRowElt, typename MatrixType::StorageIndex *perm=0)
void treePostorder(typename IndexVector::Scalar n, IndexVector &parent, IndexVector &post)
Post order a tree.
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_log_op< typename Derived::Scalar >, const Derived > log(const Eigen::ArrayBase< Derived > &x)
void solveTransposedInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:818
const MappedSupernodalType & m_mapL
Definition: SparseLU.h:848
SparseLUMatrixLReturnType(const MappedSupernodalType &mapL)
Definition: SparseLU.h:808
void solveInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:813
SparseMatrix< Scalar, ColMajor, Index > toSparse() const
Definition: SparseLU.h:823
MappedSupernodalType::Scalar Scalar
Definition: SparseLU.h:807
const MatrixUType & m_mapU
Definition: SparseLU.h:973
SparseMatrix< Scalar, RowMajor, Index > toSparse()
Definition: SparseLU.h:945
SparseLUMatrixUReturnType(const MatrixLType &mapL, const MatrixUType &mapU)
Definition: SparseLU.h:855
void solveInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:861
const MatrixLType & m_mapL
Definition: SparseLU.h:972
void solveTransposedInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:902
MatrixLType::Scalar Scalar
Definition: SparseLU.h:854
std::ptrdiff_t j