blob: df8a22ebe58fe8d886202c03b52a3405f86700a8 [file] [log] [blame]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.
#ifndef EIGEN_INVERSE_H
#define EIGEN_INVERSE_H
/** \lu_module
*
* \class Inverse
*
* \brief Inverse of a matrix
*
* \param MatrixType the type of the matrix of which we are taking the inverse
* \param CheckExistence whether or not to check the existence of the inverse while computing it
*
* This class represents the inverse of a matrix. It is the return
* type of MatrixBase::inverse() and most of the time this is the only way it
* is used.
*
* \sa MatrixBase::inverse(), MatrixBase::quickInverse()
*/
template<typename MatrixType, bool CheckExistence>
struct ei_traits<Inverse<MatrixType, CheckExistence> >
{
typedef typename MatrixType::Scalar Scalar;
enum {
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
Flags = MatrixType::Flags,
CoeffReadCost = MatrixType::CoeffReadCost
};
};
template<typename MatrixType, bool CheckExistence> class Inverse : ei_no_assignment_operator,
public MatrixBase<Inverse<MatrixType, CheckExistence> >
{
public:
EIGEN_GENERIC_PUBLIC_INTERFACE(Inverse)
Inverse(const MatrixType& matrix)
: m_inverse(MatrixType::identity(matrix.rows(), matrix.cols()))
{
if(CheckExistence) m_exists = true;
ei_assert(matrix.rows() == matrix.cols());
_compute(matrix);
}
/** \returns whether or not the inverse exists.
*
* \note This method is only available if CheckExistence is set to true, which is the default value.
* For instance, when using quickInverse(), this method is not available.
*/
bool exists() const { assert(CheckExistence); return m_exists; }
int rows() const { return m_inverse.rows(); }
int cols() const { return m_inverse.cols(); }
const Scalar coeff(int row, int col) const
{
return m_inverse.coeff(row, col);
}
template<int LoadMode>
PacketScalar packet(int row, int col) const
{
return m_inverse.template packet<LoadMode>(row, col);
}
enum { _Size = MatrixType::RowsAtCompileTime };
void _compute(const MatrixType& matrix);
void _compute_in_general_case(const MatrixType& matrix);
void _compute_in_size2_case(const MatrixType& matrix);
void _compute_in_size3_case(const MatrixType& matrix);
void _compute_in_size4_case(const MatrixType& matrix);
protected:
bool m_exists;
typename MatrixType::Eval m_inverse;
};
template<typename MatrixType, bool CheckExistence>
void Inverse<MatrixType, CheckExistence>
::_compute_in_general_case(const MatrixType& _matrix)
{
MatrixType matrix(_matrix);
const RealScalar max = CheckExistence ? matrix.cwise().abs().maxCoeff()
: static_cast<RealScalar>(0);
const int size = matrix.rows();
for(int k = 0; k < size-1; k++)
{
int rowOfBiggest;
const RealScalar max_in_this_col
= matrix.col(k).end(size-k).cwise().abs().maxCoeff(&rowOfBiggest);
if(CheckExistence && ei_isMuchSmallerThan(max_in_this_col, max))
{ m_exists = false; return; }
m_inverse.row(k).swap(m_inverse.row(k+rowOfBiggest));
matrix.row(k).swap(matrix.row(k+rowOfBiggest));
const Scalar d = matrix(k,k);
m_inverse.block(k+1, 0, size-k-1, size)
-= matrix.col(k).end(size-k-1) * (m_inverse.row(k) / d);
matrix.corner(BottomRight, size-k-1, size-k)
-= matrix.col(k).end(size-k-1) * (matrix.row(k).end(size-k) / d);
}
for(int k = 0; k < size-1; k++)
{
const Scalar d = static_cast<Scalar>(1)/matrix(k,k);
matrix.row(k).end(size-k) *= d;
m_inverse.row(k) *= d;
}
if(CheckExistence && ei_isMuchSmallerThan(matrix(size-1,size-1), max))
{ m_exists = false; return; }
m_inverse.row(size-1) /= matrix(size-1,size-1);
for(int k = size-1; k >= 1; k--)
{
m_inverse.block(0,0,k,size) -= matrix.col(k).start(k) * m_inverse.row(k);
}
}
template<typename ExpressionType, bool CheckExistence>
bool ei_compute_size2_inverse(const ExpressionType& xpr, typename ExpressionType::Eval* result)
{
typedef typename ExpressionType::Scalar Scalar;
const typename ei_nested<ExpressionType, 1+CheckExistence>::type matrix(xpr);
const Scalar det = matrix.determinant();
if(CheckExistence && ei_isMuchSmallerThan(det, matrix.cwise().abs().maxCoeff()))
return false;
const Scalar invdet = static_cast<Scalar>(1) / det;
result->coeffRef(0,0) = matrix.coeff(1,1) * invdet;
result->coeffRef(1,0) = -matrix.coeff(1,0) * invdet;
result->coeffRef(0,1) = -matrix.coeff(0,1) * invdet;
result->coeffRef(1,1) = matrix.coeff(0,0) * invdet;
return true;
}
template<typename MatrixType, bool CheckExistence>
void Inverse<MatrixType, CheckExistence>::_compute_in_size3_case(const MatrixType& matrix)
{
const Scalar det_minor00 = matrix.minor(0,0).determinant();
const Scalar det_minor10 = matrix.minor(1,0).determinant();
const Scalar det_minor20 = matrix.minor(2,0).determinant();
const Scalar det = det_minor00 * matrix.coeff(0,0)
- det_minor10 * matrix.coeff(1,0)
+ det_minor20 * matrix.coeff(2,0);
if(CheckExistence && ei_isMuchSmallerThan(det, matrix.cwise().abs().maxCoeff()))
m_exists = false;
else
{
const Scalar invdet = static_cast<Scalar>(1) / det;
m_inverse.coeffRef(0, 0) = det_minor00 * invdet;
m_inverse.coeffRef(0, 1) = -det_minor10 * invdet;
m_inverse.coeffRef(0, 2) = det_minor20 * invdet;
m_inverse.coeffRef(1, 0) = -matrix.minor(0,1).determinant() * invdet;
m_inverse.coeffRef(1, 1) = matrix.minor(1,1).determinant() * invdet;
m_inverse.coeffRef(1, 2) = -matrix.minor(2,1).determinant() * invdet;
m_inverse.coeffRef(2, 0) = matrix.minor(0,2).determinant() * invdet;
m_inverse.coeffRef(2, 1) = -matrix.minor(1,2).determinant() * invdet;
m_inverse.coeffRef(2, 2) = matrix.minor(2,2).determinant() * invdet;
}
}
template<typename MatrixType, bool CheckExistence>
void Inverse<MatrixType, CheckExistence>::_compute_in_size4_case(const MatrixType& matrix)
{
/* Let's split M into four 2x2 blocks:
* (P Q)
* (R S)
* If P is invertible, with inverse denoted by P_inverse, and if
* (S - R*P_inverse*Q) is also invertible, then the inverse of M is
* (P' Q')
* (R' S')
* where
* S' = (S - R*P_inverse*Q)^(-1)
* P' = P1 + (P1*Q) * S' *(R*P_inverse)
* Q' = -(P_inverse*Q) * S'
* R' = -S' * (R*P_inverse)
*/
typedef Block<MatrixType,2,2> XprBlock22;
typedef typename XprBlock22::Eval Block22;
Block22 P_inverse;
if(ei_compute_size2_inverse<XprBlock22, true>(matrix.template block<2,2>(0,0), &P_inverse))
{
const Block22 Q = matrix.template block<2,2>(0,2);
const Block22 P_inverse_times_Q = P_inverse * Q;
const XprBlock22 R = matrix.template block<2,2>(2,0);
const Block22 R_times_P_inverse = R * P_inverse;
const Block22 R_times_P_inverse_times_Q = R_times_P_inverse * Q;
const XprBlock22 S = matrix.template block<2,2>(2,2);
const Block22 X = S - R_times_P_inverse_times_Q;
Block22 Y;
if(ei_compute_size2_inverse<Block22, CheckExistence>(X, &Y))
{
m_inverse.template block<2,2>(2,2) = Y;
m_inverse.template block<2,2>(2,0) = - Y * R_times_P_inverse;
const Block22 Z = P_inverse_times_Q * Y;
m_inverse.template block<2,2>(0,2) = - Z;
m_inverse.template block<2,2>(0,0) = P_inverse + Z * R_times_P_inverse;
}
else
{
m_exists = false; return;
}
}
else
{
_compute_in_general_case(matrix);
}
}
template<typename MatrixType, bool CheckExistence>
void Inverse<MatrixType, CheckExistence>::_compute(const MatrixType& matrix)
{
if(_Size == 1)
{
const Scalar x = matrix.coeff(0,0);
if(CheckExistence && x == static_cast<Scalar>(0))
m_exists = false;
else
m_inverse.coeffRef(0,0) = static_cast<Scalar>(1) / x;
}
else if(_Size == 2)
{
if(CheckExistence)
m_exists = ei_compute_size2_inverse<MatrixType, true>(matrix, &m_inverse);
else
ei_compute_size2_inverse<MatrixType, false>(matrix, &m_inverse);
}
else if(_Size == 3) _compute_in_size3_case(matrix);
else if(_Size == 4) _compute_in_size4_case(matrix);
else _compute_in_general_case(matrix);
}
/** \lu_module
*
* \returns the matrix inverse of \c *this, if it exists.
*
* Example: \include MatrixBase_inverse.cpp
* Output: \verbinclude MatrixBase_inverse.out
*
* \sa class Inverse
*/
template<typename Derived>
const Inverse<typename ei_eval<Derived>::type, true>
MatrixBase<Derived>::inverse() const
{
return Inverse<typename Derived::Eval, true>(eval());
}
/** \lu_module
*
* \returns the matrix inverse of \c *this, which is assumed to exist.
*
* Example: \include MatrixBase_quickInverse.cpp
* Output: \verbinclude MatrixBase_quickInverse.out
*
* \sa class Inverse
*/
template<typename Derived>
const Inverse<typename ei_eval<Derived>::type, false>
MatrixBase<Derived>::quickInverse() const
{
return Inverse<typename Derived::Eval, false>(eval());
}
#endif // EIGEN_INVERSE_H