146 lines
7.0 KiB
C++
146 lines
7.0 KiB
C++
/* ----------------------------------------------------------------------------
|
|
|
|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
|
* Atlanta, Georgia 30332-0415
|
|
* All Rights Reserved
|
|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
|
|
|
* See LICENSE for the license information
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* @file linearExceptions.h
|
|
* @brief Exceptions that may be thrown by linear solver components
|
|
* @author Richard Roberts
|
|
* @date Aug 17, 2012
|
|
*/
|
|
#pragma once
|
|
|
|
#include <gtsam/base/ThreadsafeException.h>
|
|
#include <gtsam/base/types.h>
|
|
|
|
namespace gtsam {
|
|
|
|
/**
|
|
Thrown when a linear system is ill-posed. The most common cause for this
|
|
error is having underconstrained variables. Mathematically, the system is
|
|
either underdetermined, or its quadratic error function is concave in some
|
|
directions.
|
|
|
|
Examples of situations causing this error are:
|
|
- A landmark observed by two cameras with a very small baseline will have
|
|
high uncertainty in its distance from the cameras but low uncertainty
|
|
in its bearing, creating a poorly-conditioned system.
|
|
- A landmark observed by only a single ProjectionFactor, RangeFactor, or
|
|
BearingFactor (the landmark is not completely constrained).
|
|
- An overall scale or rigid transformation ambiguity, for example missing
|
|
a prior or hard constraint on the first pose, or missing a scale
|
|
constraint between the first two cameras (in structure-from-motion).
|
|
|
|
Mathematically, the following conditions cause this problem:
|
|
- Underdetermined system: This occurs when the variables are not
|
|
completely constrained by factors. Even if all variables are involved
|
|
in factors, the variables can still be numerically underconstrained,
|
|
(for example, if a landmark is observed by only one ProjectionFactor).
|
|
Mathematically in this case, the rank of the linear Jacobian or Hessian
|
|
is less than the number of scalars in the system.
|
|
- Indefinite system: This condition occurs when the system Hessian is
|
|
indefinite, i.e. non-positive-semidefinite. Note that this condition
|
|
can also indicate an underdetermined system, but when solving with
|
|
Cholesky, accumulation of numerical errors can cause the system to
|
|
become indefinite (have some negative eigenvalues) even if it is in
|
|
reality positive semi-definite (has some near-zero positive
|
|
eigenvalues). Alternatively, if the system contains some
|
|
HessianFactor's with negative eigenvalues, these can create a truly
|
|
indefinite system, whose quadratic error function has negative
|
|
curvature in some directions.
|
|
- Poorly-conditioned system: A system that is positive-definite (has a
|
|
unique solution) but is numerically ill-conditioned can accumulate
|
|
numerical errors during solving that cause the system to become
|
|
indefinite later during the elimination process. Note that poorly-
|
|
conditioned systems will usually have inaccurate solutions, even if
|
|
they do not always trigger this error. Systems with almost-
|
|
unconstrained variables or vastly different measurement uncertainties
|
|
or variable units can be poorly-conditioned.
|
|
|
|
Resolving this problem:
|
|
- This exception contains the variable at which the problem was
|
|
discovered (IndeterminantLinearSystemException::nearbyVariable()).
|
|
Note, however, that this is not necessarily the variable where the
|
|
problem originates. For example, in the case that a prior on the
|
|
first camera was forgotten, it may only be another camera or landmark
|
|
where the problem can be detected. Where the problem is detected
|
|
depends on the graph structure and variable elimination ordering.
|
|
- MATLAB (or similar software) is a useful tool to diagnose this problem.
|
|
Use GaussianFactorGraph::sparseJacobian_(),
|
|
GaussianFactorGraph::sparseJacobian()
|
|
GaussianFactorGraph::denseJacobian(), and
|
|
GaussianFactorGraph::denseHessian() to output the linear graph in
|
|
matrix format. If using the MATLAB wrapper, the returned matrices can
|
|
be immediately inspected and analyzed using standard methods. If not
|
|
using the MATLAB wrapper, the output of these functions may be written
|
|
to text files and then loaded into MATLAB.
|
|
- When outputting linear graphs as Jacobian matrices, rows are ordered in
|
|
the same order as factors in the graph, which each factor occupying the
|
|
number of rows indicated by its JacobianFactor::rows() function. Each
|
|
column appears in elimination ordering, as in the Ordering class. Each
|
|
variable occupies the number of columns indicated by the
|
|
JacobianFactor::getDim() function.
|
|
- When outputting linear graphs as Hessian matrices, rows and columns are
|
|
ordered in elimination order and occupy scalars in the same way as
|
|
described for Jacobian columns in the previous bullet.
|
|
*/
|
|
class GTSAM_EXPORT IndeterminantLinearSystemException : public ThreadsafeException<IndeterminantLinearSystemException> {
|
|
Key j_;
|
|
public:
|
|
IndeterminantLinearSystemException(Key j) noexcept : j_(j) {}
|
|
~IndeterminantLinearSystemException() noexcept override {}
|
|
Key nearbyVariable() const { return j_; }
|
|
const char* what() const noexcept override;
|
|
};
|
|
|
|
/* ************************************************************************* */
|
|
/** An exception indicating that the noise model dimension passed into a
|
|
* JacobianFactor has a different dimensionality than the factor. */
|
|
class GTSAM_EXPORT InvalidNoiseModel : public ThreadsafeException<InvalidNoiseModel> {
|
|
public:
|
|
const DenseIndex factorDims; ///< The dimensionality of the factor
|
|
const DenseIndex noiseModelDims; ///< The dimensionality of the noise model
|
|
|
|
InvalidNoiseModel(DenseIndex factorDims, DenseIndex noiseModelDims) :
|
|
factorDims(factorDims), noiseModelDims(noiseModelDims) {}
|
|
~InvalidNoiseModel() noexcept override {}
|
|
|
|
const char* what() const noexcept override;
|
|
|
|
private:
|
|
mutable std::string description_;
|
|
};
|
|
|
|
/* ************************************************************************* */
|
|
/** An exception indicating that a matrix block passed into a
|
|
* JacobianFactor has a different dimensionality than the factor. */
|
|
class GTSAM_EXPORT InvalidMatrixBlock : public ThreadsafeException<InvalidMatrixBlock> {
|
|
public:
|
|
const DenseIndex factorRows; ///< The dimensionality of the factor
|
|
const DenseIndex blockRows; ///< The dimensionality of the noise model
|
|
|
|
InvalidMatrixBlock(DenseIndex factorRows, DenseIndex blockRows) :
|
|
factorRows(factorRows), blockRows(blockRows) {}
|
|
~InvalidMatrixBlock() noexcept override {}
|
|
|
|
const char* what() const noexcept override;
|
|
|
|
private:
|
|
mutable std::string description_;
|
|
};
|
|
|
|
/* ************************************************************************* */
|
|
class InvalidDenseElimination : public ThreadsafeException<InvalidDenseElimination> {
|
|
public:
|
|
InvalidDenseElimination(const char *message) : ThreadsafeException<InvalidDenseElimination>(message) {}
|
|
};
|
|
|
|
}
|