xref: /aosp_15_r20/external/eigen/Eigen/src/SparseLU/SparseLU_pivotL.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Li // This file is part of Eigen, a lightweight C++ template library
2*bf2c3715SXin Li // for linear algebra.
3*bf2c3715SXin Li //
4*bf2c3715SXin Li // Copyright (C) 2012 Désiré Nuentsa-Wakam <[email protected]>
5*bf2c3715SXin Li //
6*bf2c3715SXin Li // This Source Code Form is subject to the terms of the Mozilla
7*bf2c3715SXin Li // Public License v. 2.0. If a copy of the MPL was not distributed
8*bf2c3715SXin Li // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9*bf2c3715SXin Li 
10*bf2c3715SXin Li /*
11*bf2c3715SXin Li 
12*bf2c3715SXin Li  * NOTE: This file is the modified version of xpivotL.c file in SuperLU
13*bf2c3715SXin Li 
14*bf2c3715SXin Li  * -- SuperLU routine (version 3.0) --
15*bf2c3715SXin Li  * Univ. of California Berkeley, Xerox Palo Alto Research Center,
16*bf2c3715SXin Li  * and Lawrence Berkeley National Lab.
17*bf2c3715SXin Li  * October 15, 2003
18*bf2c3715SXin Li  *
19*bf2c3715SXin Li  * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
20*bf2c3715SXin Li  *
21*bf2c3715SXin Li  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
22*bf2c3715SXin Li  * EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
23*bf2c3715SXin Li  *
24*bf2c3715SXin Li  * Permission is hereby granted to use or copy this program for any
25*bf2c3715SXin Li  * purpose, provided the above notices are retained on all copies.
26*bf2c3715SXin Li  * Permission to modify the code and to distribute modified code is
27*bf2c3715SXin Li  * granted, provided the above notices are retained, and a notice that
28*bf2c3715SXin Li  * the code was modified is included with the above copyright notice.
29*bf2c3715SXin Li  */
30*bf2c3715SXin Li #ifndef SPARSELU_PIVOTL_H
31*bf2c3715SXin Li #define SPARSELU_PIVOTL_H
32*bf2c3715SXin Li 
33*bf2c3715SXin Li namespace Eigen {
34*bf2c3715SXin Li namespace internal {
35*bf2c3715SXin Li 
36*bf2c3715SXin Li /**
37*bf2c3715SXin Li  * \brief Performs the numerical pivotin on the current column of L, and the CDIV operation.
38*bf2c3715SXin Li  *
39*bf2c3715SXin Li  * Pivot policy :
40*bf2c3715SXin Li  * (1) Compute thresh = u * max_(i>=j) abs(A_ij);
41*bf2c3715SXin Li  * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN
42*bf2c3715SXin Li  *           pivot row = k;
43*bf2c3715SXin Li  *       ELSE IF abs(A_jj) >= thresh THEN
44*bf2c3715SXin Li  *           pivot row = j;
45*bf2c3715SXin Li  *       ELSE
46*bf2c3715SXin Li  *           pivot row = m;
47*bf2c3715SXin Li  *
48*bf2c3715SXin Li  *   Note: If you absolutely want to use a given pivot order, then set u=0.0.
49*bf2c3715SXin Li  *
50*bf2c3715SXin Li  * \param jcol The current column of L
51*bf2c3715SXin Li  * \param diagpivotthresh diagonal pivoting threshold
52*bf2c3715SXin Li  * \param[in,out] perm_r Row permutation (threshold pivoting)
53*bf2c3715SXin Li  * \param[in] iperm_c column permutation - used to finf diagonal of Pc*A*Pc'
54*bf2c3715SXin Li  * \param[out] pivrow  The pivot row
55*bf2c3715SXin Li  * \param glu Global LU data
56*bf2c3715SXin Li  * \return 0 if success, i > 0 if U(i,i) is exactly zero
57*bf2c3715SXin Li  *
58*bf2c3715SXin Li  */
59*bf2c3715SXin Li template <typename Scalar, typename StorageIndex>
pivotL(const Index jcol,const RealScalar & diagpivotthresh,IndexVector & perm_r,IndexVector & iperm_c,Index & pivrow,GlobalLU_t & glu)60*bf2c3715SXin Li Index SparseLUImpl<Scalar,StorageIndex>::pivotL(const Index jcol, const RealScalar& diagpivotthresh, IndexVector& perm_r, IndexVector& iperm_c, Index& pivrow, GlobalLU_t& glu)
61*bf2c3715SXin Li {
62*bf2c3715SXin Li 
63*bf2c3715SXin Li   Index fsupc = (glu.xsup)((glu.supno)(jcol)); // First column in the supernode containing the column jcol
64*bf2c3715SXin Li   Index nsupc = jcol - fsupc; // Number of columns in the supernode portion, excluding jcol; nsupc >=0
65*bf2c3715SXin Li   Index lptr = glu.xlsub(fsupc); // pointer to the starting location of the row subscripts for this supernode portion
66*bf2c3715SXin Li   Index nsupr = glu.xlsub(fsupc+1) - lptr; // Number of rows in the supernode
67*bf2c3715SXin Li   Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc); // leading dimension
68*bf2c3715SXin Li   Scalar* lu_sup_ptr = &(glu.lusup.data()[glu.xlusup(fsupc)]); // Start of the current supernode
69*bf2c3715SXin Li   Scalar* lu_col_ptr = &(glu.lusup.data()[glu.xlusup(jcol)]); // Start of jcol in the supernode
70*bf2c3715SXin Li   StorageIndex* lsub_ptr = &(glu.lsub.data()[lptr]); // Start of row indices of the supernode
71*bf2c3715SXin Li 
72*bf2c3715SXin Li   // Determine the largest abs numerical value for partial pivoting
73*bf2c3715SXin Li   Index diagind = iperm_c(jcol); // diagonal index
74*bf2c3715SXin Li   RealScalar pivmax(-1.0);
75*bf2c3715SXin Li   Index pivptr = nsupc;
76*bf2c3715SXin Li   Index diag = emptyIdxLU;
77*bf2c3715SXin Li   RealScalar rtemp;
78*bf2c3715SXin Li   Index isub, icol, itemp, k;
79*bf2c3715SXin Li   for (isub = nsupc; isub < nsupr; ++isub) {
80*bf2c3715SXin Li     using std::abs;
81*bf2c3715SXin Li     rtemp = abs(lu_col_ptr[isub]);
82*bf2c3715SXin Li     if (rtemp > pivmax) {
83*bf2c3715SXin Li       pivmax = rtemp;
84*bf2c3715SXin Li       pivptr = isub;
85*bf2c3715SXin Li     }
86*bf2c3715SXin Li     if (lsub_ptr[isub] == diagind) diag = isub;
87*bf2c3715SXin Li   }
88*bf2c3715SXin Li 
89*bf2c3715SXin Li   // Test for singularity
90*bf2c3715SXin Li   if ( pivmax <= RealScalar(0.0) ) {
91*bf2c3715SXin Li     // if pivmax == -1, the column is structurally empty, otherwise it is only numerically zero
92*bf2c3715SXin Li     pivrow = pivmax < RealScalar(0.0) ? diagind : lsub_ptr[pivptr];
93*bf2c3715SXin Li     perm_r(pivrow) = StorageIndex(jcol);
94*bf2c3715SXin Li     return (jcol+1);
95*bf2c3715SXin Li   }
96*bf2c3715SXin Li 
97*bf2c3715SXin Li   RealScalar thresh = diagpivotthresh * pivmax;
98*bf2c3715SXin Li 
99*bf2c3715SXin Li   // Choose appropriate pivotal element
100*bf2c3715SXin Li 
101*bf2c3715SXin Li   {
102*bf2c3715SXin Li     // Test if the diagonal element can be used as a pivot (given the threshold value)
103*bf2c3715SXin Li     if (diag >= 0 )
104*bf2c3715SXin Li     {
105*bf2c3715SXin Li       // Diagonal element exists
106*bf2c3715SXin Li       using std::abs;
107*bf2c3715SXin Li       rtemp = abs(lu_col_ptr[diag]);
108*bf2c3715SXin Li       if (rtemp != RealScalar(0.0) && rtemp >= thresh) pivptr = diag;
109*bf2c3715SXin Li     }
110*bf2c3715SXin Li     pivrow = lsub_ptr[pivptr];
111*bf2c3715SXin Li   }
112*bf2c3715SXin Li 
113*bf2c3715SXin Li   // Record pivot row
114*bf2c3715SXin Li   perm_r(pivrow) = StorageIndex(jcol);
115*bf2c3715SXin Li   // Interchange row subscripts
116*bf2c3715SXin Li   if (pivptr != nsupc )
117*bf2c3715SXin Li   {
118*bf2c3715SXin Li     std::swap( lsub_ptr[pivptr], lsub_ptr[nsupc] );
119*bf2c3715SXin Li     // Interchange numerical values as well, for the two rows in the whole snode
120*bf2c3715SXin Li     // such that L is indexed the same way as A
121*bf2c3715SXin Li     for (icol = 0; icol <= nsupc; icol++)
122*bf2c3715SXin Li     {
123*bf2c3715SXin Li       itemp = pivptr + icol * lda;
124*bf2c3715SXin Li       std::swap(lu_sup_ptr[itemp], lu_sup_ptr[nsupc + icol * lda]);
125*bf2c3715SXin Li     }
126*bf2c3715SXin Li   }
127*bf2c3715SXin Li   // cdiv operations
128*bf2c3715SXin Li   Scalar temp = Scalar(1.0) / lu_col_ptr[nsupc];
129*bf2c3715SXin Li   for (k = nsupc+1; k < nsupr; k++)
130*bf2c3715SXin Li     lu_col_ptr[k] *= temp;
131*bf2c3715SXin Li   return 0;
132*bf2c3715SXin Li }
133*bf2c3715SXin Li 
134*bf2c3715SXin Li } // end namespace internal
135*bf2c3715SXin Li } // end namespace Eigen
136*bf2c3715SXin Li 
137*bf2c3715SXin Li #endif // SPARSELU_PIVOTL_H
138