Eigen::NNLS< MatrixType_ > Class Template Reference

Implementation of the Non-Negative Least Squares (NNLS) algorithm. More...

Public Types

enum  {
  RowsAtCompileTime ,
  ColsAtCompileTime ,
  Options ,
  MaxRowsAtCompileTime ,
  MaxColsAtCompileTime
}
 
typedef MatrixType::Index Index
 
typedef Matrix< Index, ColsAtCompileTime, 1 > IndicesType
 
typedef MatrixType_ MatrixType
 
typedef MatrixType::RealScalar RealScalar
 
typedef Matrix< Scalar, RowsAtCompileTime, 1 > RhsVectorType
 
typedef MatrixType::Scalar Scalar
 
typedef Matrix< Scalar, ColsAtCompileTime, 1 > SolutionVectorType
 

Public Member Functions

template<typename MatrixDerived >
NNLS< MatrixType > & compute (const EigenBase< MatrixDerived > &A)
 
ComputationInfo info () const
 
Index iterations () const
 
Index maxIterations () const
 
 NNLS ()
 
 NNLS (const MatrixType &A, Index max_iter=-1, Scalar tol=NumTraits< Scalar >::dummy_precision())
 Constructs a NNLS sovler and initializes it with the given system matrix A. More...
 
NNLS< MatrixType > & setMaxIterations (Index maxIters)
 
NNLS< MatrixType > & setTolerance (const Scalar &tolerance)
 
const SolutionVectorTypesolve (const RhsVectorType &b)
 Solves the NNLS problem. More...
 
Scalar tolerance () const
 
const SolutionVectorTypex () const
 Returns the solution if a problem was solved. If not, an uninitialized vector may be returned. More...
 

Private Types

typedef Matrix< Scalar, ColsAtCompileTime, ColsAtCompileTimeMatrixAtAType
 

Private Member Functions

void moveToActiveSet_ (Index idx)
 
void moveToInactiveSet_ (Index idx)
 
void solveInactiveSet_ (const RhsVectorType &b)
 

Private Attributes

MatrixType A_
 
MatrixAtAType AtA_
 
SolutionVectorType Atb_
 
SolutionVectorType gradient_
 
IndicesType index_sets_
 
ComputationInfo info_
 
Index iterations_
 
Index max_iter_
 
Index numInactive_
 
MatrixType QR_
 
SolutionVectorType qrCoeffs_
 
RhsVectorType tempRhsVector_
 
SolutionVectorType tempSolutionVector_
 
Scalar tolerance_
 
SolutionVectorType x_
 
SolutionVectorType y_
 

Detailed Description

template<class MatrixType_>
class Eigen::NNLS< MatrixType_ >

Implementation of the Non-Negative Least Squares (NNLS) algorithm.

Template Parameters
MatrixTypeThe type of the system matrix \(A\).

This class implements the NNLS algorithm as described in "SOLVING LEAST SQUARES PROBLEMS", Charles L. Lawson and Richard J. Hanson, Prentice-Hall, 1974. This algorithm solves a least squares problem iteratively and ensures that the solution is non-negative. I.e.

\[ \min \left\Vert Ax-b\right\Vert_2^2\quad s.t.\, x\ge 0 \]

The algorithm solves the constrained least-squares problem above by iteratively improving an estimate of which constraints are active (elements of \(x\) equal to zero) and which constraints are inactive (elements of \(x\) greater than zero). Each iteration, an unconstrained linear least-squares problem solves for the components of \(x\) in the (estimated) inactive set and the sets are updated. The unconstrained problem minimizes \(\left\Vert A^Nx^N-b\right\Vert_2^2\), where \(A^N\) is a matrix formed by selecting all columns of A which are in the inactive set \(N\).

See the wikipedia page on non-negative least squares for more background information.

Note
Please note that it is possible to construct an NNLS problem for which the algorithm does not converge. In practice these cases are extremely rare.

Definition at line 66 of file NNLS.

Member Typedef Documentation

◆ Index

template<class MatrixType_ >
typedef MatrixType::Index Eigen::NNLS< MatrixType_ >::Index

Definition at line 80 of file NNLS.

◆ IndicesType

template<class MatrixType_ >
typedef Matrix<Index, ColsAtCompileTime, 1> Eigen::NNLS< MatrixType_ >::IndicesType

