Home | History | Annotate | Download | only in PardisoSupport
      1 /*
      2  Copyright (c) 2011, Intel Corporation. All rights reserved.
      3 
      4  Redistribution and use in source and binary forms, with or without modification,
      5  are permitted provided that the following conditions are met:
      6 
      7  * Redistributions of source code must retain the above copyright notice, this
      8    list of conditions and the following disclaimer.
      9  * Redistributions in binary form must reproduce the above copyright notice,
     10    this list of conditions and the following disclaimer in the documentation
     11    and/or other materials provided with the distribution.
     12  * Neither the name of Intel Corporation nor the names of its contributors may
     13    be used to endorse or promote products derived from this software without
     14    specific prior written permission.
     15 
     16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     23  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27  ********************************************************************************
     28  *   Content : Eigen bindings to Intel(R) MKL PARDISO
     29  ********************************************************************************
     30 */
     31 
     32 #ifndef EIGEN_PARDISOSUPPORT_H
     33 #define EIGEN_PARDISOSUPPORT_H
     34 
     35 namespace Eigen {
     36 
     37 template<typename _MatrixType> class PardisoLU;
     38 template<typename _MatrixType, int Options=Upper> class PardisoLLT;
     39 template<typename _MatrixType, int Options=Upper> class PardisoLDLT;
     40 
     41 namespace internal
     42 {
     43   template<typename IndexType>
     44   struct pardiso_run_selector
     45   {
     46     static IndexType run( _MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, IndexType n, void *a,
     47                       IndexType *ia, IndexType *ja, IndexType *perm, IndexType nrhs, IndexType *iparm, IndexType msglvl, void *b, void *x)
     48     {
     49       IndexType error = 0;
     50       ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
     51       return error;
     52     }
     53   };
     54   template<>
     55   struct pardiso_run_selector<long long int>
     56   {
     57     typedef long long int IndexType;
     58     static IndexType run( _MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, IndexType n, void *a,
     59                       IndexType *ia, IndexType *ja, IndexType *perm, IndexType nrhs, IndexType *iparm, IndexType msglvl, void *b, void *x)
     60     {
     61       IndexType error = 0;
     62       ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
     63       return error;
     64     }
     65   };
     66 
     67   template<class Pardiso> struct pardiso_traits;
     68 
     69   template<typename _MatrixType>
     70   struct pardiso_traits< PardisoLU<_MatrixType> >
     71   {
     72     typedef _MatrixType MatrixType;
     73     typedef typename _MatrixType::Scalar Scalar;
     74     typedef typename _MatrixType::RealScalar RealScalar;
     75     typedef typename _MatrixType::StorageIndex StorageIndex;
     76   };
     77 
     78   template<typename _MatrixType, int Options>
     79   struct pardiso_traits< PardisoLLT<_MatrixType, Options> >
     80   {
     81     typedef _MatrixType MatrixType;
     82     typedef typename _MatrixType::Scalar Scalar;
     83     typedef typename _MatrixType::RealScalar RealScalar;
     84     typedef typename _MatrixType::StorageIndex StorageIndex;
     85   };
     86 
     87   template<typename _MatrixType, int Options>
     88   struct pardiso_traits< PardisoLDLT<_MatrixType, Options> >
     89   {
     90     typedef _MatrixType MatrixType;
     91     typedef typename _MatrixType::Scalar Scalar;
     92     typedef typename _MatrixType::RealScalar RealScalar;
     93     typedef typename _MatrixType::StorageIndex StorageIndex;
     94   };
     95 
     96 } // end namespace internal
     97 
     98 template<class Derived>
     99 class PardisoImpl : public SparseSolverBase<Derived>
    100 {
    101   protected:
    102     typedef SparseSolverBase<Derived> Base;
    103     using Base::derived;
    104     using Base::m_isInitialized;
    105 
    106     typedef internal::pardiso_traits<Derived> Traits;
    107   public:
    108     using Base::_solve_impl;
    109 
    110     typedef typename Traits::MatrixType MatrixType;
    111     typedef typename Traits::Scalar Scalar;
    112     typedef typename Traits::RealScalar RealScalar;
    113     typedef typename Traits::StorageIndex StorageIndex;
    114     typedef SparseMatrix<Scalar,RowMajor,StorageIndex> SparseMatrixType;
    115     typedef Matrix<Scalar,Dynamic,1> VectorType;
    116     typedef Matrix<StorageIndex, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
    117     typedef Matrix<StorageIndex, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
    118     typedef Array<StorageIndex,64,1,DontAlign> ParameterType;
    119     enum {
    120       ScalarIsComplex = NumTraits<Scalar>::IsComplex,
    121       ColsAtCompileTime = Dynamic,
    122       MaxColsAtCompileTime = Dynamic
    123     };
    124 
    125     PardisoImpl()
    126     {
    127       eigen_assert((sizeof(StorageIndex) >= sizeof(_INTEGER_t) && sizeof(StorageIndex) <= 8) && "Non-supported index type");
    128       m_iparm.setZero();
    129       m_msglvl = 0; // No output
    130       m_isInitialized = false;
    131     }
    132 
    133     ~PardisoImpl()
    134     {
    135       pardisoRelease();
    136     }
    137 
    138     inline Index cols() const { return m_size; }
    139     inline Index rows() const { return m_size; }
    140 
    141     /** \brief Reports whether previous computation was successful.
    142       *
    143       * \returns \c Success if computation was succesful,
    144       *          \c NumericalIssue if the matrix appears to be negative.
    145       */
    146     ComputationInfo info() const
    147     {
    148       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
    149       return m_info;
    150     }
    151 
    152     /** \warning for advanced usage only.
    153       * \returns a reference to the parameter array controlling PARDISO.
    154       * See the PARDISO manual to know how to use it. */
    155     ParameterType& pardisoParameterArray()
    156     {
    157       return m_iparm;
    158     }
    159 
    160     /** Performs a symbolic decomposition on the sparcity of \a matrix.
    161       *
    162       * This function is particularly useful when solving for several problems having the same structure.
    163       *
    164       * \sa factorize()
    165       */
    166     Derived& analyzePattern(const MatrixType& matrix);
    167 
    168     /** Performs a numeric decomposition of \a matrix
    169       *
    170       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
    171       *
    172       * \sa analyzePattern()
    173       */
    174     Derived& factorize(const MatrixType& matrix);
    175 
    176     Derived& compute(const MatrixType& matrix);
    177 
    178     template<typename Rhs,typename Dest>
    179     void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const;
    180 
    181   protected:
    182     void pardisoRelease()
    183     {
    184       if(m_isInitialized) // Factorization ran at least once
    185       {
    186         internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, -1, internal::convert_index<StorageIndex>(m_size),0, 0, 0, m_perm.data(), 0,
    187                                                           m_iparm.data(), m_msglvl, NULL, NULL);
    188         m_isInitialized = false;
    189       }
    190     }
    191 
    192     void pardisoInit(int type)
    193     {
    194       m_type = type;
    195       bool symmetric = std::abs(m_type) < 10;
    196       m_iparm[0] = 1;   // No solver default
    197       m_iparm[1] = 2;   // use Metis for the ordering
    198       m_iparm[2] = 0;   // Reserved. Set to zero. (??Numbers of processors, value of OMP_NUM_THREADS??)
    199       m_iparm[3] = 0;   // No iterative-direct algorithm
    200       m_iparm[4] = 0;   // No user fill-in reducing permutation
    201       m_iparm[5] = 0;   // Write solution into x, b is left unchanged
    202       m_iparm[6] = 0;   // Not in use
    203       m_iparm[7] = 2;   // Max numbers of iterative refinement steps
    204       m_iparm[8] = 0;   // Not in use
    205       m_iparm[9] = 13;  // Perturb the pivot elements with 1E-13
    206       m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS
    207       m_iparm[11] = 0;  // Not in use
    208       m_iparm[12] = symmetric ? 0 : 1;  // Maximum weighted matching algorithm is switched-off (default for symmetric).
    209                                         // Try m_iparm[12] = 1 in case of inappropriate accuracy
    210       m_iparm[13] = 0;  // Output: Number of perturbed pivots
    211       m_iparm[14] = 0;  // Not in use
    212       m_iparm[15] = 0;  // Not in use
    213       m_iparm[16] = 0;  // Not in use
    214       m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU
    215       m_iparm[18] = -1; // Output: Mflops for LU factorization
    216       m_iparm[19] = 0;  // Output: Numbers of CG Iterations
    217 
    218       m_iparm[20] = 0;  // 1x1 pivoting
    219       m_iparm[26] = 0;  // No matrix checker
    220       m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0;
    221       m_iparm[34] = 1;  // C indexing
    222       m_iparm[36] = 0;  // CSR
    223       m_iparm[59] = 0;  // 0 - In-Core ; 1 - Automatic switch between In-Core and Out-of-Core modes ; 2 - Out-of-Core
    224 
    225       memset(m_pt, 0, sizeof(m_pt));
    226     }
    227 
    228   protected:
    229     // cached data to reduce reallocation, etc.
    230 
    231     void manageErrorCode(Index error) const
    232     {
    233       switch(error)
    234       {
    235         case 0:
    236           m_info = Success;
    237           break;
    238         case -4:
    239         case -7:
    240           m_info = NumericalIssue;
    241           break;
    242         default:
    243           m_info = InvalidInput;
    244       }
    245     }
    246 
    247     mutable SparseMatrixType m_matrix;
    248     mutable ComputationInfo m_info;
    249     bool m_analysisIsOk, m_factorizationIsOk;
    250     StorageIndex m_type, m_msglvl;
    251     mutable void *m_pt[64];
    252     mutable ParameterType m_iparm;
    253     mutable IntColVectorType m_perm;
    254     Index m_size;
    255 
    256 };
    257 
    258 template<class Derived>
    259 Derived& PardisoImpl<Derived>::compute(const MatrixType& a)
    260 {
    261   m_size = a.rows();
    262   eigen_assert(a.rows() == a.cols());
    263 
    264   pardisoRelease();
    265   m_perm.setZero(m_size);
    266   derived().getMatrix(a);
    267 
    268   Index error;
    269   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 12, internal::convert_index<StorageIndex>(m_size),
    270                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    271                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    272   manageErrorCode(error);
    273   m_analysisIsOk = true;
    274   m_factorizationIsOk = true;
    275   m_isInitialized = true;
    276   return derived();
    277 }
    278 
    279 template<class Derived>
    280 Derived& PardisoImpl<Derived>::analyzePattern(const MatrixType& a)
    281 {
    282   m_size = a.rows();
    283   eigen_assert(m_size == a.cols());
    284 
    285   pardisoRelease();
    286   m_perm.setZero(m_size);
    287   derived().getMatrix(a);
    288 
    289   Index error;
    290   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 11, internal::convert_index<StorageIndex>(m_size),
    291                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    292                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    293 
    294   manageErrorCode(error);
    295   m_analysisIsOk = true;
    296   m_factorizationIsOk = false;
    297   m_isInitialized = true;
    298   return derived();
    299 }
    300 
    301 template<class Derived>
    302 Derived& PardisoImpl<Derived>::factorize(const MatrixType& a)
    303 {
    304   eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
    305   eigen_assert(m_size == a.rows() && m_size == a.cols());
    306 
    307   derived().getMatrix(a);
    308 
    309   Index error;
    310   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 22, internal::convert_index<StorageIndex>(m_size),
    311                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    312                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    313 
    314   manageErrorCode(error);
    315   m_factorizationIsOk = true;
    316   return derived();
    317 }
    318 
    319 template<class Derived>
    320 template<typename BDerived,typename XDerived>
    321 void PardisoImpl<Derived>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const
    322 {
    323   if(m_iparm[0] == 0) // Factorization was not computed
    324   {
    325     m_info = InvalidInput;
    326     return;
    327   }
    328 
    329   //Index n = m_matrix.rows();
    330   Index nrhs = Index(b.cols());
    331   eigen_assert(m_size==b.rows());
    332   eigen_assert(((MatrixBase<BDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major right hand sides are not supported");
    333   eigen_assert(((MatrixBase<XDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major matrices of unknowns are not supported");
    334   eigen_assert(((nrhs == 1) || b.outerStride() == b.rows()));
    335 
    336 
    337 //  switch (transposed) {
    338 //    case SvNoTrans    : m_iparm[11] = 0 ; break;
    339 //    case SvTranspose  : m_iparm[11] = 2 ; break;
    340 //    case SvAdjoint    : m_iparm[11] = 1 ; break;
    341 //    default:
    342 //      //std::cerr << "Eigen: transposition  option \"" << transposed << "\" not supported by the PARDISO backend\n";
    343 //      m_iparm[11] = 0;
    344 //  }
    345 
    346   Scalar* rhs_ptr = const_cast<Scalar*>(b.derived().data());
    347   Matrix<Scalar,Dynamic,Dynamic,ColMajor> tmp;
    348 
    349   // Pardiso cannot solve in-place
    350   if(rhs_ptr == x.derived().data())
    351   {
    352     tmp = b;
    353     rhs_ptr = tmp.data();
    354   }
    355 
    356   Index error;
    357   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 33, internal::convert_index<StorageIndex>(m_size),
    358                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    359                                                             m_perm.data(), internal::convert_index<StorageIndex>(nrhs), m_iparm.data(), m_msglvl,
    360                                                             rhs_ptr, x.derived().data());
    361 
    362   manageErrorCode(error);
    363 }
    364 
    365 
    366 /** \ingroup PardisoSupport_Module
    367   * \class PardisoLU
    368   * \brief A sparse direct LU factorization and solver based on the PARDISO library
    369   *
    370   * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization
    371   * using the Intel MKL PARDISO library. The sparse matrix A must be squared and invertible.
    372   * The vectors or matrices X and B can be either dense or sparse.
    373   *
    374   * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set:
    375   * \code solver.pardisoParameterArray()[59] = 1; \endcode
    376   *
    377   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    378   *
    379   * \implsparsesolverconcept
    380   *
    381   * \sa \ref TutorialSparseSolverConcept, class SparseLU
    382   */
    383 template<typename MatrixType>
    384 class PardisoLU : public PardisoImpl< PardisoLU<MatrixType> >
    385 {
    386   protected:
    387     typedef PardisoImpl<PardisoLU> Base;
    388     typedef typename Base::Scalar Scalar;
    389     typedef typename Base::RealScalar RealScalar;
    390     using Base::pardisoInit;
    391     using Base::m_matrix;
    392     friend class PardisoImpl< PardisoLU<MatrixType> >;
    393 
    394   public:
    395 
    396     using Base::compute;
    397     using Base::solve;
    398 
    399     PardisoLU()
    400       : Base()
    401     {
    402       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
    403     }
    404 
    405     explicit PardisoLU(const MatrixType& matrix)
    406       : Base()
    407     {
    408       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
    409       compute(matrix);
    410     }
    411   protected:
    412     void getMatrix(const MatrixType& matrix)
    413     {
    414       m_matrix = matrix;
    415       m_matrix.makeCompressed();
    416     }
    417 };
    418 
    419 /** \ingroup PardisoSupport_Module
    420   * \class PardisoLLT
    421   * \brief A sparse direct Cholesky (LLT) factorization and solver based on the PARDISO library
    422   *
    423   * This class allows to solve for A.X = B sparse linear problems via a LL^T Cholesky factorization
    424   * using the Intel MKL PARDISO library. The sparse matrix A must be selfajoint and positive definite.
    425   * The vectors or matrices X and B can be either dense or sparse.
    426   *
    427   * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set:
    428   * \code solver.pardisoParameterArray()[59] = 1; \endcode
    429   *
    430   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    431   * \tparam UpLo can be any bitwise combination of Upper, Lower. The default is Upper, meaning only the upper triangular part has to be used.
    432   *         Upper|Lower can be used to tell both triangular parts can be used as input.
    433   *
    434   * \implsparsesolverconcept
    435   *
    436   * \sa \ref TutorialSparseSolverConcept, class SimplicialLLT
    437   */
    438 template<typename MatrixType, int _UpLo>
    439 class PardisoLLT : public PardisoImpl< PardisoLLT<MatrixType,_UpLo> >
    440 {
    441   protected:
    442     typedef PardisoImpl< PardisoLLT<MatrixType,_UpLo> > Base;
    443     typedef typename Base::Scalar Scalar;
    444     typedef typename Base::RealScalar RealScalar;
    445     using Base::pardisoInit;
    446     using Base::m_matrix;
    447     friend class PardisoImpl< PardisoLLT<MatrixType,_UpLo> >;
    448 
    449   public:
    450 
    451     typedef typename Base::StorageIndex StorageIndex;
    452     enum { UpLo = _UpLo };
    453     using Base::compute;
    454 
    455     PardisoLLT()
    456       : Base()
    457     {
    458       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
    459     }
    460 
    461     explicit PardisoLLT(const MatrixType& matrix)
    462       : Base()
    463     {
    464       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
    465       compute(matrix);
    466     }
    467 
    468   protected:
    469 
    470     void getMatrix(const MatrixType& matrix)
    471     {
    472       // PARDISO supports only upper, row-major matrices
    473       PermutationMatrix<Dynamic,Dynamic,StorageIndex> p_null;
    474       m_matrix.resize(matrix.rows(), matrix.cols());
    475       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
    476       m_matrix.makeCompressed();
    477     }
    478 };
    479 
    480 /** \ingroup PardisoSupport_Module
    481   * \class PardisoLDLT
    482   * \brief A sparse direct Cholesky (LDLT) factorization and solver based on the PARDISO library
    483   *
    484   * This class allows to solve for A.X = B sparse linear problems via a LDL^T Cholesky factorization
    485   * using the Intel MKL PARDISO library. The sparse matrix A is assumed to be selfajoint and positive definite.
    486   * For complex matrices, A can also be symmetric only, see the \a Options template parameter.
    487   * The vectors or matrices X and B can be either dense or sparse.
    488   *
    489   * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set:
    490   * \code solver.pardisoParameterArray()[59] = 1; \endcode
    491   *
    492   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    493   * \tparam Options can be any bitwise combination of Upper, Lower, and Symmetric. The default is Upper, meaning only the upper triangular part has to be used.
    494   *         Symmetric can be used for symmetric, non-selfadjoint complex matrices, the default being to assume a selfadjoint matrix.
    495   *         Upper|Lower can be used to tell both triangular parts can be used as input.
    496   *
    497   * \implsparsesolverconcept
    498   *
    499   * \sa \ref TutorialSparseSolverConcept, class SimplicialLDLT
    500   */
    501 template<typename MatrixType, int Options>
    502 class PardisoLDLT : public PardisoImpl< PardisoLDLT<MatrixType,Options> >
    503 {
    504   protected:
    505     typedef PardisoImpl< PardisoLDLT<MatrixType,Options> > Base;
    506     typedef typename Base::Scalar Scalar;
    507     typedef typename Base::RealScalar RealScalar;
    508     using Base::pardisoInit;
    509     using Base::m_matrix;
    510     friend class PardisoImpl< PardisoLDLT<MatrixType,Options> >;
    511 
    512   public:
    513 
    514     typedef typename Base::StorageIndex StorageIndex;
    515     using Base::compute;
    516     enum { UpLo = Options&(Upper|Lower) };
    517 
    518     PardisoLDLT()
    519       : Base()
    520     {
    521       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
    522     }
    523 
    524     explicit PardisoLDLT(const MatrixType& matrix)
    525       : Base()
    526     {
    527       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
    528       compute(matrix);
    529     }
    530 
    531     void getMatrix(const MatrixType& matrix)
    532     {
    533       // PARDISO supports only upper, row-major matrices
    534       PermutationMatrix<Dynamic,Dynamic,StorageIndex> p_null;
    535       m_matrix.resize(matrix.rows(), matrix.cols());
    536       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
    537       m_matrix.makeCompressed();
    538     }
    539 };
    540 
    541 } // end namespace Eigen
    542 
    543 #endif // EIGEN_PARDISOSUPPORT_H
    544