// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud // // 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 . #ifndef EIGEN_SOLVETRIANGULAR_H #define EIGEN_SOLVETRIANGULAR_H template class ei_trsolve_traits { private: enum { RhsIsVectorAtCompileTime = (Side==OnTheLeft ? Rhs::ColsAtCompileTime : Rhs::RowsAtCompileTime)==1 }; public: enum { Unrolling = (RhsIsVectorAtCompileTime && Rhs::SizeAtCompileTime != Dynamic && Rhs::SizeAtCompileTime <= 8) ? CompleteUnrolling : NoUnrolling, RhsVectors = RhsIsVectorAtCompileTime ? 1 : Dynamic }; }; template::Unrolling, int StorageOrder = (int(Lhs::Flags) & RowMajorBit) ? RowMajor : ColMajor, int RhsVectors = ei_trsolve_traits::RhsVectors > struct ei_triangular_solver_selector; // forward and backward substitution, row-major, rhs is a vector template struct ei_triangular_solver_selector { typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; typedef ei_blas_traits LhsProductTraits; typedef typename LhsProductTraits::ExtractType ActualLhsType; typedef typename Lhs::Index Index; enum { IsLower = ((Mode&Lower)==Lower) }; static void run(const Lhs& lhs, Rhs& other) { static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH; ActualLhsType actualLhs = LhsProductTraits::extract(lhs); const Index size = lhs.cols(); for(Index pi=IsLower ? 0 : size; IsLower ? pi0; IsLower ? pi+=PanelWidth : pi-=PanelWidth) { Index actualPanelWidth = std::min(IsLower ? size - pi : pi, PanelWidth); Index r = IsLower ? pi : size - pi; // remaining size if (r > 0) { // let's directly call the low level product function because: // 1 - it is faster to compile // 2 - it is slighlty faster at runtime Index startRow = IsLower ? pi : pi-actualPanelWidth; Index startCol = IsLower ? 0 : pi; ei_general_matrix_vector_product::run( actualPanelWidth, r, &(actualLhs.const_cast_derived().coeffRef(startRow,startCol)), actualLhs.outerStride(), &(other.coeffRef(startCol)), other.innerStride(), &other.coeffRef(startRow), other.innerStride(), RhsScalar(-1)); } for(Index k=0; k0) other.coeffRef(i) -= (lhs.row(i).segment(s,k).transpose().cwiseProduct(other.segment(s,k))).sum(); if(!(Mode & UnitDiag)) other.coeffRef(i) /= lhs.coeff(i,i); } } } }; // forward and backward substitution, column-major, rhs is a vector template struct ei_triangular_solver_selector { typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; typedef ei_blas_traits LhsProductTraits; typedef typename LhsProductTraits::ExtractType ActualLhsType; typedef typename Lhs::Index Index; enum { IsLower = ((Mode&Lower)==Lower) }; static void run(const Lhs& lhs, Rhs& other) { static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH; ActualLhsType actualLhs = LhsProductTraits::extract(lhs); const Index size = lhs.cols(); for(Index pi=IsLower ? 0 : size; IsLower ? pi0; IsLower ? pi+=PanelWidth : pi-=PanelWidth) { Index actualPanelWidth = std::min(IsLower ? size - pi : pi, PanelWidth); Index startBlock = IsLower ? pi : pi-actualPanelWidth; Index endBlock = IsLower ? pi + actualPanelWidth : 0; for(Index k=0; k0) other.segment(s,r) -= other.coeffRef(i) * Block(lhs, s, i, r, 1); } Index r = IsLower ? size - endBlock : startBlock; // remaining size if (r > 0) { // let's directly call the low level product function because: // 1 - it is faster to compile // 2 - it is slighlty faster at runtime ei_general_matrix_vector_product::run( r, actualPanelWidth, &(actualLhs.const_cast_derived().coeffRef(endBlock,startBlock)), actualLhs.outerStride(), &other.coeff(startBlock), other.innerStride(), &(other.coeffRef(endBlock, 0)), other.innerStride(), RhsScalar(-1)); } } } }; // transpose OnTheRight cases for vectors template struct ei_triangular_solver_selector { static void run(const Lhs& lhs, Rhs& rhs) { Transpose rhsTr(rhs); Transpose lhsTr(lhs); ei_triangular_solver_selector,Transpose,OnTheLeft,TriangularView::TransposeMode>::run(lhsTr,rhsTr); } }; template struct ei_triangular_solve_matrix; // the rhs is a matrix template struct ei_triangular_solver_selector { typedef typename Rhs::Scalar Scalar; typedef typename Rhs::Index Index; typedef ei_blas_traits LhsProductTraits; typedef typename LhsProductTraits::DirectLinearAccessType ActualLhsType; static void run(const Lhs& lhs, Rhs& rhs) { const ActualLhsType actualLhs = LhsProductTraits::extract(lhs); ei_triangular_solve_matrix ::run(lhs.rows(), Side==OnTheLeft? rhs.cols() : rhs.rows(), &actualLhs.coeff(0,0), actualLhs.outerStride(), &rhs.coeffRef(0,0), rhs.outerStride()); } }; /*************************************************************************** * meta-unrolling implementation ***************************************************************************/ template struct ei_triangular_solver_unroller; template struct ei_triangular_solver_unroller { enum { IsLower = ((Mode&Lower)==Lower), I = IsLower ? Index : Size - Index - 1, S = IsLower ? 0 : I+1 }; static void run(const Lhs& lhs, Rhs& rhs) { if (Index>0) rhs.coeffRef(I) -= lhs.row(I).template segment(S).transpose().cwiseProduct(rhs.template segment(S)).sum(); if(!(Mode & UnitDiag)) rhs.coeffRef(I) /= lhs.coeff(I,I); ei_triangular_solver_unroller::run(lhs,rhs); } }; template struct ei_triangular_solver_unroller { static void run(const Lhs&, Rhs&) {} }; template struct ei_triangular_solver_selector { static void run(const Lhs& lhs, Rhs& rhs) { ei_triangular_solver_unroller::run(lhs,rhs); } }; /*************************************************************************** * TriangularView methods ***************************************************************************/ /** "in-place" version of TriangularView::solve() where the result is written in \a other * * * * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. * This function will const_cast it, so constness isn't honored here. * * See TriangularView:solve() for the details. */ template template void TriangularView::solveInPlace(const MatrixBase& _other) const { OtherDerived& other = _other.const_cast_derived(); ei_assert(cols() == rows()); ei_assert( (Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols()) ); ei_assert(!(Mode & ZeroDiag)); ei_assert(Mode & (Upper|Lower)); enum { copy = ei_traits::Flags & RowMajorBit && OtherDerived::IsVectorAtCompileTime }; typedef typename ei_meta_if::type, OtherDerived&>::ret OtherCopy; OtherCopy otherCopy(other); ei_triangular_solver_selector::type, Side, Mode>::run(nestedExpression(), otherCopy); if (copy) other = otherCopy; } /** \returns the product of the inverse of \c *this with \a other, \a *this being triangular. * * * * This function computes the inverse-matrix matrix product inverse(\c *this) * \a other. * The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the * diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this * is an upper (resp. lower) triangular matrix. * * It is required that \c *this be marked as either an upper or a lower triangular matrix, which * can be done by marked(), and that is automatically the case with expressions such as those returned * by extract(). * * Example: \include MatrixBase_marked.cpp * Output: \verbinclude MatrixBase_marked.out * * This function is essentially a wrapper to the faster solveTriangularInPlace() function creating * a temporary copy of \a other, calling solveTriangularInPlace() on the copy and returning it. * Therefore, if \a other is not needed anymore, it is quite faster to call solveTriangularInPlace() * instead of solveTriangular(). * * For users coming from BLAS, this function (and more specifically solveTriangularInPlace()) offer * all the operations supported by the \c *TRSV and \c *TRSM BLAS routines. * * \b Tips: to perform a \em "right-inverse-multiply" you can simply transpose the operation, e.g.: * \code * M * T^1 <=> T.transpose().solveInPlace(M.transpose()); * \endcode * * \sa TriangularView::solveInPlace() */ template template typename ei_plain_matrix_type_column_major::type TriangularView::solve(const MatrixBase& rhs) const { typename ei_plain_matrix_type_column_major::type res(rhs); solveInPlace(res); return res; } #endif // EIGEN_SOLVETRIANGULAR_H