Definition at line 86 of file NNLS.

◆ MatrixAtAType

template<class MatrixType_ >
typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> Eigen::NNLS< MatrixType_ >::MatrixAtAType
private

Definition at line 167 of file NNLS.

◆ MatrixType

template<class MatrixType_ >
typedef MatrixType_ Eigen::NNLS< MatrixType_ >::MatrixType

Definition at line 68 of file NNLS.

◆ RealScalar

template<class MatrixType_ >
typedef MatrixType::RealScalar Eigen::NNLS< MatrixType_ >::RealScalar

Definition at line 79 of file NNLS.

◆ RhsVectorType

template<class MatrixType_ >
typedef Matrix<Scalar, RowsAtCompileTime, 1> Eigen::NNLS< MatrixType_ >::RhsVectorType

Type of a column vector of the system matrix \(A\).

Definition at line 85 of file NNLS.

◆ Scalar

template<class MatrixType_ >
typedef MatrixType::Scalar Eigen::NNLS< MatrixType_ >::Scalar

Definition at line 78 of file NNLS.

◆ SolutionVectorType

template<class MatrixType_ >
typedef Matrix<Scalar, ColsAtCompileTime, 1> Eigen::NNLS< MatrixType_ >::SolutionVectorType

Type of a row vector of the system matrix \(A\).

Definition at line 83 of file NNLS.

Member Enumeration Documentation

◆ anonymous enum

template<class MatrixType_ >
anonymous enum
Enumerator
RowsAtCompileTime 
ColsAtCompileTime 
Options 
MaxRowsAtCompileTime 
MaxColsAtCompileTime 

Definition at line 70 of file NNLS.

70  {
71  RowsAtCompileTime = MatrixType::RowsAtCompileTime,
72  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
73  Options = MatrixType::Options,
74  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
75  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
76  };
@ RowsAtCompileTime
Definition: NNLS:71
@ MaxRowsAtCompileTime
Definition: NNLS:74
@ MaxColsAtCompileTime
Definition: NNLS:75
@ Options
Definition: NNLS:73
@ ColsAtCompileTime
Definition: NNLS:72

Constructor & Destructor Documentation

◆ NNLS() [1/2]

template<typename MatrixType >
Eigen::NNLS< MatrixType >::NNLS

Definition at line 209 of file NNLS.

210  : max_iter_(-1),
211  iterations_(0),
213  numInactive_(0),
214  tolerance_(NumTraits<Scalar>::dummy_precision()) {}
Index iterations_
Definition: NNLS:173
Index numInactive_
Definition: NNLS:177
Index max_iter_
Definition: NNLS:171
ComputationInfo info_
Definition: NNLS:175
Scalar tolerance_
Definition: NNLS:179
InvalidInput

◆ NNLS() [2/2]

template<typename MatrixType >
Eigen::NNLS< MatrixType >::NNLS ( const MatrixType A,
Index  max_iter = -1,
Scalar  tol = NumTraits<Scalar>::dummy_precision() 
)

Constructs a NNLS sovler and initializes it with the given system matrix A.

Parameters
ASpecifies the system matrix.
max_iterSpecifies the maximum number of iterations to solve the system.
tolSpecifies the precision of the optimum. This is an absolute tolerance on the gradient of the Lagrangian, \(A^T(Ax-b)-\lambda\) (with Lagrange multipliers \(\lambda\)).

Definition at line 217 of file NNLS.

217  : max_iter_(max_iter), tolerance_(tol) {
218  compute(A);
219 }
NNLS< MatrixType > & compute(const EigenBase< MatrixDerived > &A)
Definition: NNLS:223

Member Function Documentation

◆ compute()

template<typename MatrixType >
template<typename MatrixDerived >
NNLS< MatrixType > & Eigen::NNLS< MatrixType >::compute ( const EigenBase< MatrixDerived > &  A)

Initializes the solver with the matrix A for further solving NNLS problems.

This function mostly initializes/computes the preconditioner. In the future we might, for instance, implement column reordering for faster matrix vector products.

Definition at line 223 of file NNLS.

