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 #ifndef EIGEN_SPARSE_LU_H
12 #define EIGEN_SPARSE_LU_H
13 
14 // IWYU pragma: private
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 template <typename MatrixType_, typename OrderingType_ = COLAMDOrdering<typename MatrixType_::StorageIndex>>
20 class SparseLU;
21 template <typename MappedSparseMatrixType>
22 struct SparseLUMatrixLReturnType;
23 template <typename MatrixLType, typename MatrixUType>
24 struct SparseLUMatrixUReturnType;
25 
26 template <bool Conjugate, class SparseLUType>
27 class SparseLUTransposeView : public SparseSolverBase<SparseLUTransposeView<Conjugate, SparseLUType>> {
28  protected:
31 
32  public:
33  typedef typename SparseLUType::Scalar Scalar;
34  typedef typename SparseLUType::StorageIndex StorageIndex;
36  typedef typename SparseLUType::OrderingType OrderingType;
37 
38  enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime };
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; }
48  template <typename Rhs, typename Dest>
49  bool _solve_impl(const MatrixBase<Rhs>& B, MatrixBase<Dest>& X_base) const {
50  Dest& X(X_base.derived());
51  eigen_assert(m_sparseLU->info() == Success && "The matrix should be factorized first");
52  EIGEN_STATIC_ASSERT((Dest::Flags & RowMajorBit) == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
53 
54  // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
55  for (Index j = 0; j < B.cols(); ++j) {
56  X.col(j) = m_sparseLU->colsPermutation() * B.const_cast_derived().col(j);
57  }
58  // Forward substitution with transposed or adjoint of U
59  m_sparseLU->matrixU().template solveTransposedInPlace<Conjugate>(X);
60 
61  // Backward substitution with transposed or adjoint of L
62  m_sparseLU->matrixL().template solveTransposedInPlace<Conjugate>(X);
63 
64  // Permute back the solution
65  for (Index j = 0; j < B.cols(); ++j) X.col(j) = m_sparseLU->rowsPermutation().transpose() * X.col(j);
66  return true;
67  }
68  inline Index rows() const { return m_sparseLU->rows(); }
69  inline Index cols() const { return m_sparseLU->cols(); }
70 
71  private:
72  SparseLUType* m_sparseLU;
74 };
75 
149 template <typename MatrixType_, typename OrderingType_>
150 class SparseLU : public SparseSolverBase<SparseLU<MatrixType_, OrderingType_>>,
151  public internal::SparseLUImpl<typename MatrixType_::Scalar, typename MatrixType_::StorageIndex> {
152  protected:
155 
156  public:
157  using APIBase::_solve_impl;
158 
159  typedef MatrixType_ MatrixType;
160  typedef OrderingType_ OrderingType;
161  typedef typename MatrixType::Scalar Scalar;
163  typedef typename MatrixType::StorageIndex StorageIndex;
170 
171  enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime };
172 
173  public:
179  : m_lastError(""), m_Ustore(0, 0, 0, 0, 0, 0), m_symmetricmode(false), m_diagpivotthresh(1.0), m_detPermR(1) {
180  initperfvalues();
181  }
186  explicit SparseLU(const MatrixType& matrix)
187  : m_lastError(""), m_Ustore(0, 0, 0, 0, 0, 0), m_symmetricmode(false), m_diagpivotthresh(1.0), m_detPermR(1) {
188  initperfvalues();
189  compute(matrix);
190  }
191 
193  // Free all explicit dynamic pointers
194  }
195 
196  void analyzePattern(const MatrixType& matrix);
197  void factorize(const MatrixType& matrix);
199 
210  void compute(const MatrixType& matrix) {
211  // Analyze
213  // Factorize
214  factorize(matrix);
215  }
216 
231  transposeView.setSparseLU(this);
232  transposeView.setIsInitialized(this->m_isInitialized);
233  return transposeView;
234  }
235 
252  adjointView.setSparseLU(this);
253  adjointView.setIsInitialized(this->m_isInitialized);
254  return adjointView;
255  }
256 
259  inline Index rows() const { return m_mat.rows(); }
262  inline Index cols() const { return m_mat.cols(); }
265  void isSymmetric(bool sym) { m_symmetricmode = sym; }
266 
286  }
287 
293  inline const PermutationType& rowsPermutation() const { return m_perm_r; }
299  inline const PermutationType& colsPermutation() const { return m_perm_c; }
301  void setPivotThreshold(const RealScalar& thresh) { m_diagpivotthresh = thresh; }
302 
303 #ifdef EIGEN_PARSED_BY_DOXYGEN
312  template <typename Rhs>
313  inline const Solve<SparseLU, Rhs> solve(const MatrixBase<Rhs>& B) const;
314 #endif // EIGEN_PARSED_BY_DOXYGEN
315 
327  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
328  return m_info;
329  }
330 
336 
337  template <typename Rhs, typename Dest>
338  bool _solve_impl(const MatrixBase<Rhs>& B, MatrixBase<Dest>& X_base) const {
339  Dest& X(X_base.derived());
340  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first");
341  EIGEN_STATIC_ASSERT((Dest::Flags & RowMajorBit) == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
342 
343  // Permute the right hand side to form X = Pr*B
344  // on return, X is overwritten by the computed solution
345  X.resize(B.rows(), B.cols());
346 
347  // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
348  for (Index j = 0; j < B.cols(); ++j) X.col(j) = rowsPermutation() * B.const_cast_derived().col(j);
349 
350  // Forward substitution with L
351  this->matrixL().solveInPlace(X);
352  this->matrixU().solveInPlace(X);
353 
354  // Permute back the solution
355  for (Index j = 0; j < B.cols(); ++j) X.col(j) = colsPermutation().inverse() * X.col(j);
356 
357  return true;
358  }
359 
372  using std::abs;
373  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
374  // Initialize with the determinant of the row matrix
375  Scalar det = Scalar(1.);
376  // Note that the diagonal blocks of U are stored in supernodes,
377  // which are available in the L part :)
378  for (Index j = 0; j < this->cols(); ++j) {
379  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) {
380  if (it.index() == j) {
381  det *= abs(it.value());
382  break;
383  }
384  }
385  }
386  return det;
387  }
388 
400  using std::abs;
401  using std::log;
402 
403  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
404  Scalar det = Scalar(0.);
405  for (Index j = 0; j < this->cols(); ++j) {
406  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) {
407  if (it.row() < j) continue;
408  if (it.row() == j) {
409  det += log(abs(it.value()));
410  break;
411  }
412  }
413  }
414  return det;
415  }
416 
424  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
425  // Initialize with the determinant of the row matrix
426  Index det = 1;
427  // Note that the diagonal blocks of U are stored in supernodes,
428  // which are available in the L part :)
429  for (Index j = 0; j < this->cols(); ++j) {
430  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) {
431  if (it.index() == j) {
432  if (it.value() < 0)
433  det = -det;
434  else if (it.value() == 0)
435  return 0;
436  break;
437  }
438  }
439  }
440  return det * m_detPermR * m_detPermC;
441  }
442 
450  eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
451  // Initialize with the determinant of the row matrix
452  Scalar det = Scalar(1.);
453  // Note that the diagonal blocks of U are stored in supernodes,
454  // which are available in the L part :)
455  for (Index j = 0; j < this->cols(); ++j) {
456  for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) {
457  if (it.index() == j) {
458  det *= it.value();
459  break;
460  }
461  }
462  }
463  return (m_detPermR * m_detPermC) > 0 ? det : -det;
464  }
465 
468  Index nnzL() const { return m_nnzL; }
471  Index nnzU() const { return m_nnzU; }
472 
473  protected:
474  // Functions
475  void initperfvalues() {
476  m_perfv.panel_size = 16;
477  m_perfv.relax = 1;
478  m_perfv.maxsuper = 128;
479  m_perfv.rowblk = 16;
480  m_perfv.colblk = 8;
481  m_perfv.fillfactor = 20;
482  }
483 
484  // Variables
489  NCMatrix m_mat; // The input (permuted ) matrix
490  SCMatrix m_Lstore; // The lower triangular matrix (supernodal)
492  PermutationType m_perm_c; // Column permutation
493  PermutationType m_perm_r; // Row permutation
494  IndexVector m_etree; // Column elimination tree
495 
497 
498  // SparseLU options
500  // values for performance
502  RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
503  Index m_nnzL, m_nnzU; // Nonzeros in L and U factors
504  Index m_detPermR, m_detPermC; // Determinants of the permutation matrices
505  private:
506  // Disable copy constructor
508 }; // End class SparseLU
509 
510 // Functions needed by the anaysis phase
527 template <typename MatrixType, typename OrderingType>
529  // TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat.
530 
531  // Firstly, copy the whole input matrix.
532  m_mat = mat;
533 
534  // Compute fill-in ordering
535  OrderingType ord;
536  ord(m_mat, m_perm_c);
537 
538  // Apply the permutation to the column of the input matrix
539  if (m_perm_c.size()) {
540  m_mat.uncompress(); // NOTE: The effect of this command is only to create the InnerNonzeros pointers. FIXME : This
541  // vector is filled but not subsequently used.
542  // Then, permute only the column pointers
544  StorageIndex, outerIndexPtr, mat.cols() + 1,
545  mat.isCompressed() ? const_cast<StorageIndex*>(mat.outerIndexPtr()) : 0);
546 
547  // If the input matrix 'mat' is uncompressed, then the outer-indices do not match the ones of m_mat, and a copy is
548  // thus needed.
549  if (!mat.isCompressed())
550  IndexVector::Map(outerIndexPtr, mat.cols() + 1) = IndexVector::Map(m_mat.outerIndexPtr(), mat.cols() + 1);
551 
552  // Apply the permutation and compute the nnz per column.
553  for (Index i = 0; i < mat.cols(); i++) {
554  m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
555  m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i + 1] - outerIndexPtr[i];
556  }
557  }
558 
559  // Compute the column elimination tree of the permuted matrix
560  IndexVector firstRowElt;
561  internal::coletree(m_mat, m_etree, firstRowElt);
562 
563  // In symmetric mode, do not do postorder here
564  if (!m_symmetricmode) {
565  IndexVector post, iwork;
566  // Post order etree
567  internal::treePostorder(StorageIndex(m_mat.cols()), m_etree, post);
568 
569  // Renumber etree in postorder
570  Index m = m_mat.cols();
571  iwork.resize(m + 1);
572  for (Index i = 0; i < m; ++i) iwork(post(i)) = post(m_etree(i));
573  m_etree = iwork;
574 
575  // Postmultiply A*Pc by post, i.e reorder the matrix according to the postorder of the etree
576  PermutationType post_perm(m);
577  for (Index i = 0; i < m; i++) post_perm.indices()(i) = post(i);
578 
579  // Combine the two permutations : postorder the permutation for future use
580  if (m_perm_c.size()) {
581  m_perm_c = post_perm * m_perm_c;
582  }
583 
584  } // end postordering
585 
586  m_analysisIsOk = true;
587 }
588 
589 // Functions needed by the numerical factorization phase
590 
610 template <typename MatrixType, typename OrderingType>
612  using internal::emptyIdxLU;
613  eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
614  eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices");
615 
616  m_isInitialized = true;
617 
618  // Apply the column permutation computed in analyzepattern()
619  // m_mat = matrix * m_perm_c.inverse();
620  m_mat = matrix;
621  if (m_perm_c.size()) {
622  m_mat.uncompress(); // NOTE: The effect of this command is only to create the InnerNonzeros pointers.
623  // Then, permute only the column pointers
624  const StorageIndex* outerIndexPtr;
625  if (matrix.isCompressed())
626  outerIndexPtr = matrix.outerIndexPtr();
627  else {
628  StorageIndex* outerIndexPtr_t = new StorageIndex[matrix.cols() + 1];
629  for (Index i = 0; i <= matrix.cols(); i++) outerIndexPtr_t[i] = m_mat.outerIndexPtr()[i];
630  outerIndexPtr = outerIndexPtr_t;
631  }
632  for (Index i = 0; i < matrix.cols(); i++) {
633  m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
634  m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i + 1] - outerIndexPtr[i];
635  }
636  if (!matrix.isCompressed()) delete[] outerIndexPtr;
637  } else { // FIXME This should not be needed if the empty permutation is handled transparently
638  m_perm_c.resize(matrix.cols());
639  for (StorageIndex i = 0; i < matrix.cols(); ++i) m_perm_c.indices()(i) = i;
640  }
641 
642  Index m = m_mat.rows();
643  Index n = m_mat.cols();
644  Index nnz = m_mat.nonZeros();
645  Index maxpanel = m_perfv.panel_size * m;
646  // Allocate working storage common to the factor routines
647  Index lwork = 0;
648  // Return the size of actually allocated memory when allocation failed,
649  // and 0 on success.
650  Index info = Base::memInit(m, n, nnz, lwork, m_perfv.fillfactor, m_perfv.panel_size, m_glu);
651  if (info) {
652  m_lastError = "UNABLE TO ALLOCATE WORKING MEMORY\n\n";
653  m_factorizationIsOk = false;
654  return;
655  }
656 
657  // Set up pointers for integer working arrays
658  IndexVector segrep(m);
659  segrep.setZero();
660  IndexVector parent(m);
661  parent.setZero();
662  IndexVector xplore(m);
663  xplore.setZero();
664  IndexVector repfnz(maxpanel);
665  IndexVector panel_lsub(maxpanel);
666  IndexVector xprune(n);
667  xprune.setZero();
669  marker.setZero();
670 
671  repfnz.setConstant(-1);
672  panel_lsub.setConstant(-1);
673 
674  // Set up pointers for scalar working arrays
675  ScalarVector dense;
676  dense.setZero(maxpanel);
677  ScalarVector tempv;
678  tempv.setZero(internal::LUnumTempV(m, m_perfv.panel_size, m_perfv.maxsuper, /*m_perfv.rowblk*/ m));
679 
680  // Compute the inverse of perm_c
681  PermutationType iperm_c(m_perm_c.inverse());
682 
683  // Identify initial relaxed snodes
684  IndexVector relax_end(n);
685  if (m_symmetricmode == true)
686  Base::heap_relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
687  else
688  Base::relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
689 
690  m_perm_r.resize(m);
691  m_perm_r.indices().setConstant(-1);
692  marker.setConstant(-1);
693  m_detPermR = 1; // Record the determinant of the row permutation
694 
695  m_glu.supno(0) = emptyIdxLU;
696  m_glu.xsup.setConstant(0);
697  m_glu.xsup(0) = m_glu.xlsub(0) = m_glu.xusub(0) = m_glu.xlusup(0) = Index(0);
698 
699  // Work on one 'panel' at a time. A panel is one of the following :
700  // (a) a relaxed supernode at the bottom of the etree, or
701  // (b) panel_size contiguous columns, <panel_size> defined by the user
702  Index jcol;
703  Index pivrow; // Pivotal row number in the original row matrix
704  Index nseg1; // Number of segments in U-column above panel row jcol
705  Index nseg; // Number of segments in each U-column
706  Index irep;
707  Index i, k, jj;
708  for (jcol = 0; jcol < n;) {
709  // Adjust panel size so that a panel won't overlap with the next relaxed snode.
710  Index panel_size = m_perfv.panel_size; // upper bound on panel width
711  for (k = jcol + 1; k < (std::min)(jcol + panel_size, n); k++) {
712  if (relax_end(k) != emptyIdxLU) {
713  panel_size = k - jcol;
714  break;
715  }
716  }
717  if (k == n) panel_size = n - jcol;
718 
719  // Symbolic outer factorization on a panel of columns
720  Base::panel_dfs(m, panel_size, jcol, m_mat, m_perm_r.indices(), nseg1, dense, panel_lsub, segrep, repfnz, xprune,
721  marker, parent, xplore, m_glu);
722 
723  // Numeric sup-panel updates in topological order
724  Base::panel_bmod(m, panel_size, jcol, nseg1, dense, tempv, segrep, repfnz, m_glu);
725 
726  // Sparse LU within the panel, and below the panel diagonal
727  for (jj = jcol; jj < jcol + panel_size; jj++) {
728  k = (jj - jcol) * m; // Column index for w-wide arrays
729 
730  nseg = nseg1; // begin after all the panel segments
731  // Depth-first-search for the current column
732  VectorBlock<IndexVector> panel_lsubk(panel_lsub, k, m);
733  VectorBlock<IndexVector> repfnz_k(repfnz, k, m);
734  // Return 0 on success and > 0 number of bytes allocated when run out of space.
735  info = Base::column_dfs(m, jj, m_perm_r.indices(), m_perfv.maxsuper, nseg, panel_lsubk, segrep, repfnz_k, xprune,
736  marker, parent, xplore, m_glu);
737  if (info) {
738  m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_DFS() ";
739  m_info = NumericalIssue;
740  m_factorizationIsOk = false;
741  return;
742  }
743  // Numeric updates to this column
744  VectorBlock<ScalarVector> dense_k(dense, k, m);
745  VectorBlock<IndexVector> segrep_k(segrep, nseg1, m - nseg1);
746  // Return 0 on success and > 0 number of bytes allocated when run out of space.
747  info = Base::column_bmod(jj, (nseg - nseg1), dense_k, tempv, segrep_k, repfnz_k, jcol, m_glu);
748  if (info) {
749  m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_BMOD() ";
750  m_info = NumericalIssue;
751  m_factorizationIsOk = false;
752  return;
753  }
754 
755  // Copy the U-segments to ucol(*)
756  // Return 0 on success and > 0 number of bytes allocated when run out of space.
757  info = Base::copy_to_ucol(jj, nseg, segrep, repfnz_k, m_perm_r.indices(), dense_k, m_glu);
758  if (info) {
759  m_lastError = "UNABLE TO EXPAND MEMORY IN COPY_TO_UCOL() ";
760  m_info = NumericalIssue;
761  m_factorizationIsOk = false;
762  return;
763  }
764 
765  // Form the L-segment
766  // Return O if success, i > 0 if U(i, i) is exactly zero.
767  info = Base::pivotL(jj, m_diagpivotthresh, m_perm_r.indices(), iperm_c.indices(), pivrow, m_glu);
768  if (info) {
769  m_lastError = "THE MATRIX IS STRUCTURALLY SINGULAR";
770 #ifndef EIGEN_NO_IO
771  std::ostringstream returnInfo;
772  returnInfo << " ... ZERO COLUMN AT ";
773  returnInfo << info;
774  m_lastError += returnInfo.str();
775 #endif
776  m_info = NumericalIssue;
777  m_factorizationIsOk = false;
778  return;
779  }
780 
781  // Update the determinant of the row permutation matrix
782  // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not
783  // directly the row pivot.
784  if (pivrow != jj) m_detPermR = -m_detPermR;
785 
786  // Prune columns (0:jj-1) using column jj
787  Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu);
788 
789  // Reset repfnz for this column
790  for (i = 0; i < nseg; i++) {
791  irep = segrep(i);
792  repfnz_k(irep) = emptyIdxLU;
793  }
794  } // end SparseLU within the panel
795  jcol += panel_size; // Move to the next panel
796  } // end for -- end elimination
797 
798  m_detPermR = m_perm_r.determinant();
799  m_detPermC = m_perm_c.determinant();
800 
801  // Count the number of nonzeros in factors
802  Base::countnz(n, m_nnzL, m_nnzU, m_glu);
803  // Apply permutation to the L subscripts
804  Base::fixupL(n, m_perm_r.indices(), m_glu);
805 
806  // Create supernode matrix L
807  m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup);
808  // Create the column major upper sparse matrix U;
809  new (&m_Ustore) Map<SparseMatrix<Scalar, ColMajor, StorageIndex>>(m, n, m_nnzU, m_glu.xusub.data(), m_glu.usub.data(),
810  m_glu.ucol.data());
811 
812  m_info = Success;
813  m_factorizationIsOk = true;
814 }
815 
816 template <typename MappedSupernodalType>
819  explicit SparseLUMatrixLReturnType(const MappedSupernodalType& mapL) : m_mapL(mapL) {}
820  Index rows() const { return m_mapL.rows(); }
821  Index cols() const { return m_mapL.cols(); }
822  template <typename Dest>
824  m_mapL.solveInPlace(X);
825  }
826  template <bool Conjugate, typename Dest>
828  m_mapL.template solveTransposedInPlace<Conjugate>(X);
829  }
830 
832  ArrayXi colCount = ArrayXi::Ones(cols());
833  for (Index i = 0; i < cols(); i++) {
834  typename MappedSupernodalType::InnerIterator iter(m_mapL, i);
835  for (; iter; ++iter) {
836  if (iter.row() > iter.col()) {
837  colCount(iter.col())++;
838  }
839  }
840  }
842  sL.reserve(colCount);
843  for (Index i = 0; i < cols(); i++) {
844  sL.insert(i, i) = 1.0;
845  typename MappedSupernodalType::InnerIterator iter(m_mapL, i);
846  for (; iter; ++iter) {
847  if (iter.row() > iter.col()) {
848  sL.insert(iter.row(), iter.col()) = iter.value();
849  }
850  }
851  }
852  sL.makeCompressed();
853  return sL;
854  }
855 
856  const MappedSupernodalType& m_mapL;
857 };
858 
859 template <typename MatrixLType, typename MatrixUType>
861  typedef typename MatrixLType::Scalar Scalar;
862  SparseLUMatrixUReturnType(const MatrixLType& mapL, const MatrixUType& mapU) : m_mapL(mapL), m_mapU(mapU) {}
863  Index rows() const { return m_mapL.rows(); }
864  Index cols() const { return m_mapL.cols(); }
865 
866  template <typename Dest>
868  Index nrhs = X.cols();
869  // Backward solve with U
870  for (Index k = m_mapL.nsuper(); k >= 0; k--) {
871  Index fsupc = m_mapL.supToCol()[k];
872  Index lda = m_mapL.colIndexPtr()[fsupc + 1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
873  Index nsupc = m_mapL.supToCol()[k + 1] - fsupc;
874  Index luptr = m_mapL.colIndexPtr()[fsupc];
875 
876  if (nsupc == 1) {
877  for (Index j = 0; j < nrhs; j++) {
878  X(fsupc, j) /= m_mapL.valuePtr()[luptr];
879  }
880  } else {
881  // FIXME: the following lines should use Block expressions and not Map!
883  nsupc, OuterStride<>(lda));
884  typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
885  U = A.template triangularView<Upper>().solve(U);
886  }
887 
888  for (Index j = 0; j < nrhs; ++j) {
889  for (Index jcol = fsupc; jcol < fsupc + nsupc; jcol++) {
890  typename MatrixUType::InnerIterator it(m_mapU, jcol);
891  for (; it; ++it) {
892  Index irow = it.index();
893  X(irow, j) -= X(jcol, j) * it.value();
894  }
895  }
896  }
897  } // End For U-solve
898  }
899 
900  template <bool Conjugate, typename Dest>
902  using numext::conj;
903  Index nrhs = X.cols();
904  // Forward solve with U
905  for (Index k = 0; k <= m_mapL.nsuper(); k++) {
906  Index fsupc = m_mapL.supToCol()[k];
907  Index lda = m_mapL.colIndexPtr()[fsupc + 1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
908  Index nsupc = m_mapL.supToCol()[k + 1] - fsupc;
909  Index luptr = m_mapL.colIndexPtr()[fsupc];
910 
911  for (Index j = 0; j < nrhs; ++j) {
912  for (Index jcol = fsupc; jcol < fsupc + nsupc; jcol++) {
913  typename MatrixUType::InnerIterator it(m_mapU, jcol);
914  for (; it; ++it) {
915  Index irow = it.index();
916  X(jcol, j) -= X(irow, j) * (Conjugate ? conj(it.value()) : it.value());
917  }
918  }
919  }
920  if (nsupc == 1) {
921  for (Index j = 0; j < nrhs; j++) {
922  X(fsupc, j) /= (Conjugate ? conj(m_mapL.valuePtr()[luptr]) : m_mapL.valuePtr()[luptr]);
923  }
924  } else {
926  nsupc, OuterStride<>(lda));
927  typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
928  if (Conjugate)
929  U = A.adjoint().template triangularView<Lower>().solve(U);
930  else
931  U = A.transpose().template triangularView<Lower>().solve(U);
932  }
933  } // End For U-solve
934  }
935 
937  ArrayXi rowCount = ArrayXi::Zero(rows());
938  for (Index i = 0; i < cols(); i++) {
939  typename MatrixLType::InnerIterator iter(m_mapL, i);
940  for (; iter; ++iter) {
941  if (iter.row() <= iter.col()) {
942  rowCount(iter.row())++;
943  }
944  }
945  }
946 
948  sU.reserve(rowCount);
949  for (Index i = 0; i < cols(); i++) {
950  typename MatrixLType::InnerIterator iter(m_mapL, i);
951  for (; iter; ++iter) {
952  if (iter.row() <= iter.col()) {
953  sU.insert(iter.row(), iter.col()) = iter.value();
954  }
955  }
956  }
957  sU.makeCompressed();
958  const SparseMatrix<Scalar, RowMajor, Index> u = m_mapU; // convert to RowMajor
959  sU += u;
960  return sU;
961  }
962 
963  const MatrixLType& m_mapL;
964  const MatrixUType& m_mapU;
965 };
966 
967 } // End namespace Eigen
968 
969 #endif
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar conj(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:133
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Eigen::SparseMatrix< double > mat
Definition: EigenUnitTest.cpp:10
#define eigen_assert(x)
Definition: Macros.h:910
#define ei_declare_aligned_stack_constructed_variable(TYPE, NAME, SIZE, BUFFER)
Definition: Memory.h:806
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
SCALAR Scalar
Definition: bench_gemm.cpp:45
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
MatrixXf MatrixType
Definition: benchmark-blocking-sizes.cpp:52
Definition: ForwardDeclarations.h:102
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:96
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:104
InverseReturnType inverse() const
Definition: PermutationMatrix.h:172
const IndicesType & indices() const
Definition: PermutationMatrix.h:334
EIGEN_DEVICE_FUNC Derived & setZero(Index size)
Definition: CwiseNullaryOp.h:569
EIGEN_DEVICE_FUNC Derived & setConstant(Index size, const Scalar &val)
Definition: CwiseNullaryOp.h:365
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
Definition: PlainObjectBase.h:294
Pseudo expression representing a solving operation.
Definition: Solve.h:62
Definition: SparseLU.h:27
SparseLUType::MatrixType MatrixType
Definition: SparseLU.h:35
Index cols() const
Definition: SparseLU.h:69
SparseLUType * m_sparseLU
Definition: SparseLU.h:72
void setSparseLU(SparseLUType *sparseLU)
Definition: SparseLU.h:46
SparseSolverBase< SparseLUTransposeView< Conjugate, SparseLUType > > APIBase
Definition: SparseLU.h:29
@ MaxColsAtCompileTime
Definition: SparseLU.h:38
@ ColsAtCompileTime
Definition: SparseLU.h:38
SparseLUType::Scalar Scalar
Definition: SparseLU.h:33
bool _solve_impl(const MatrixBase< Rhs > &B, MatrixBase< Dest > &X_base) const
Definition: SparseLU.h:49
SparseLUTransposeView & operator=(const SparseLUTransposeView &)
void setIsInitialized(const bool isInitialized)
Definition: SparseLU.h:45
SparseLUTransposeView()
Definition: SparseLU.h:40
Index rows() const
Definition: SparseLU.h:68
SparseLUType::OrderingType OrderingType
Definition: SparseLU.h:36
SparseLUTransposeView(const SparseLUTransposeView &view)
Definition: SparseLU.h:41
SparseLUType::StorageIndex StorageIndex
Definition: SparseLU.h:34
Sparse supernodal LU factorization for general matrices.
Definition: SparseLU.h:151
SparseLU(const SparseLU &)
std::string m_lastError
Definition: SparseLU.h:488
void setPivotThreshold(const RealScalar &thresh)
Definition: SparseLU.h:301
Index cols() const
Give the number of columns.
Definition: SparseLU.h:262
Scalar logAbsDeterminant() const
Give the natural log of the absolute determinant.
Definition: SparseLU.h:399
Matrix< Scalar, Dynamic, 1 > ScalarVector
Definition: SparseLU.h:166
Index rows() const
Give the number of rows.
Definition: SparseLU.h:259
~SparseLU()
Definition: SparseLU.h:192
Index nnzU() const
Give the number of non zero in matrix U.
Definition: SparseLU.h:471
MatrixType::Scalar Scalar
Definition: SparseLU.h:161
SparseSolverBase< SparseLU< MatrixType_, OrderingType_ > > APIBase
Definition: SparseLU.h:153
bool m_factorizationIsOk
Definition: SparseLU.h:486
SparseLUMatrixUReturnType< SCMatrix, Map< SparseMatrix< Scalar, ColMajor, StorageIndex > > > matrixU() const
Give the MatrixU.
Definition: SparseLU.h:284
MatrixType::RealScalar RealScalar
Definition: SparseLU.h:162
PermutationType m_perm_c
Definition: SparseLU.h:492
void factorize(const MatrixType &matrix)
Factorize the matrix to get the solver ready.
Definition: SparseLU.h:611
Index m_detPermR
Definition: SparseLU.h:504
const PermutationType & rowsPermutation() const
Give the row matrix permutation.
Definition: SparseLU.h:293
NCMatrix m_mat
Definition: SparseLU.h:489
Map< SparseMatrix< Scalar, ColMajor, StorageIndex > > m_Ustore
Definition: SparseLU.h:491
std::string lastErrorMessage() const
Give a human readable error.
Definition: SparseLU.h:335
Matrix< StorageIndex, Dynamic, 1 > IndexVector
Definition: SparseLU.h:167
SparseLUMatrixLReturnType< SCMatrix > matrixL() const
Give the matrixL.
Definition: SparseLU.h:275
SCMatrix m_Lstore
Definition: SparseLU.h:490
Index m_nnzU
Definition: SparseLU.h:503
void compute(const MatrixType &matrix)
Analyze and factorize the matrix so the solver is ready to solve.
Definition: SparseLU.h:210
const SparseLUTransposeView< false, SparseLU< MatrixType_, OrderingType_ > > transpose()
Return a solver for the transposed matrix.
Definition: SparseLU.h:229
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: SparseLU.h:326
bool m_analysisIsOk
Definition: SparseLU.h:487
Scalar signDeterminant()
Give the sign of the determinant.
Definition: SparseLU.h:423
SparseMatrix< Scalar, ColMajor, StorageIndex > NCMatrix
Definition: SparseLU.h:164
void initperfvalues()
Definition: SparseLU.h:475
@ ColsAtCompileTime
Definition: SparseLU.h:171
@ MaxColsAtCompileTime
Definition: SparseLU.h:171
bool _solve_impl(const MatrixBase< Rhs > &B, MatrixBase< Dest > &X_base) const
Definition: SparseLU.h:338
void simplicialfactorize(const MatrixType &matrix)
bool m_symmetricmode
Definition: SparseLU.h:499
SparseLU()
Basic constructor of the solver.
Definition: SparseLU.h:178
Scalar absDeterminant()
Give the absolute value of the determinant.
Definition: SparseLU.h:371
internal::perfvalues m_perfv
Definition: SparseLU.h:501
OrderingType_ OrderingType
Definition: SparseLU.h:160
Index m_detPermC
Definition: SparseLU.h:504
internal::MappedSuperNodalMatrix< Scalar, StorageIndex > SCMatrix
Definition: SparseLU.h:165
void analyzePattern(const MatrixType &matrix)
Compute the column permutation.
Definition: SparseLU.h:528
Index nnzL() const
Give the number of non zero in matrix L.
Definition: SparseLU.h:468
Index m_nnzL
Definition: SparseLU.h:503
PermutationMatrix< Dynamic, Dynamic, StorageIndex > PermutationType
Definition: SparseLU.h:168
MatrixType_ MatrixType
Definition: SparseLU.h:159
IndexVector m_etree
Definition: SparseLU.h:494
PermutationType m_perm_r
Definition: SparseLU.h:493
void isSymmetric(bool sym)
Let you set that the pattern of the input matrix is symmetric.
Definition: SparseLU.h:265
const PermutationType & colsPermutation() const
Give the column matrix permutation.
Definition: SparseLU.h:299
Base::GlobalLU_t m_glu
Definition: SparseLU.h:496
RealScalar m_diagpivotthresh
Definition: SparseLU.h:502
SparseLU(const MatrixType &matrix)
Constructor of the solver already based on a specific matrix.
Definition: SparseLU.h:186
Scalar determinant()
Give the determinant.
Definition: SparseLU.h:449
const SparseLUTransposeView< true, SparseLU< MatrixType_, OrderingType_ > > adjoint()
Return a solver for the adjointed matrix.
Definition: SparseLU.h:250
MatrixType::StorageIndex StorageIndex
Definition: SparseLU.h:163
ComputationInfo m_info
Definition: SparseLU.h:485
internal::SparseLUImpl< Scalar, StorageIndex > Base
Definition: SparseLU.h:169
Index cols() const
Definition: SparseMatrix.h:161
void makeCompressed()
Definition: SparseMatrix.h:589
bool isCompressed() const
Definition: SparseCompressedBase.h:114
Index rows() const
Definition: SparseMatrix.h:159
const StorageIndex * outerIndexPtr() const
Definition: SparseMatrix.h:189
void reserve(Index reserveSize)
Definition: SparseMatrix.h:315
Scalar & insert(Index row, Index col)
Definition: SparseMatrix.h:1586
A base class for sparse solvers.
Definition: SparseSolverBase.h:67
const Solve< SparseLU< MatrixType_, OrderingType_ >, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition: SparseSolverBase.h:84
void _solve_impl(const SparseMatrixBase< Rhs > &b, SparseMatrixBase< Dest > &dest) const
Definition: SparseSolverBase.h:104
Expression of a fixed-size or dynamic-size sub-vector.
Definition: VectorBlock.h:58
Definition: SparseLUImpl.h:23
Definition: XprHelper.h:134
Definition: matrices.h:74
Eigen::Map< Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor >, 0, Eigen::OuterStride<> > matrix(T *data, int rows, int cols, int stride)
Definition: common.h:85
#define min(a, b)
Definition: datatypes.h:22
ComputationInfo
Definition: Constants.h:438
@ NumericalIssue
Definition: Constants.h:442
@ Success
Definition: Constants.h:440
const unsigned int RowMajorBit
Definition: Constants.h:70
#define X
Definition: icosphere.cpp:20
const char const int const RealScalar const RealScalar const int * lda
Definition: level2_cplx_impl.h:20
int * m
Definition: level2_cplx_impl.h:294
int info
Definition: level2_cplx_impl.h:39
char char char int int * k
Definition: level2_impl.h:374
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 log(const bfloat16 &a)
Definition: BFloat16.h:618
Index LUnumTempV(Index &m, Index &w, Index &t, Index &b)
Definition: SparseLU_Memory.h:42
@ LUNoMarker
Definition: SparseLU_Memory.h:40
@ emptyIdxLU
Definition: SparseLU_Memory.h:41
int coletree(const MatrixType &mat, IndexVector &parent, IndexVector &firstRowElt, typename MatrixType::StorageIndex *perm=0)
Definition: SparseColEtree.h:61
void treePostorder(typename IndexVector::Scalar n, IndexVector &parent, IndexVector &post)
Post order a tree.
Definition: SparseColEtree.h:168
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
const AutoDiffScalar< DerType > & conj(const AutoDiffScalar< DerType > &x)
Definition: AutoDiffScalar.h:482
double U
Swimming speed.
Definition: two_d_variable_diff_adapt.cc:53
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
double Zero
Definition: pseudosolid_node_update_elements.cc:35
void fixupL(const int, const int *, GlobalLU_t *)
void countnz(const int, int *, int *, int *, GlobalLU_t *)
void relax_snode(const int, int *, const int, int *, int *)
void heap_relax_snode(const int, int *, const int, int *, int *)
Definition: SparseLU.h:817
void solveTransposedInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:827
const MappedSupernodalType & m_mapL
Definition: SparseLU.h:856
Index rows() const
Definition: SparseLU.h:820
Index cols() const
Definition: SparseLU.h:821
SparseLUMatrixLReturnType(const MappedSupernodalType &mapL)
Definition: SparseLU.h:819
void solveInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:823
SparseMatrix< Scalar, ColMajor, Index > toSparse() const
Definition: SparseLU.h:831
MappedSupernodalType::Scalar Scalar
Definition: SparseLU.h:818
Definition: SparseLU.h:860
const MatrixUType & m_mapU
Definition: SparseLU.h:964
Index cols() const
Definition: SparseLU.h:864
SparseMatrix< Scalar, RowMajor, Index > toSparse()
Definition: SparseLU.h:936
SparseLUMatrixUReturnType(const MatrixLType &mapL, const MatrixUType &mapU)
Definition: SparseLU.h:862
Index rows() const
Definition: SparseLU.h:863
void solveInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:867
const MatrixLType & m_mapL
Definition: SparseLU.h:963
void solveTransposedInPlace(MatrixBase< Dest > &X) const
Definition: SparseLU.h:901
MatrixLType::Scalar Scalar
Definition: SparseLU.h:861
Definition: SparseLU_Structs.h:80
Definition: SparseLU_Structs.h:99
Index relax
Definition: SparseLU_Structs.h:101
Index panel_size
Definition: SparseLU_Structs.h:100
Index maxsuper
Definition: SparseLU_Structs.h:104
Index rowblk
Definition: SparseLU_Structs.h:105
Index colblk
Definition: SparseLU_Structs.h:106
Index fillfactor
Definition: SparseLU_Structs.h:107
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2