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