|  | // This file is part of Eigen, a lightweight C++ template library | 
|  | // for linear algebra. | 
|  | // | 
|  | // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr> | 
|  | // Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr> | 
|  | // | 
|  | // This Source Code Form is subject to the terms of the Mozilla | 
|  | // Public License v. 2.0. If a copy of the MPL was not distributed | 
|  | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
|  |  | 
|  | /* | 
|  |  | 
|  | * NOTE: This file is the modified version of xcolumn_bmod.c file in SuperLU | 
|  |  | 
|  | * -- SuperLU routine (version 3.0) -- | 
|  | * Univ. of California Berkeley, Xerox Palo Alto Research Center, | 
|  | * and Lawrence Berkeley National Lab. | 
|  | * October 15, 2003 | 
|  | * | 
|  | * Copyright (c) 1994 by Xerox Corporation.  All rights reserved. | 
|  | * | 
|  | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY | 
|  | * EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK. | 
|  | * | 
|  | * Permission is hereby granted to use or copy this program for any | 
|  | * purpose, provided the above notices are retained on all copies. | 
|  | * Permission to modify the code and to distribute modified code is | 
|  | * granted, provided the above notices are retained, and a notice that | 
|  | * the code was modified is included with the above copyright notice. | 
|  | */ | 
|  | #ifndef SPARSELU_COLUMN_BMOD_H | 
|  | #define SPARSELU_COLUMN_BMOD_H | 
|  |  | 
|  | #include "./InternalHeaderCheck.h" | 
|  |  | 
|  | namespace Eigen { | 
|  |  | 
|  | namespace internal { | 
|  | /** | 
|  | * \brief Performs numeric block updates (sup-col) in topological order | 
|  | * | 
|  | * \param jcol current column to update | 
|  | * \param nseg Number of segments in the U part | 
|  | * \param dense Store the full representation of the column | 
|  | * \param tempv working array | 
|  | * \param segrep segment representative ... | 
|  | * \param repfnz ??? First nonzero column in each row ???  ... | 
|  | * \param fpanelc First column in the current panel | 
|  | * \param glu Global LU data. | 
|  | * \return 0 - successful return | 
|  | *         > 0 - number of bytes allocated when run out of space | 
|  | * | 
|  | */ | 
|  | template <typename Scalar, typename StorageIndex> | 
|  | Index SparseLUImpl<Scalar,StorageIndex>::column_bmod(const Index jcol, const Index nseg, BlockScalarVector dense, ScalarVector& tempv, | 
|  | BlockIndexVector segrep, BlockIndexVector repfnz, Index fpanelc, GlobalLU_t& glu) | 
|  | { | 
|  | Index  jsupno, k, ksub, krep, ksupno; | 
|  | Index lptr, nrow, isub, irow, nextlu, new_next, ufirst; | 
|  | Index fsupc, nsupc, nsupr, luptr, kfnz, no_zeros; | 
|  | /* krep = representative of current k-th supernode | 
|  | * fsupc =  first supernodal column | 
|  | * nsupc = number of columns in a supernode | 
|  | * nsupr = number of rows in a supernode | 
|  | * luptr = location of supernodal LU-block in storage | 
|  | * kfnz = first nonz in the k-th supernodal segment | 
|  | * no_zeros = no lf leading zeros in a supernodal U-segment | 
|  | */ | 
|  |  | 
|  | jsupno = glu.supno(jcol); | 
|  | // For each nonzero supernode segment of U[*,j] in topological order | 
|  | k = nseg - 1; | 
|  | Index d_fsupc; // distance between the first column of the current panel and the | 
|  | // first column of the current snode | 
|  | Index fst_col; // First column within small LU update | 
|  | Index segsize; | 
|  | for (ksub = 0; ksub < nseg; ksub++) | 
|  | { | 
|  | krep = segrep(k); k--; | 
|  | ksupno = glu.supno(krep); | 
|  | if (jsupno != ksupno ) | 
|  | { | 
|  | // outside the rectangular supernode | 
|  | fsupc = glu.xsup(ksupno); | 
|  | fst_col = (std::max)(fsupc, fpanelc); | 
|  |  | 
|  | // Distance from the current supernode to the current panel; | 
|  | // d_fsupc = 0 if fsupc > fpanelc | 
|  | d_fsupc = fst_col - fsupc; | 
|  |  | 
|  | luptr = glu.xlusup(fst_col) + d_fsupc; | 
|  | lptr = glu.xlsub(fsupc) + d_fsupc; | 
|  |  | 
|  | kfnz = repfnz(krep); | 
|  | kfnz = (std::max)(kfnz, fpanelc); | 
|  |  | 
|  | segsize = krep - kfnz + 1; | 
|  | nsupc = krep - fst_col + 1; | 
|  | nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); | 
|  | nrow = nsupr - d_fsupc - nsupc; | 
|  | Index lda = glu.xlusup(fst_col+1) - glu.xlusup(fst_col); | 
|  |  | 
|  |  | 
|  | // Perform a triangular solver and block update, | 
|  | // then scatter the result of sup-col update to dense | 
|  | no_zeros = kfnz - fst_col; | 
|  | if(segsize==1) | 
|  | LU_kernel_bmod<1>::run(segsize, dense, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); | 
|  | else | 
|  | LU_kernel_bmod<Dynamic>::run(segsize, dense, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); | 
|  | } // end if jsupno | 
|  | } // end for each segment | 
|  |  | 
|  | // Process the supernodal portion of  L\U[*,j] | 
|  | nextlu = glu.xlusup(jcol); | 
|  | fsupc = glu.xsup(jsupno); | 
|  |  | 
|  | // copy the SPA dense into L\U[*,j] | 
|  | Index mem; | 
|  | new_next = nextlu + glu.xlsub(fsupc + 1) - glu.xlsub(fsupc); | 
|  | Index offset = internal::first_multiple<Index>(new_next, internal::packet_traits<Scalar>::size) - new_next; | 
|  | if(offset) | 
|  | new_next += offset; | 
|  | while (new_next > glu.nzlumax ) | 
|  | { | 
|  | mem = memXpand<ScalarVector>(glu.lusup, glu.nzlumax, nextlu, LUSUP, glu.num_expansions); | 
|  | if (mem) return mem; | 
|  | } | 
|  |  | 
|  | for (isub = glu.xlsub(fsupc); isub < glu.xlsub(fsupc+1); isub++) | 
|  | { | 
|  | irow = glu.lsub(isub); | 
|  | glu.lusup(nextlu) = dense(irow); | 
|  | dense(irow) = Scalar(0.0); | 
|  | ++nextlu; | 
|  | } | 
|  |  | 
|  | if(offset) | 
|  | { | 
|  | glu.lusup.segment(nextlu,offset).setZero(); | 
|  | nextlu += offset; | 
|  | } | 
|  | glu.xlusup(jcol + 1) = StorageIndex(nextlu);  // close L\U(*,jcol); | 
|  |  | 
|  | /* For more updates within the panel (also within the current supernode), | 
|  | * should start from the first column of the panel, or the first column | 
|  | * of the supernode, whichever is bigger. There are two cases: | 
|  | *  1) fsupc < fpanelc, then fst_col <-- fpanelc | 
|  | *  2) fsupc >= fpanelc, then fst_col <-- fsupc | 
|  | */ | 
|  | fst_col = (std::max)(fsupc, fpanelc); | 
|  |  | 
|  | if (fst_col  < jcol) | 
|  | { | 
|  | // Distance between the current supernode and the current panel | 
|  | // d_fsupc = 0 if fsupc >= fpanelc | 
|  | d_fsupc = fst_col - fsupc; | 
|  |  | 
|  | lptr = glu.xlsub(fsupc) + d_fsupc; | 
|  | luptr = glu.xlusup(fst_col) + d_fsupc; | 
|  | nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); // leading dimension | 
|  | nsupc = jcol - fst_col; // excluding jcol | 
|  | nrow = nsupr - d_fsupc - nsupc; | 
|  |  | 
|  | // points to the beginning of jcol in snode L\U(jsupno) | 
|  | ufirst = glu.xlusup(jcol) + d_fsupc; | 
|  | Index lda = glu.xlusup(jcol+1) - glu.xlusup(jcol); | 
|  | MappedMatrixBlock A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); | 
|  | VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc); | 
|  | u = A.template triangularView<UnitLower>().solve(u); | 
|  |  | 
|  | new (&A) MappedMatrixBlock ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); | 
|  | VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow); | 
|  | l.noalias() -= A * u; | 
|  |  | 
|  | } // End if fst_col | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | } // end namespace internal | 
|  | } // end namespace Eigen | 
|  |  | 
|  | #endif // SPARSELU_COLUMN_BMOD_H |