223  {
224  // Ensure Scalar type is real. The non-negativity constraint doesn't obviously extend to complex numbers.
225  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
226 
227  // max_iter_: unchanged
228  iterations_ = 0;
230  numInactive_ = 0;
231  // tolerance: unchanged
232  A_ = A.derived();
233  AtA_.noalias() = A_.transpose() * A_;
234  x_.resize(A_.cols());
235  gradient_.resize(A_.cols());
236  y_.resize(A_.cols());
237  Atb_.resize(A_.cols());
238  index_sets_.resize(A_.cols());
239  QR_.resize(A_.rows(), A_.cols());
240  qrCoeffs_.resize(A_.cols());
241  tempSolutionVector_.resize(A_.cols());
242  tempRhsVector_.resize(A_.rows());
243 
244  return *this;
245 }
SparseMatrix< double > A(n, n)
#define EIGEN_STATIC_ASSERT(X, MSG)
RhsVectorType tempRhsVector_
Definition: NNLS:201
SolutionVectorType gradient_
Definition: NNLS:187
MatrixAtAType AtA_
Definition: NNLS:183
SolutionVectorType qrCoeffs_
Definition: NNLS:198
MatrixType A_
Definition: NNLS:181
IndicesType index_sets_
Definition: NNLS:194
SolutionVectorType tempSolutionVector_
Definition: NNLS:200
SolutionVectorType x_
Definition: NNLS:185
SolutionVectorType y_
Definition: NNLS:189
MatrixType QR_
Definition: NNLS:196
SolutionVectorType Atb_
Definition: NNLS:191
constexpr void resize(Index rows, Index cols)
Success
SparseMatrix< double, Options_, StorageIndex_ > & derived()

◆ info()

template<class MatrixType_ >
ComputationInfo Eigen::NNLS< MatrixType_ >::info ( ) const
inline
Returns
Success if the iterations converged, and an error values otherwise.

Definition at line 154 of file NNLS.

154 { return info_; }

◆ iterations()

template<class MatrixType_ >
Index Eigen::NNLS< MatrixType_ >::iterations ( ) const
inline
Returns
the number of iterations (least-squares solves) performed during the last solve

Definition at line 151 of file NNLS.

151 { return iterations_; }

◆ maxIterations()

template<class MatrixType_ >
Index Eigen::NNLS< MatrixType_ >::maxIterations ( ) const
inline
Returns
the max number of iterations. It is either the value set by setMaxIterations or, by default, twice the number of columns of the matrix.

Definition at line 139 of file NNLS.

139 { return max_iter_ < 0 ? 2 * A_.cols() : max_iter_; }

◆ moveToActiveSet_()

template<typename MatrixType >
void Eigen::NNLS< MatrixType >::moveToActiveSet_ ( Index  idx)
private

Definition at line 350 of file NNLS.

350  {
351  // swap index with last inactive one & reduce number of inactive columns
352  std::swap(index_sets_(idx), index_sets_(numInactive_ - 1));
353  numInactive_--;
354  // Update QR decomposition starting from the removed index up to the end [idx, ..., numInactive_]
355  for (Index i = idx; i < numInactive_; i++) {
356  Index col = index_sets_(i);
358  }
359 }
int i
ColXpr col(Index i) const
void householder_qr_inplace_update(MatrixQR &mat, HCoeffs &hCoeffs, const VectorQR &newColumn, typename MatrixQR::Index k, typename MatrixQR::Scalar *tempData)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index

◆ moveToInactiveSet_()

template<typename MatrixType >
void Eigen::NNLS< MatrixType >::moveToInactiveSet_ ( Index  idx)
private

Definition at line 339 of file NNLS.

339  {
340  // Update permutation matrix:
341  std::swap(index_sets_(idx), index_sets_(numInactive_));
342  numInactive_++;
343 
344  // Perform rank-1 update of the QR decomposition stored in QR_ & qrCoeff_
347 }

◆ setMaxIterations()

template<class MatrixType_ >
NNLS<MatrixType>& Eigen::NNLS< MatrixType_ >::setMaxIterations ( Index  maxIters)
inline

Sets the max number of iterations. Default is twice the number of columns of the matrix. The algorithm requires at least k iterations to produce a solution vector with k non-zero entries.

Definition at line 145 of file NNLS.

145  {
146  max_iter_ = maxIters;
147  return *this;
148  }

◆ setTolerance()

template<class MatrixType_ >
NNLS<MatrixType>& Eigen::NNLS< MatrixType_ >::setTolerance ( const Scalar tolerance)
inline

