determinant.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00015 #ifndef determinant_h
00016 #define determinant_h
00017 
00018 #include <cml/matrix/lu.h>
00019 
00020 namespace cml {
00021 namespace detail {
00022 
00023 /* Need to use a functional, since template functions cannot be
00024  * specialized.  N is used to differentiate dimension only, so this can be
00025  * used for any matrix size type:
00026  */
00027 template<typename MatT, int N> struct determinant_f;
00028 
00029 /* 2x2 determinant.  Despite being marked for fixed_size matrices, this can
00030  * be used for dynamic-sized ones also:
00031  */
00032 template<typename MatT>
00033 struct determinant_f<MatT,2>
00034 {
00035     typename MatT::value_type operator()(const MatT& M) const
00036     {
00037         return M(0,0)*M(1,1) - M(1,0)*M(0,1);
00038     }
00039 
00040 };
00041 
00042 /* 3x3 determinant.  Despite being marked for fixed_size matrices, this can
00043  * be used for dynamic-sized ones also:
00044  */
00045 template<typename MatT>
00046 struct determinant_f<MatT,3>
00047 {
00048     /*     [00 01 02]
00049      * M = [10 11 12]
00050      *     [20 21 22]
00051      */
00052     typename MatT::value_type operator()(const MatT& M) const
00053     {
00054         return M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
00055              + M(0,1)*(M(1,2)*M(2,0) - M(1,0)*M(2,2))
00056              + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00057     }
00058 
00059 };
00060 
00061 /* 4x4 determinant.  Despite being marked for fixed_size matrices, this can
00062  * be used for dynamic-sized ones also:
00063  */
00064 template<typename MatT>
00065 struct determinant_f<MatT,4>
00066 {
00067     /*     [00 01 02 03]
00068      * M = [10 11 12 13]
00069      *     [20 21 22 23]
00070      *     [30 31 32 33]
00071      *
00072      *       |11 12 13|         |10 12 13|
00073      * C00 = |21 22 23|   C01 = |20 22 23|
00074      *       |31 32 33|         |30 32 33|
00075      *
00076      *       |10 11 13|         |10 11 12|
00077      * C02 = |20 21 23|   C03 = |20 21 22|
00078      *       |30 31 33|         |30 31 32|
00079      *
00080      * d00 =   11 * (22*33 - 23*32)  d01 =   10 * (22*33 - 23*32)
00081      *       + 12 * (23*31 - 21*33)        + 12 * (23*30 - 20*33)
00082      *       + 13 * (21*32 - 22*31)        + 13 * (20*32 - 22*30)
00083      *
00084      * d02 =   10 * (21*33 - 23*31)  d03 =   10 * (21*32 - 22*31)
00085      *       + 11 * (23*30 - 20*33)        + 11 * (22*30 - 20*32)
00086      *       + 13 * (20*31 - 21*30)        + 12 * (20*31 - 21*30)
00087      */
00088     typename MatT::value_type operator()(const MatT& M) const
00089     {
00090         /* Shorthand. */
00091         typedef typename MatT::value_type value_type;
00092 
00093         /* Common cofactors: */
00094         value_type m_22_33_23_32 = M(2,2)*M(3,3) - M(2,3)*M(3,2);
00095         value_type m_23_30_20_33 = M(2,3)*M(3,0) - M(2,0)*M(3,3);
00096         value_type m_20_31_21_30 = M(2,0)*M(3,1) - M(2,1)*M(3,0);
00097         value_type m_21_32_22_31 = M(2,1)*M(3,2) - M(2,2)*M(3,1);
00098         value_type m_23_31_21_33 = M(2,3)*M(3,1) - M(2,1)*M(3,3);
00099         value_type m_20_32_22_30 = M(2,0)*M(3,2) - M(2,2)*M(3,0);
00100 
00101         value_type d00 = M(0,0)*(
00102                 M(1,1) * m_22_33_23_32
00103               + M(1,2) * m_23_31_21_33
00104               + M(1,3) * m_21_32_22_31);
00105 
00106         value_type d01 = M(0,1)*(
00107                 M(1,0) * m_22_33_23_32
00108               + M(1,2) * m_23_30_20_33
00109               + M(1,3) * m_20_32_22_30);
00110 
00111         value_type d02 = M(0,2)*(
00112                 M(1,0) * - m_23_31_21_33
00113               + M(1,1) * m_23_30_20_33
00114               + M(1,3) * m_20_31_21_30);
00115 
00116         value_type d03 = M(0,3)*(
00117                 M(1,0) * m_21_32_22_31
00118               + M(1,1) * - m_20_32_22_30
00119               + M(1,2) * m_20_31_21_30);
00120 
00121         return d00 - d01 + d02 - d03;
00122     }
00123 
00124 };
00125 
00126 /* General NxN determinant by LU factorization:  */
00127 template<typename MatT, int N>
00128 struct determinant_f
00129 {
00130     typename MatT::value_type operator()(const MatT& M) const
00131     {
00132         /* Compute the LU factorization: */
00133         typename MatT::temporary_type LU = lu(M);
00134 
00135         /* The product of the diagonal entries is the determinant: */
00136         typename MatT::value_type det = LU(0,0);
00137         for(size_t i = 1; i < LU.rows(); ++ i)
00138             det *= LU(i,i);
00139         return det;
00140     }
00141 
00142 };
00143 
00144 /* Generator for the determinant functional for fixed-size matrices: */
00145 template<typename MatT> typename MatT::value_type
00146 determinant(const MatT& M, fixed_size_tag)
00147 {
00148     /* Require a square matrix: */
00149     cml::et::CheckedSquare(M, fixed_size_tag());
00150     return determinant_f<MatT,MatT::array_rows>()(M);
00151 }
00152 
00153 /* Generator for the determinant functional for dynamic-size matrices: */
00154 template<typename MatT> typename MatT::value_type
00155 determinant(const MatT& M, dynamic_size_tag)
00156 {
00157     /* Require a square matrix: */
00158     cml::et::CheckedSquare(M, dynamic_size_tag());
00159 
00160     /* Dispatch based upon the matrix dimension: */
00161     switch(M.rows()) {
00162         case 2:  return determinant_f<MatT,2>()(M);
00163         case 3:  return determinant_f<MatT,3>()(M);
00164         case 4:  return determinant_f<MatT,4>()(M);
00165         default: return determinant_f<MatT,0>()(M);     // > 4x4.
00166     }
00167 }
00168 
00169 } // namespace detail
00170 
00172 template<typename E, class AT, class BO, class L> inline E
00173 determinant(const matrix<E,AT,BO,L>& M)
00174 {
00175     typedef typename matrix<E,AT,BO,L>::size_tag size_tag;
00176     return detail::determinant(M,size_tag());
00177 }
00178 
00180 template<typename XprT> inline typename XprT::value_type
00181 determinant(const et::MatrixXpr<XprT>& e)
00182 {
00183     typedef typename et::MatrixXpr<XprT>::size_tag size_tag;
00184     return detail::determinant(e,size_tag());
00185 }
00186 
00187 } // namespace cml
00188 
00189 #endif
00190 
00191 // -------------------------------------------------------------------------
00192 // vim:ft=cpp

Generated on Sat Jul 18 19:35:22 2009 for CML 1.0 by  doxygen 1.5.9