mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-13 20:26:03 +08:00
Remove dense nested loops in IncompleteCholesky
This commit is contained in:
parent
e31fc50280
commit
7e0d7a76b8
@ -72,7 +72,7 @@ class IncompleteCholesky : public SparseSolverBase<IncompleteCholesky<Scalar,_Up
|
|||||||
/**
|
/**
|
||||||
* \brief Set the initial shift parameter
|
* \brief Set the initial shift parameter
|
||||||
*/
|
*/
|
||||||
void setShift( Scalar shift) { m_initialShift = shift; }
|
void setInitialShift(RealScalar shift) { m_initialShift = shift; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Computes the fill reducing permutation vector.
|
* \brief Computes the fill reducing permutation vector.
|
||||||
@ -114,9 +114,9 @@ class IncompleteCholesky : public SparseSolverBase<IncompleteCholesky<Scalar,_Up
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FactorType m_L; // The lower part stored in CSC
|
FactorType m_L; // The lower part stored in CSC
|
||||||
VectorRx m_scale; // The vector for scaling the matrix
|
VectorRx m_scale; // The vector for scaling the matrix
|
||||||
Scalar m_initialShift; // The initial shift parameter
|
RealScalar m_initialShift; // The initial shift parameter
|
||||||
bool m_analysisIsOk;
|
bool m_analysisIsOk;
|
||||||
bool m_factorizationIsOk;
|
bool m_factorizationIsOk;
|
||||||
ComputationInfo m_info;
|
ComputationInfo m_info;
|
||||||
@ -157,8 +157,11 @@ void IncompleteCholesky<Scalar,_UpLo, OrderingType>::factorize(const _MatrixType
|
|||||||
Map<VectorIx> colPtr( m_L.outerIndexPtr(), n+1); // Pointer to the beginning of each row
|
Map<VectorIx> colPtr( m_L.outerIndexPtr(), n+1); // Pointer to the beginning of each row
|
||||||
VectorIx firstElt(n-1); // for each j, points to the next entry in vals that will be used in the factorization
|
VectorIx firstElt(n-1); // for each j, points to the next entry in vals that will be used in the factorization
|
||||||
VectorList listCol(n); // listCol(j) is a linked list of columns to update column j
|
VectorList listCol(n); // listCol(j) is a linked list of columns to update column j
|
||||||
VectorSx curCol(n); // Store a nonzero values in each column
|
VectorSx col_vals(n); // Store a nonzero values in each column
|
||||||
VectorIx irow(n); // Row indices of nonzero elements in each column
|
VectorIx col_irow(n); // Row indices of nonzero elements in each column
|
||||||
|
VectorIx col_pattern(n);
|
||||||
|
col_pattern.fill(-1);
|
||||||
|
StorageIndex col_nnz;
|
||||||
|
|
||||||
|
|
||||||
// Computes the scaling factors
|
// Computes the scaling factors
|
||||||
@ -196,59 +199,77 @@ void IncompleteCholesky<Scalar,_UpLo, OrderingType>::factorize(const _MatrixType
|
|||||||
for (Index j=0; j < n; ++j)
|
for (Index j=0; j < n; ++j)
|
||||||
{
|
{
|
||||||
// Left-looking factorization of the j-th column
|
// Left-looking factorization of the j-th column
|
||||||
// First, load the j-th column into curCol
|
// First, load the j-th column into col_vals
|
||||||
Scalar diag = vals[colPtr[j]]; // It is assumed that only the lower part is stored
|
Scalar diag = vals[colPtr[j]]; // It is assumed that only the lower part is stored
|
||||||
curCol.setZero();
|
col_nnz = 0;
|
||||||
irow.setLinSpaced(n,0,internal::convert_index<StorageIndex,Index>(n-1));
|
|
||||||
for (Index i = colPtr[j] + 1; i < colPtr[j+1]; i++)
|
for (Index i = colPtr[j] + 1; i < colPtr[j+1]; i++)
|
||||||
{
|
{
|
||||||
curCol(rowIdx[i]) = vals[i];
|
StorageIndex l = rowIdx[i];
|
||||||
irow(rowIdx[i]) = rowIdx[i];
|
col_vals(col_nnz) = vals[i];
|
||||||
|
col_irow(col_nnz) = l;
|
||||||
|
col_pattern(l) = col_nnz;
|
||||||
|
col_nnz++;
|
||||||
}
|
}
|
||||||
typename std::list<StorageIndex>::iterator k;
|
|
||||||
// Browse all previous columns that will update column j
|
|
||||||
for(k = listCol[j].begin(); k != listCol[j].end(); k++)
|
|
||||||
{
|
{
|
||||||
Index jk = firstElt(*k); // First element to use in the column
|
typename std::list<StorageIndex>::iterator k;
|
||||||
eigen_internal_assert(rowIdx[jk]==j);
|
// Browse all previous columns that will update column j
|
||||||
Scalar v_j_jk = numext::conj(vals[jk]);
|
for(k = listCol[j].begin(); k != listCol[j].end(); k++)
|
||||||
|
{
|
||||||
jk += 1;
|
Index jk = firstElt(*k); // First element to use in the column
|
||||||
for (Index i = jk; i < colPtr[*k+1]; i++)
|
eigen_internal_assert(rowIdx[jk]==j);
|
||||||
curCol(rowIdx[i]) -= vals[i] * v_j_jk;
|
Scalar v_j_jk = numext::conj(vals[jk]);
|
||||||
updateList(colPtr,rowIdx,vals, *k, jk, firstElt, listCol);
|
|
||||||
|
jk += 1;
|
||||||
|
for (Index i = jk; i < colPtr[*k+1]; i++)
|
||||||
|
{
|
||||||
|
StorageIndex l = rowIdx[i];
|
||||||
|
if(col_pattern[l]<0)
|
||||||
|
{
|
||||||
|
col_vals(col_nnz) = vals[i] * v_j_jk;
|
||||||
|
col_irow[col_nnz] = l;
|
||||||
|
col_pattern(l) = col_nnz;
|
||||||
|
col_nnz++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
col_vals(col_pattern[l]) -= vals[i] * v_j_jk;
|
||||||
|
}
|
||||||
|
updateList(colPtr,rowIdx,vals, *k, jk, firstElt, listCol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale the current column
|
// Scale the current column
|
||||||
if(numext::real(diag) <= 0)
|
if(numext::real(diag) <= 0)
|
||||||
{
|
{
|
||||||
//std::cerr << "\nNegative diagonal during Incomplete factorization at position " << j << " (value = " << diag << ")\n";
|
std::cerr << "\nNegative diagonal during Incomplete factorization at position " << j << " (value = " << diag << ")\n";
|
||||||
m_info = NumericalIssue;
|
m_info = NumericalIssue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RealScalar rdiag = sqrt(numext::real(diag));
|
RealScalar rdiag = sqrt(numext::real(diag));
|
||||||
vals[colPtr[j]] = rdiag;
|
vals[colPtr[j]] = rdiag;
|
||||||
// TODO, the following should iterate on the structurally non-zeros only
|
for (Index k = 0; k<col_nnz; ++k)
|
||||||
for (Index i = j+1; i < n; i++)
|
|
||||||
{
|
{
|
||||||
//Scale
|
Index i = col_irow[k];
|
||||||
curCol(i) /= rdiag;
|
//Scale
|
||||||
//Update the remaining diagonals with curCol
|
col_vals(k) /= rdiag;
|
||||||
vals[colPtr[i]] -= numext::abs2(curCol(i));
|
//Update the remaining diagonals with col_vals
|
||||||
|
vals[colPtr[i]] -= numext::abs2(col_vals(k));
|
||||||
}
|
}
|
||||||
// Select the largest p elements
|
// Select the largest p elements
|
||||||
// p is the original number of elements in the column (without the diagonal)
|
// p is the original number of elements in the column (without the diagonal)
|
||||||
// TODO, QuickSplit should operate on the structurally non zeros only.
|
|
||||||
Index p = colPtr[j+1] - colPtr[j] - 1 ;
|
Index p = colPtr[j+1] - colPtr[j] - 1 ;
|
||||||
internal::QuickSplit(curCol, irow, p);
|
Ref<VectorSx> cvals = col_vals.head(col_nnz);
|
||||||
|
Ref<VectorIx> cirow = col_irow.head(col_nnz);
|
||||||
|
internal::QuickSplit(cvals,cirow, p);
|
||||||
// Insert the largest p elements in the matrix
|
// Insert the largest p elements in the matrix
|
||||||
Index cpt = 0;
|
Index cpt = 0;
|
||||||
for (Index i = colPtr[j]+1; i < colPtr[j+1]; i++)
|
for (Index i = colPtr[j]+1; i < colPtr[j+1]; i++)
|
||||||
{
|
{
|
||||||
vals[i] = curCol(cpt);
|
vals[i] = col_vals(cpt);
|
||||||
rowIdx[i] = irow(cpt);
|
rowIdx[i] = col_irow(cpt);
|
||||||
cpt ++;
|
// restore col_pattern:
|
||||||
|
col_pattern(col_irow(cpt)) = -1;
|
||||||
|
cpt++;
|
||||||
}
|
}
|
||||||
// Get the first smallest row index and put it after the diagonal element
|
// Get the first smallest row index and put it after the diagonal element
|
||||||
Index jk = colPtr(j)+1;
|
Index jk = colPtr(j)+1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user