30#ifndef EIGEN_NNLS_MODULE_H
31#define EIGEN_NNLS_MODULE_H
33#include "../../Eigen/Core"
34#include "../../Eigen/QR"
38#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
68template <
class MatrixType_>
71 typedef MatrixType_ MatrixType;
74 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
75 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
76 Options = MatrixType::Options,
77 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
78 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
81 typedef typename MatrixType::Scalar Scalar;
82 typedef typename MatrixType::RealScalar RealScalar;
83 typedef typename MatrixType::Index Index;
108 template <
typename MatrixDerived>
142 Index
maxIterations()
const {
return max_iter_ < 0 ? 2 * A_.cols() : max_iter_; }
149 max_iter_ = maxIters;
161 void moveToInactiveSet_(Index idx);
164 void moveToActiveSet_(Index idx);
197 IndicesType index_sets_;
211template <
typename MatrixType>
212NNLS<MatrixType>::NNLS()
217 tolerance_(NumTraits<Scalar>::dummy_precision()) {}
219template <
typename MatrixType>
220NNLS<MatrixType>::NNLS(
const MatrixType &A, Index max_iter, Scalar tol) : max_iter_(max_iter), tolerance_(tol) {
224template <
typename MatrixType>
225template <
typename MatrixDerived>
232 info_ = ComputationInfo::Success;
236 AtA_.noalias() = A_.transpose() * A_;
237 x_.resize(A_.cols());
238 gradient_.resize(A_.cols());
239 y_.resize(A_.cols());
240 Atb_.resize(A_.cols());
241 index_sets_.resize(A_.cols());
242 QR_.resize(A_.rows(), A_.cols());
243 qrCoeffs_.resize(A_.cols());
244 tempSolutionVector_.resize(A_.cols());
245 tempRhsVector_.resize(A_.rows());
250template <
typename MatrixType>
254 info_ = ComputationInfo::NumericalIssue;
257 index_sets_ = IndicesType::LinSpaced(A_.cols(), 0, A_.cols() - 1);
261 Atb_.noalias() = A_.transpose() * b;
263 if (A_.rows() == 0) {
264 info_ = ComputationInfo::Success;
273 if (A_.cols() == numInactive_) {
274 info_ = ComputationInfo::Success;
281 gradient_.noalias() = Atb_ - AtA_ * x_;
282 if (!gradient_.allFinite())
return x_;
284 const Index numActive = A_.cols() - numInactive_;
285 Index argmaxGradient = -1;
286 const Scalar maxGradient = gradient_(index_sets_.tail(numActive)).maxCoeff(&argmaxGradient);
287 argmaxGradient += numInactive_;
289 if (maxGradient < tolerance_) {
290 info_ = ComputationInfo::Success;
295 info_ = ComputationInfo::NoConvergence;
305 if (numInactive_ == A_.rows()) {
306 info_ = ComputationInfo::NumericalIssue;
310 moveToInactiveSet_(argmaxGradient);
316 info_ = ComputationInfo::NoConvergence;
324 solveInactiveSet_(b);
326 if (!y_.allFinite())
return x_;
329 bool feasible =
true;
331 Index infeasibleIdx = -1;
332 for (Index i = 0; i < numInactive_; i++) {
333 Index idx = index_sets_[i];
336 Scalar t = -x_(idx) / (y_(idx) - x_(idx));
344 eigen_assert(feasible || 0 <= infeasibleIdx);
353 for (Index i = 0; i < numInactive_; i++) {
354 Index idx = index_sets_[i];
355 x_(idx) += alpha * (y_(idx) - x_(idx));
359 moveToActiveSet_(infeasibleIdx);
364template <
typename MatrixType>
365void NNLS<MatrixType>::moveToInactiveSet_(Index idx) {
367 std::swap(index_sets_(idx), index_sets_(numInactive_));
371 internal::householder_qr_inplace_update(QR_, qrCoeffs_, A_.col(index_sets_(numInactive_ - 1)), numInactive_ - 1,
372 tempSolutionVector_.data());
375template <
typename MatrixType>
376void NNLS<MatrixType>::moveToActiveSet_(Index idx) {
378 std::swap(index_sets_(idx), index_sets_(numInactive_ - 1));
381 for (Index i = idx; i < numInactive_; i++) {
382 Index col = index_sets_(i);
383 internal::householder_qr_inplace_update(QR_, qrCoeffs_, A_.col(col), i, tempSolutionVector_.data());
387template <
typename MatrixType>
388void NNLS<MatrixType>::solveInactiveSet_(
const RhsVectorType &b) {
389 eigen_assert(numInactive_ > 0);
395 tempRhsVector_.applyOnTheLeft(
396 householderSequence(QR_.leftCols(numInactive_), qrCoeffs_.head(numInactive_)).transpose());
400 tempSolutionVector_.head(numInactive_) =
401 QR_.topLeftCorner(numInactive_, numInactive_)
402 .template triangularView<Upper>()
403 .solve(tempRhsVector_.head(numInactive_));
406 tempSolutionVector_.tail(y_.size() - numInactive_).setZero();
409 y_.noalias() = index_sets_.asPermutation() * tempSolutionVector_.head(y_.size());
414#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
Matrix< Scalar, RowsAtCompileTime, 1 > RhsVectorType
Definition NNLS:88
Matrix< Scalar, ColsAtCompileTime, 1 > SolutionVectorType
Definition NNLS:86
Index iterations() const
Definition NNLS:154
ComputationInfo info() const
Definition NNLS:157
NNLS< MatrixType > & compute(const EigenBase< MatrixDerived > &A)
Definition NNLS:226
const SolutionVectorType & x() const
Returns the solution if a problem was solved. If not, an uninitialized vector may be returned.
Definition NNLS:122
Scalar tolerance() const
Definition NNLS:127
NNLS< MatrixType > & setMaxIterations(Index maxIters)
Definition NNLS:148
NNLS< MatrixType > & setTolerance(const Scalar &tolerance)
Definition NNLS:134
const SolutionVectorType & solve(const RhsVectorType &b)
Solves the NNLS problem.
Definition NNLS:251
Index maxIterations() const
Definition NNLS:142
Derived & setZero(Index rows, Index cols)
HouseholderSequence< VectorsType, CoeffsType > householderSequence(const VectorsType &v, const CoeffsType &h)
Namespace containing all symbols from the Eigen library.
constexpr Derived & derived()