Medial Code Documentation
Loading...
Searching...
No Matches
SparseLU.h
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
15namespace Eigen {
16
17template <typename _MatrixType, typename _OrderingType = COLAMDOrdering<typename _MatrixType::StorageIndex> > class SparseLU;
18template <typename MappedSparseMatrixType> struct SparseLUMatrixLReturnType;
19template <typename MatrixLType, typename MatrixUType> struct SparseLUMatrixUReturnType;
20
21template <bool Conjugate,class SparseLUType>
22class SparseLUTransposeView : public SparseSolverBase<SparseLUTransposeView<Conjugate,SparseLUType> >
23{
24protected:
26 using APIBase::m_isInitialized;
27public:
28 typedef typename SparseLUType::Scalar Scalar;
29 typedef typename SparseLUType::StorageIndex StorageIndex;
30 typedef typename SparseLUType::MatrixType MatrixType;
31 typedef typename SparseLUType::OrderingType OrderingType;
32
33 enum {
34 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
35 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
36 };
37
38 SparseLUTransposeView() : APIBase(), m_sparseLU(NULL) {}
40 this->m_sparseLU = view.m_sparseLU;
41 this->m_isInitialized = view.m_isInitialized;
42 }
43 void setIsInitialized(const bool isInitialized) {this->m_isInitialized = isInitialized;}
44 void setSparseLU(SparseLUType* sparseLU) {m_sparseLU = sparseLU;}
45 using APIBase::_solve_impl;
46 template<typename Rhs, typename Dest>
47 bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &X_base) const
48 {
49 Dest& X(X_base.derived());
50 eigen_assert(m_sparseLU->info() == Success && "The matrix should be factorized first");
51 EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
52 THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
53
54
55 // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
56 for(Index j = 0; j < B.cols(); ++j){
57 X.col(j) = m_sparseLU->colsPermutation() * B.const_cast_derived().col(j);
58 }
59 //Forward substitution with transposed or adjoint of U
60 m_sparseLU->matrixU().template solveTransposedInPlace<Conjugate>(X);
61
62 //Backward substitution with transposed or adjoint of L
63 m_sparseLU->matrixL().template solveTransposedInPlace<Conjugate>(X);
64
65 // Permute back the solution
66 for (Index j = 0; j < B.cols(); ++j)
67 X.col(j) = m_sparseLU->rowsPermutation().transpose() * X.col(j);
68 return true;
69 }
70 inline Index rows() const { return m_sparseLU->rows(); }
71 inline Index cols() const { return m_sparseLU->cols(); }
72
73private:
74 SparseLUType *m_sparseLU;
76};
77
78
131template <typename _MatrixType, typename _OrderingType>
132class SparseLU : public SparseSolverBase<SparseLU<_MatrixType,_OrderingType> >, public internal::SparseLUImpl<typename _MatrixType::Scalar, typename _MatrixType::StorageIndex>
133{
134 protected:
136 using APIBase::m_isInitialized;
137 public:
138 using APIBase::_solve_impl;
139
140 typedef _MatrixType MatrixType;
142 typedef typename MatrixType::Scalar Scalar;
143 typedef typename MatrixType::RealScalar RealScalar;
144 typedef typename MatrixType::StorageIndex StorageIndex;
151
152 enum {
153 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
154 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
155 };
156
157 public:
158
159 SparseLU():m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1)
160 {
161 initperfvalues();
162 }
163 explicit SparseLU(const MatrixType& matrix)
164 : m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1)
165 {
166 initperfvalues();
167 compute(matrix);
168 }
169
170 ~SparseLU()
171 {
172 // Free all explicit dynamic pointers
173 }
174
175 void analyzePattern (const MatrixType& matrix);
176 void factorize (const MatrixType& matrix);
177 void simplicialfactorize(const MatrixType& matrix);
178
183 void compute (const MatrixType& matrix)
184 {
185 // Analyze
186 analyzePattern(matrix);
187 //Factorize
188 factorize(matrix);
189 }
190
208
209
229
230 inline Index rows() const { return m_mat.rows(); }
231 inline Index cols() const { return m_mat.cols(); }
233 void isSymmetric(bool sym)
234 {
235 m_symmetricmode = sym;
236 }
237
258
263 inline const PermutationType& rowsPermutation() const
264 {
265 return m_perm_r;
266 }
271 inline const PermutationType& colsPermutation() const
272 {
273 return m_perm_c;
274 }
276 void setPivotThreshold(const RealScalar& thresh)
277 {
278 m_diagpivotthresh = thresh;
279 }
280
281#ifdef EIGEN_PARSED_BY_DOXYGEN
288 template<typename Rhs>
289 inline const Solve<SparseLU, Rhs> solve(const MatrixBase<Rhs>& B) const;
290#endif // EIGEN_PARSED_BY_DOXYGEN
291
301 {
302 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
303 return m_info;
304 }
305
309 std::string lastErrorMessage() const
310 {
311 return m_lastError;
312 }
313
314 template<typename Rhs, typename Dest>
315 bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &X_base) const
316 {
317 Dest& X(X_base.derived());
318 eigen_assert(m_factorizationIsOk && "The matrix should be factorized first");
319 EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
320 THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
321
322 // Permute the right hand side to form X = Pr*B
323 // on return, X is overwritten by the computed solution
324 X.resize(B.rows(),B.cols());
325
326 // this ugly const_cast_derived() helps to detect aliasing when applying the permutations
327 for(Index j = 0; j < B.cols(); ++j)
328 X.col(j) = rowsPermutation() * B.const_cast_derived().col(j);
329
330 //Forward substitution with L
331 this->matrixL().solveInPlace(X);
332 this->matrixU().solveInPlace(X);
333
334 // Permute back the solution
335 for (Index j = 0; j < B.cols(); ++j)
336 X.col(j) = colsPermutation().inverse() * X.col(j);
337
338 return true;
339 }
340
352 {
353 using std::abs;
354 eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
355 // Initialize with the determinant of the row matrix
356 Scalar det = Scalar(1.);
357 // Note that the diagonal blocks of U are stored in supernodes,
358 // which are available in the L part :)
359 for (Index j = 0; j < this->cols(); ++j)
360 {
361 for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
362 {
363 if(it.index() == j)
364 {
365 det *= abs(it.value());
366 break;
367 }
368 }
369 }
370 return det;
371 }
372
381 Scalar logAbsDeterminant() const
382 {
383 using std::log;
384 using std::abs;
385
386 eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
387 Scalar det = Scalar(0.);
388 for (Index j = 0; j < this->cols(); ++j)
389 {
390 for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
391 {
392 if(it.row() < j) continue;
393 if(it.row() == j)
394 {
395 det += log(abs(it.value()));
396 break;
397 }
398 }
399 }
400 return det;
401 }
402
408 {
409 eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
410 // Initialize with the determinant of the row matrix
411 Index det = 1;
412 // Note that the diagonal blocks of U are stored in supernodes,
413 // which are available in the L part :)
414 for (Index j = 0; j < this->cols(); ++j)
415 {
416 for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
417 {
418 if(it.index() == j)
419 {
420 if(it.value()<0)
421 det = -det;
422 else if(it.value()==0)
423 return 0;
424 break;
425 }
426 }
427 }
428 return det * m_detPermR * m_detPermC;
429 }
430
435 Scalar determinant()
436 {
437 eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
438 // Initialize with the determinant of the row matrix
439 Scalar det = Scalar(1.);
440 // Note that the diagonal blocks of U are stored in supernodes,
441 // which are available in the L part :)
442 for (Index j = 0; j < this->cols(); ++j)
443 {
444 for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
445 {
446 if(it.index() == j)
447 {
448 det *= it.value();
449 break;
450 }
451 }
452 }
453 return (m_detPermR * m_detPermC) > 0 ? det : -det;
454 }
455
456 Index nnzL() const { return m_nnzL; };
457 Index nnzU() const { return m_nnzU; };
458
459 protected:
460 // Functions
461 void initperfvalues()
462 {
463 m_perfv.panel_size = 16;
464 m_perfv.relax = 1;
465 m_perfv.maxsuper = 128;
466 m_perfv.rowblk = 16;
467 m_perfv.colblk = 8;
468 m_perfv.fillfactor = 20;
469 }
470
471 // Variables
472 mutable ComputationInfo m_info;
473 bool m_factorizationIsOk;
474 bool m_analysisIsOk;
475 std::string m_lastError;
476 NCMatrix m_mat; // The input (permuted ) matrix
477 SCMatrix m_Lstore; // The lower triangular matrix (supernodal)
478 MappedSparseMatrix<Scalar,ColMajor,StorageIndex> m_Ustore; // The upper triangular matrix
479 PermutationType m_perm_c; // Column permutation
480 PermutationType m_perm_r ; // Row permutation
481 IndexVector m_etree; // Column elimination tree
482
483 typename Base::GlobalLU_t m_glu;
484
485 // SparseLU options
486 bool m_symmetricmode;
487 // values for performance
488 internal::perfvalues m_perfv;
489 RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
490 Index m_nnzL, m_nnzU; // Nonzeros in L and U factors
491 Index m_detPermR, m_detPermC; // Determinants of the permutation matrices
492 private:
493 // Disable copy constructor
494 SparseLU (const SparseLU& );
495}; // End class SparseLU
496
497
498
499// Functions needed by the anaysis phase
510template <typename MatrixType, typename OrderingType>
512{
513
514 //TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat.
515
516 // Firstly, copy the whole input matrix.
517 m_mat = mat;
518
519 // Compute fill-in ordering
521 ord(m_mat,m_perm_c);
522
523 // Apply the permutation to the column of the input matrix
524 if (m_perm_c.size())
525 {
526 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.
527 // Then, permute only the column pointers
528 ei_declare_aligned_stack_constructed_variable(StorageIndex,outerIndexPtr,mat.cols()+1,mat.isCompressed()?const_cast<StorageIndex*>(mat.outerIndexPtr()):0);
529
530 // 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.
531 if(!mat.isCompressed())
532 IndexVector::Map(outerIndexPtr, mat.cols()+1) = IndexVector::Map(m_mat.outerIndexPtr(),mat.cols()+1);
533
534 // Apply the permutation and compute the nnz per column.
535 for (Index i = 0; i < mat.cols(); i++)
536 {
537 m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
538 m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i+1] - outerIndexPtr[i];
539 }
540 }
541
542 // Compute the column elimination tree of the permuted matrix
544 internal::coletree(m_mat, m_etree,firstRowElt);
545
546 // In symmetric mode, do not do postorder here
547 if (!m_symmetricmode) {
549 // Post order etree
550 internal::treePostorder(StorageIndex(m_mat.cols()), m_etree, post);
551
552
553 // Renumber etree in postorder
554 Index m = m_mat.cols();
555 iwork.resize(m+1);
556 for (Index i = 0; i < m; ++i) iwork(post(i)) = post(m_etree(i));
557 m_etree = iwork;
558
559 // Postmultiply A*Pc by post, i.e reorder the matrix according to the postorder of the etree
561 for (Index i = 0; i < m; i++)
562 post_perm.indices()(i) = post(i);
563
564 // Combine the two permutations : postorder the permutation for future use
565 if(m_perm_c.size()) {
566 m_perm_c = post_perm * m_perm_c;
567 }
568
569 } // end postordering
570
571 m_analysisIsOk = true;
572}
573
574// Functions needed by the numerical factorization phase
575
576
595template <typename MatrixType, typename OrderingType>
597{
598 using internal::emptyIdxLU;
599 eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
600 eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices");
601
602 m_isInitialized = true;
603
604 // Apply the column permutation computed in analyzepattern()
605 // m_mat = matrix * m_perm_c.inverse();
606 m_mat = matrix;
607 if (m_perm_c.size())
608 {
609 m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers.
610 //Then, permute only the column pointers
611 const StorageIndex * outerIndexPtr;
612 if (matrix.isCompressed()) outerIndexPtr = matrix.outerIndexPtr();
613 else
614 {
615 StorageIndex* outerIndexPtr_t = new StorageIndex[matrix.cols()+1];
616 for(Index i = 0; i <= matrix.cols(); i++) outerIndexPtr_t[i] = m_mat.outerIndexPtr()[i];
617 outerIndexPtr = outerIndexPtr_t;
618 }
619 for (Index i = 0; i < matrix.cols(); i++)
620 {
621 m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i];
622 m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i+1] - outerIndexPtr[i];
623 }
624 if(!matrix.isCompressed()) delete[] outerIndexPtr;
625 }
626 else
627 { //FIXME This should not be needed if the empty permutation is handled transparently
628 m_perm_c.resize(matrix.cols());
629 for(StorageIndex i = 0; i < matrix.cols(); ++i) m_perm_c.indices()(i) = i;
630 }
631
632 Index m = m_mat.rows();
633 Index n = m_mat.cols();
634 Index nnz = m_mat.nonZeros();
635 Index maxpanel = m_perfv.panel_size * m;
636 // Allocate working storage common to the factor routines
637 Index lwork = 0;
638 Index info = Base::memInit(m, n, nnz, lwork, m_perfv.fillfactor, m_perfv.panel_size, m_glu);
639 if (info)
640 {
641 m_lastError = "UNABLE TO ALLOCATE WORKING MEMORY\n\n" ;
642 m_factorizationIsOk = false;
643 return ;
644 }
645
646 // Set up pointers for integer working arrays
648 IndexVector parent(m); parent.setZero();
653 IndexVector marker(m*internal::LUNoMarker); marker.setZero();
654
655 repfnz.setConstant(-1);
657
658 // Set up pointers for scalar working arrays
662 tempv.setZero(internal::LUnumTempV(m, m_perfv.panel_size, m_perfv.maxsuper, /*m_perfv.rowblk*/m) );
663
664 // Compute the inverse of perm_c
665 PermutationType iperm_c(m_perm_c.inverse());
666
667 // Identify initial relaxed snodes
669 if ( m_symmetricmode == true )
670 Base::heap_relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
671 else
672 Base::relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
673
674
675 m_perm_r.resize(m);
676 m_perm_r.indices().setConstant(-1);
678 m_detPermR = 1; // Record the determinant of the row permutation
679
680 m_glu.supno(0) = emptyIdxLU; m_glu.xsup.setConstant(0);
681 m_glu.xsup(0) = m_glu.xlsub(0) = m_glu.xusub(0) = m_glu.xlusup(0) = Index(0);
682
683 // Work on one 'panel' at a time. A panel is one of the following :
684 // (a) a relaxed supernode at the bottom of the etree, or
685 // (b) panel_size contiguous columns, <panel_size> defined by the user
686 Index jcol;
687 Index pivrow; // Pivotal row number in the original row matrix
688 Index nseg1; // Number of segments in U-column above panel row jcol
689 Index nseg; // Number of segments in each U-column
690 Index irep;
691 Index i, k, jj;
692 for (jcol = 0; jcol < n; )
693 {
694 // Adjust panel size so that a panel won't overlap with the next relaxed snode.
695 Index panel_size = m_perfv.panel_size; // upper bound on panel width
696 for (k = jcol + 1; k < (std::min)(jcol+panel_size, n); k++)
697 {
698 if (relax_end(k) != emptyIdxLU)
699 {
700 panel_size = k - jcol;
701 break;
702 }
703 }
704 if (k == n)
705 panel_size = n - jcol;
706
707 // Symbolic outer factorization on a panel of columns
708 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);
709
710 // Numeric sup-panel updates in topological order
711 Base::panel_bmod(m, panel_size, jcol, nseg1, dense, tempv, segrep, repfnz, m_glu);
712
713 // Sparse LU within the panel, and below the panel diagonal
714 for ( jj = jcol; jj< jcol + panel_size; jj++)
715 {
716 k = (jj - jcol) * m; // Column index for w-wide arrays
717
718 nseg = nseg1; // begin after all the panel segments
719 //Depth-first-search for the current column
722 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);
723 if ( info )
724 {
725 m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_DFS() ";
726 m_info = NumericalIssue;
727 m_factorizationIsOk = false;
728 return;
729 }
730 // Numeric updates to this column
733 info = Base::column_bmod(jj, (nseg - nseg1), dense_k, tempv, segrep_k, repfnz_k, jcol, m_glu);
734 if ( info )
735 {
736 m_lastError = "UNABLE TO EXPAND MEMORY IN COLUMN_BMOD() ";
737 m_info = NumericalIssue;
738 m_factorizationIsOk = false;
739 return;
740 }
741
742 // Copy the U-segments to ucol(*)
743 info = Base::copy_to_ucol(jj, nseg, segrep, repfnz_k ,m_perm_r.indices(), dense_k, m_glu);
744 if ( info )
745 {
746 m_lastError = "UNABLE TO EXPAND MEMORY IN COPY_TO_UCOL() ";
747 m_info = NumericalIssue;
748 m_factorizationIsOk = false;
749 return;
750 }
751
752 // Form the L-segment
753 info = Base::pivotL(jj, m_diagpivotthresh, m_perm_r.indices(), iperm_c.indices(), pivrow, m_glu);
754 if ( info )
755 {
756 m_lastError = "THE MATRIX IS STRUCTURALLY SINGULAR";
757#ifndef EIGEN_NO_IO
758 std::ostringstream returnInfo;
759 returnInfo << " ... ZERO COLUMN AT ";
760 returnInfo << info;
761 m_lastError += returnInfo.str();
762#endif
763 m_info = NumericalIssue;
764 m_factorizationIsOk = false;
765 return;
766 }
767
768 // Update the determinant of the row permutation matrix
769 // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not directly the row pivot.
770 if (pivrow != jj) m_detPermR = -m_detPermR;
771
772 // Prune columns (0:jj-1) using column jj
773 Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu);
774
775 // Reset repfnz for this column
776 for (i = 0; i < nseg; i++)
777 {
778 irep = segrep(i);
779 repfnz_k(irep) = emptyIdxLU;
780 }
781 } // end SparseLU within the panel
782 jcol += panel_size; // Move to the next panel
783 } // end for -- end elimination
784
785 m_detPermR = m_perm_r.determinant();
786 m_detPermC = m_perm_c.determinant();
787
788 // Count the number of nonzeros in factors
789 Base::countnz(n, m_nnzL, m_nnzU, m_glu);
790 // Apply permutation to the L subscripts
791 Base::fixupL(n, m_perm_r.indices(), m_glu);
792
793 // Create supernode matrix L
794 m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup);
795 // Create the column major upper sparse matrix U;
796 new (&m_Ustore) MappedSparseMatrix<Scalar, ColMajor, StorageIndex> ( m, n, m_nnzU, m_glu.xusub.data(), m_glu.usub.data(), m_glu.ucol.data() );
797
798 m_info = Success;
799 m_factorizationIsOk = true;
800}
801
802template<typename MappedSupernodalType>
804{
805 typedef typename MappedSupernodalType::Scalar Scalar;
807 { }
808 Index rows() const { return m_mapL.rows(); }
809 Index cols() const { return m_mapL.cols(); }
810 template<typename Dest>
811 void solveInPlace( MatrixBase<Dest> &X) const
812 {
813 m_mapL.solveInPlace(X);
814 }
815 template<bool Conjugate, typename Dest>
816 void solveTransposedInPlace( MatrixBase<Dest> &X) const
817 {
818 m_mapL.template solveTransposedInPlace<Conjugate>(X);
819 }
820
821 const MappedSupernodalType& m_mapL;
822};
823
824template<typename MatrixLType, typename MatrixUType>
826{
827 typedef typename MatrixLType::Scalar Scalar;
828 SparseLUMatrixUReturnType(const MatrixLType& mapL, const MatrixUType& mapU)
829 : m_mapL(mapL),m_mapU(mapU)
830 { }
831 Index rows() const { return m_mapL.rows(); }
832 Index cols() const { return m_mapL.cols(); }
833
834 template<typename Dest> void solveInPlace(MatrixBase<Dest> &X) const
835 {
836 Index nrhs = X.cols();
837 // Backward solve with U
838 for (Index k = m_mapL.nsuper(); k >= 0; k--)
839 {
840 Index fsupc = m_mapL.supToCol()[k];
841 Index lda = m_mapL.colIndexPtr()[fsupc+1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
842 Index nsupc = m_mapL.supToCol()[k+1] - fsupc;
843 Index luptr = m_mapL.colIndexPtr()[fsupc];
844
845 if (nsupc == 1)
846 {
847 for (Index j = 0; j < nrhs; j++)
848 {
849 X(fsupc, j) /= m_mapL.valuePtr()[luptr];
850 }
851 }
852 else
853 {
854 // FIXME: the following lines should use Block expressions and not Map!
856 typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
857 U = A.template triangularView<Upper>().solve(U);
858 }
859
860 for (Index j = 0; j < nrhs; ++j)
861 {
862 for (Index jcol = fsupc; jcol < fsupc + nsupc; jcol++)
863 {
864 typename MatrixUType::InnerIterator it(m_mapU, jcol);
865 for ( ; it; ++it)
866 {
867 Index irow = it.index();
868 X(irow, j) -= X(jcol, j) * it.value();
869 }
870 }
871 }
872 } // End For U-solve
873 }
874
875 template<bool Conjugate, typename Dest> void solveTransposedInPlace(MatrixBase<Dest> &X) const
876 {
877 using numext::conj;
878 Index nrhs = X.cols();
879 // Forward solve with U
880 for (Index k = 0; k <= m_mapL.nsuper(); k++)
881 {
882 Index fsupc = m_mapL.supToCol()[k];
883 Index lda = m_mapL.colIndexPtr()[fsupc+1] - m_mapL.colIndexPtr()[fsupc]; // leading dimension
884 Index nsupc = m_mapL.supToCol()[k+1] - fsupc;
885 Index luptr = m_mapL.colIndexPtr()[fsupc];
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(jcol, j) -= X(irow, j) * (Conjugate? conj(it.value()): it.value());
896 }
897 }
898 }
899 if (nsupc == 1)
900 {
901 for (Index j = 0; j < nrhs; j++)
902 {
903 X(fsupc, j) /= (Conjugate? conj(m_mapL.valuePtr()[luptr]) : m_mapL.valuePtr()[luptr]);
904 }
905 }
906 else
907 {
909 typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc);
910 if(Conjugate)
911 U = A.adjoint().template triangularView<Lower>().solve(U);
912 else
913 U = A.transpose().template triangularView<Lower>().solve(U);
914 }
915 }// End For U-solve
916 }
917
918
919 const MatrixLType& m_mapL;
920 const MatrixUType& m_mapU;
921};
922
923} // End namespace Eigen
924
925#endif
Definition ForwardDeclarations.h:87
EIGEN_DEVICE_FUNC void resize(Index newSize)
Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods...
Definition DenseBase.h:246
EIGEN_DEVICE_FUNC Derived & setConstant(const Scalar &value)
Sets all coefficients in this expression to value val.
Definition CwiseNullaryOp.h:345
EIGEN_DEVICE_FUNC CoeffReturnType value() const
Definition DenseBase.h:526
EIGEN_DEVICE_FUNC Derived & setZero()
Sets all coefficients in this expression to zero.
Definition CwiseNullaryOp.h:546
EIGEN_DEVICE_FUNC TransposeReturnType transpose()
Definition Transpose.h:182
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:50
EIGEN_DEVICE_FUNC Scalar determinant() const
\lu_module
Definition Determinant.h:108
EIGEN_DEVICE_FUNC const Inverse< Derived > inverse() const
\lu_module
Definition InverseImpl.h:348
EIGEN_DEVICE_FUNC Derived & setZero(Index size)
Resizes to the given size, and sets all coefficients in this expression to zero.
Definition CwiseNullaryOp.h:562
Definition SparseLU.h:23
Sparse supernodal LU factorization for general matrices.
Definition SparseLU.h:133
Scalar determinant()
Definition SparseLU.h:435
Scalar absDeterminant()
Definition SparseLU.h:351
const PermutationType & colsPermutation() const
Definition SparseLU.h:271
const SparseLUTransposeView< false, SparseLU< _MatrixType, _OrderingType > > transpose()
Definition SparseLU.h:201
void factorize(const MatrixType &matrix)
Definition SparseLU.h:596
SparseLUMatrixLReturnType< SCMatrix > matrixL() const
Definition SparseLU.h:244
std::string lastErrorMessage() const
Definition SparseLU.h:309
Scalar signDeterminant()
Definition SparseLU.h:407
Scalar logAbsDeterminant() const
Definition SparseLU.h:381
void setPivotThreshold(const RealScalar &thresh)
Set the threshold used for a diagonal entry to be an acceptable pivot.
Definition SparseLU.h:276
void compute(const MatrixType &matrix)
Compute the symbolic and numeric factorization of the input sparse matrix.
Definition SparseLU.h:183
void analyzePattern(const MatrixType &matrix)
Compute the column permutation to minimize the fill-in.
Definition SparseLU.h:511
const SparseLUTransposeView< true, SparseLU< _MatrixType, _OrderingType > > adjoint()
Definition SparseLU.h:222
ComputationInfo info() const
Reports whether previous computation was successful.
Definition SparseLU.h:300
const PermutationType & rowsPermutation() const
Definition SparseLU.h:263
SparseLUMatrixUReturnType< SCMatrix, MappedSparseMatrix< Scalar, ColMajor, StorageIndex > > matrixU() const
Definition SparseLU.h:254
void isSymmetric(bool sym)
Indicate that the pattern of the input matrix is symmetric.
Definition SparseLU.h:233
Index rows() const
Definition SparseMatrix.h:138
Index cols() const
Definition SparseMatrix.h:140
A base class for sparse solvers.
Definition SparseSolverBase.h:68
const Solve< SparseLU< _MatrixType, _OrderingType >, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition SparseSolverBase.h:88
a class to manipulate the L supernodal factor from the SparseLU factorization
Definition SparseLU_SupernodalMatrix.h:34
Base class for sparseLU.
Definition SparseLUImpl.h:21
Definition XprHelper.h:110
ComputationInfo
Enum for reporting the status of a computation.
Definition Constants.h:440
@ NumericalIssue
The provided data did not satisfy the prerequisites.
Definition Constants.h:444
@ Success
Computation was successful.
Definition Constants.h:442
const unsigned int RowMajorBit
for a matrix, this means that the storage order is row-major.
Definition Constants.h:66
Namespace containing all symbols from the Eigen library.
Definition LDLT.h:16
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:74
Definition SparseLU.h:804
Definition SparseLU.h:826