summaryrefslogtreecommitdiffhomepage
path: root/eigen/Eigen/src/SparseLU/SparseLU_pivotL.h
blob: a86dac93fa9b384d49fa61bd37e9b31a625dcdfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// 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>
//
// 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 xpivotL.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_PIVOTL_H
#define SPARSELU_PIVOTL_H

namespace Eigen {
namespace internal {
  
/**
 * \brief Performs the numerical pivotin on the current column of L, and the CDIV operation.
 * 
 * Pivot policy :
 * (1) Compute thresh = u * max_(i>=j) abs(A_ij);
 * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN
 *           pivot row = k;
 *       ELSE IF abs(A_jj) >= thresh THEN
 *           pivot row = j;
 *       ELSE
 *           pivot row = m;
 * 
 *   Note: If you absolutely want to use a given pivot order, then set u=0.0.
 * 
 * \param jcol The current column of L
 * \param diagpivotthresh diagonal pivoting threshold
 * \param[in,out] perm_r Row permutation (threshold pivoting)
 * \param[in] iperm_c column permutation - used to finf diagonal of Pc*A*Pc'
 * \param[out] pivrow  The pivot row
 * \param glu Global LU data
 * \return 0 if success, i > 0 if U(i,i) is exactly zero 
 * 
 */
template <typename Scalar, typename StorageIndex>
Index SparseLUImpl<Scalar,StorageIndex>::pivotL(const Index jcol, const RealScalar& diagpivotthresh, IndexVector& perm_r, IndexVector& iperm_c, Index& pivrow, GlobalLU_t& glu)
{
  
  Index fsupc = (glu.xsup)((glu.supno)(jcol)); // First column in the supernode containing the column jcol
  Index nsupc = jcol - fsupc; // Number of columns in the supernode portion, excluding jcol; nsupc >=0
  Index lptr = glu.xlsub(fsupc); // pointer to the starting location of the row subscripts for this supernode portion
  Index nsupr = glu.xlsub(fsupc+1) - lptr; // Number of rows in the supernode
  Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc); // leading dimension
  Scalar* lu_sup_ptr = &(glu.lusup.data()[glu.xlusup(fsupc)]); // Start of the current supernode
  Scalar* lu_col_ptr = &(glu.lusup.data()[glu.xlusup(jcol)]); // Start of jcol in the supernode
  StorageIndex* lsub_ptr = &(glu.lsub.data()[lptr]); // Start of row indices of the supernode
  
  // Determine the largest abs numerical value for partial pivoting 
  Index diagind = iperm_c(jcol); // diagonal index 
  RealScalar pivmax(-1.0);
  Index pivptr = nsupc; 
  Index diag = emptyIdxLU; 
  RealScalar rtemp;
  Index isub, icol, itemp, k; 
  for (isub = nsupc; isub < nsupr; ++isub) {
    using std::abs;
    rtemp = abs(lu_col_ptr[isub]);
    if (rtemp > pivmax) {
      pivmax = rtemp; 
      pivptr = isub;
    } 
    if (lsub_ptr[isub] == diagind) diag = isub;
  }
  
  // Test for singularity
  if ( pivmax <= RealScalar(0.0) ) {
    // if pivmax == -1, the column is structurally empty, otherwise it is only numerically zero
    pivrow = pivmax < RealScalar(0.0) ? diagind : lsub_ptr[pivptr];
    perm_r(pivrow) = StorageIndex(jcol);
    return (jcol+1);
  }
  
  RealScalar thresh = diagpivotthresh * pivmax; 
  
  // Choose appropriate pivotal element 
  
  {
    // Test if the diagonal element can be used as a pivot (given the threshold value)
    if (diag >= 0 ) 
    {
      // Diagonal element exists
      using std::abs;
      rtemp = abs(lu_col_ptr[diag]);
      if (rtemp != RealScalar(0.0) && rtemp >= thresh) pivptr = diag;
    }
    pivrow = lsub_ptr[pivptr];
  }
  
  // Record pivot row
  perm_r(pivrow) = StorageIndex(jcol);
  // Interchange row subscripts
  if (pivptr != nsupc )
  {
    std::swap( lsub_ptr[pivptr], lsub_ptr[nsupc] );
    // Interchange numerical values as well, for the two rows in the whole snode
    // such that L is indexed the same way as A
    for (icol = 0; icol <= nsupc; icol++)
    {
      itemp = pivptr + icol * lda; 
      std::swap(lu_sup_ptr[itemp], lu_sup_ptr[nsupc + icol * lda]);
    }
  }
  // cdiv operations
  Scalar temp = Scalar(1.0) / lu_col_ptr[nsupc];
  for (k = nsupc+1; k < nsupr; k++)
    lu_col_ptr[k] *= temp; 
  return 0;
}

} // end namespace internal
} // end namespace Eigen

#endif // SPARSELU_PIVOTL_H