Sets the tolerance threshold used by the stopping criteria.

This is an absolute tolerance on the gradient of the Lagrangian, \(A^T(Ax-b)-\lambda\) (with Lagrange multipliers \(\lambda\)).

Definition at line 131 of file NNLS.

131  {
133  return *this;
134  }
Scalar tolerance() const
Definition: NNLS:124

◆ solve()

template<typename MatrixType >
const NNLS< MatrixType >::SolutionVectorType & Eigen::NNLS< MatrixType >::solve ( const RhsVectorType b)

Solves the NNLS problem.

The dimension of b must be equal to the number of rows of A, given to the constructor.

Returns
The approximate solution vector \( x \). Use info() to determine if the solve was a success or not.
See also
info()

Definition at line 248 of file NNLS.

248  {
249  // Initialize solver
250  iterations_ = 0;
252  x_.setZero();
253 
254  index_sets_ = IndicesType::LinSpaced(A_.cols(), 0, A_.cols() - 1); // Identity permutation.
255  numInactive_ = 0;
256 
257  // Precompute A^T*b
258  Atb_.noalias() = A_.transpose() * b;
259 
260  const Index maxIterations = this->maxIterations();
261 
262  // OUTER LOOP
263  while (true) {
264  // Early exit if all variables are inactive, which breaks 'maxCoeff' below.
265  if (A_.cols() == numInactive_) {
267  return x_;
268  }
269 
270  // Find the maximum element of the gradient in the active set.
271  // If it is small or negative, then we have converged.
272  // Else, we move that variable to the inactive set.
273  gradient_.noalias() = Atb_ - AtA_ * x_;
274 
275  const Index numActive = A_.cols() - numInactive_;
276  Index argmaxGradient = -1;
277  const Scalar maxGradient = gradient_(index_sets_.tail(numActive)).maxCoeff(&argmaxGradient);
278  argmaxGradient += numInactive_; // beacause tail() skipped the first numInactive_ elements
279 
280  if (maxGradient < tolerance_) {
282  return x_;
283  }
284 
285  moveToInactiveSet_(argmaxGradient);
286 
287  // INNER LOOP
288  while (true) {
289  // Check if max. number of iterations is reached
290  if (iterations_ >= maxIterations) {
292  return x_;
293  }
294 
295  // Solve least-squares problem in inactive set only,
296  // this step is rather trivial as moveToInactiveSet_ & moveToActiveSet_
297  // updates the QR decomposition of inactive columns A^N.
298  // solveInactiveSet_ puts the solution in y_
300  ++iterations_; // The solve is expensive, so that is what we count as an iteration.
301 
302  // Check feasability...
303  bool feasible = true;
304  Scalar alpha = NumTraits<Scalar>::highest();
305  Index infeasibleIdx = -1; // Which variable became infeasible first.
306  for (Index i = 0; i < numInactive_; i++) {
307  Index idx = index_sets_[i];
308  if (y_(idx) < 0) {
309  // t should always be in [0,1].
310  Scalar t = -x_(idx) / (y_(idx) - x_(idx));
311  if (alpha > t) {
312  alpha = t;
313  infeasibleIdx = i;
314  feasible = false;
315  }
316  }
317  }
318  eigen_assert(feasible || 0 <= infeasibleIdx);
319 
320  // If solution is feasible, exit to outer loop
321  if (feasible) {
322  x_ = y_;
323  break;
324  }
325 
326  // Infeasible solution -> interpolate to feasible one
327  for (Index i = 0; i < numInactive_; i++) {
328  Index idx = index_sets_[i];
329  x_(idx) += alpha * (y_(idx) - x_(idx));
330  }
331 
332  // Remove these indices from the inactive set and update QR decomposition
333  moveToActiveSet_(infeasibleIdx);
334  }
335  }
336 }
#define eigen_assert(x)
MatrixType::Scalar Scalar
Definition: NNLS:78
void moveToActiveSet_(Index idx)
Definition: NNLS:350
void solveInactiveSet_(const RhsVectorType &b)
Definition: NNLS:362
void moveToInactiveSet_(Index idx)
Definition: NNLS:339
Index maxIterations() const
Definition: NNLS:139
Derived & setZero(Index rows, Index cols)
NumericalIssue
NoConvergence

