diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h index a62672201..2e2d9a851 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h @@ -72,7 +72,7 @@ class IncompleteCholesky : public SparseSolverBase::factorize(const _MatrixType Map 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 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 - VectorIx irow(n); // Row indices of nonzero elements in each column + VectorSx col_vals(n); // Store a nonzero values 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 @@ -196,59 +199,77 @@ void IncompleteCholesky::factorize(const _MatrixType for (Index j=0; j < n; ++j) { // 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 - curCol.setZero(); - irow.setLinSpaced(n,0,internal::convert_index(n-1)); + col_nnz = 0; for (Index i = colPtr[j] + 1; i < colPtr[j+1]; i++) { - curCol(rowIdx[i]) = vals[i]; - irow(rowIdx[i]) = rowIdx[i]; + StorageIndex l = rowIdx[i]; + col_vals(col_nnz) = vals[i]; + col_irow(col_nnz) = l; + col_pattern(l) = col_nnz; + col_nnz++; } - typename std::list::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 - eigen_internal_assert(rowIdx[jk]==j); - Scalar v_j_jk = numext::conj(vals[jk]); - - jk += 1; - for (Index i = jk; i < colPtr[*k+1]; i++) - curCol(rowIdx[i]) -= vals[i] * v_j_jk; - updateList(colPtr,rowIdx,vals, *k, jk, firstElt, listCol); + typename std::list::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 + eigen_internal_assert(rowIdx[jk]==j); + Scalar v_j_jk = numext::conj(vals[jk]); + + 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 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; return; } RealScalar rdiag = sqrt(numext::real(diag)); vals[colPtr[j]] = rdiag; - // TODO, the following should iterate on the structurally non-zeros only - for (Index i = j+1; i < n; i++) + for (Index k = 0; k cvals = col_vals.head(col_nnz); + Ref cirow = col_irow.head(col_nnz); + internal::QuickSplit(cvals,cirow, p); // Insert the largest p elements in the matrix Index cpt = 0; for (Index i = colPtr[j]+1; i < colPtr[j+1]; i++) { - vals[i] = curCol(cpt); - rowIdx[i] = irow(cpt); - cpt ++; + vals[i] = col_vals(cpt); + rowIdx[i] = col_irow(cpt); + // restore col_pattern: + col_pattern(col_irow(cpt)) = -1; + cpt++; } // Get the first smallest row index and put it after the diagonal element Index jk = colPtr(j)+1;