◆ solveInactiveSet_()

template<typename MatrixType >
void Eigen::NNLS< MatrixType >::solveInactiveSet_ ( const RhsVectorType b)
private

Definition at line 362 of file NNLS.

362  {
364 
365  tempRhsVector_ = b;
366 
367  // tmpRHS(0:numInactive_-1) := Q'*b
368  // tmpRHS(numInactive_:end) := useless stuff we would rather not compute at all.
369  tempRhsVector_.applyOnTheLeft(
370  householderSequence(QR_.leftCols(numInactive_), qrCoeffs_.head(numInactive_)).transpose());
371 
372  // tempSol(0:numInactive_-1) := inv(R) * Q' * b
373  // = the least-squares solution for the inactive variables.
375  QR_.topLeftCorner(numInactive_, numInactive_) //
376  .template triangularView<Upper>() //
377  .solve(tempRhsVector_.head(numInactive_)); //
378 
379  // tempSol(numInactive_:end) := 0 = the value for the constrained variables.
380  tempSolutionVector_.tail(y_.size() - numInactive_).setZero();
381 
382  // Back permute into original column order of A
383  y_.noalias() = index_sets_.asPermutation() * tempSolutionVector_.head(y_.size());
384 }
HouseholderSequence< VectorsType, CoeffsType > householderSequence(const VectorsType &v, const CoeffsType &h)

◆ tolerance()

template<class MatrixType_ >
Scalar Eigen::NNLS< MatrixType_ >::tolerance ( ) const
inline
Returns
the tolerance threshold used by the stopping criteria.
See also
setTolerance()

Definition at line 124 of file NNLS.

124 { return tolerance_; }

◆ x()

template<class MatrixType_ >
const SolutionVectorType& Eigen::NNLS< MatrixType_ >::x ( ) const
inline

Returns the solution if a problem was solved. If not, an uninitialized vector may be returned.

Definition at line 119 of file NNLS.

119 { return x_; }

Member Data Documentation

◆ A_

template<class MatrixType_ >
MatrixType Eigen::NNLS< MatrixType_ >::A_
private

Definition at line 181 of file NNLS.

◆ AtA_

template<class MatrixType_ >
MatrixAtAType Eigen::NNLS< MatrixType_ >::AtA_
private

Definition at line 183 of file NNLS.

◆ Atb_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::Atb_
private

Definition at line 191 of file NNLS.

◆ gradient_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::gradient_
private

Definition at line 187 of file NNLS.

◆ index_sets_

template<class MatrixType_ >
IndicesType Eigen::NNLS< MatrixType_ >::index_sets_
private

Definition at line 194 of file NNLS.

◆ info_

template<class MatrixType_ >
ComputationInfo Eigen::NNLS< MatrixType_ >::info_
private

Definition at line 175 of file NNLS.

◆ iterations_

template<class MatrixType_ >
Index Eigen::NNLS< MatrixType_ >::iterations_
private

Definition at line 173 of file NNLS.

◆ max_iter_

template<class MatrixType_ >
Index Eigen::NNLS< MatrixType_ >::max_iter_
private

Definition at line 171 of file NNLS.

◆ numInactive_

template<class MatrixType_ >
Index Eigen::NNLS< MatrixType_ >::numInactive_
private

Definition at line 177 of file NNLS.

◆ QR_

template<class MatrixType_ >
MatrixType Eigen::NNLS< MatrixType_ >::QR_
private

Definition at line 196 of file NNLS.

◆ qrCoeffs_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::qrCoeffs_
private

Definition at line 198 of file NNLS.

◆ tempRhsVector_

template<class MatrixType_ >
RhsVectorType Eigen::NNLS< MatrixType_ >::tempRhsVector_
private

Definition at line 201 of file NNLS.

◆ tempSolutionVector_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::tempSolutionVector_
private

Definition at line 200 of file NNLS.

◆ tolerance_

template<class MatrixType_ >
Scalar Eigen::NNLS< MatrixType_ >::tolerance_
private

Definition at line 179 of file NNLS.

◆ x_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::x_
private

Definition at line 185 of file NNLS.

◆ y_

template<class MatrixType_ >
SolutionVectorType Eigen::NNLS< MatrixType_ >::y_
private

Definition at line 189 of file NNLS.


The documentation for this class was generated from the following file: