Initial commit
This commit is contained in:
341
Lib/Include/CML/matrix/class_ops.h
Normal file
341
Lib/Include/CML/matrix/class_ops.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* @note GCC4 requires a copy constructor to elide---it won't elide a
|
||||
* compiler-generated copy constructor!
|
||||
*/
|
||||
|
||||
#ifndef matrix_class_ops_h
|
||||
#define matrix_class_ops_h
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1400
|
||||
#pragma warning(disable:4003)
|
||||
// XXX Horrible hack to turn off warnings about "not enough actual params"
|
||||
// for the macros below.
|
||||
#endif
|
||||
|
||||
/* This is to circumvent the problem of commas in a macro argument. It's
|
||||
* used to instantiate CML_ACCUMULATED_MATRIX_MULT:
|
||||
*/
|
||||
#define TEMPLATED_MATRIX_MACRO matrix<E,AT,BO,L>
|
||||
|
||||
/* XXX HACK!!! This is a hack to resize in the assign() functions only when
|
||||
* auto resizing is turned off.
|
||||
*/
|
||||
#if !defined(CML_MATRIX_RESIZE_ON_ASSIGNMENT)
|
||||
#define _DO_MATRIX_SET_RESIZE(_R_,_C_) cml::et::detail::Resize(*this,_R_,_C_)
|
||||
#else
|
||||
#define _DO_MATRIX_SET_RESIZE(_R_,_C_)
|
||||
#endif
|
||||
|
||||
/** Set a matrix from 2x2 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_ASSIGN_MAT_22 \
|
||||
matrix_type& \
|
||||
set( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \
|
||||
) \
|
||||
{ \
|
||||
_DO_MATRIX_SET_RESIZE(2,2); \
|
||||
/* This is overkill, but simplifies size checking: */ \
|
||||
value_type v[2][2] = {{e00,e01},{e10,e11}}; \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
typedef const value_type element; \
|
||||
cml::matrix<element, external<2,2>, basis_orient, row_major> \
|
||||
src(&v[0][0]); \
|
||||
et::UnrollAssignment<OpT>(*this,src); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
/** Create a matrix from 3x3 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_ASSIGN_MAT_33 \
|
||||
matrix_type& \
|
||||
set( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \
|
||||
ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \
|
||||
) \
|
||||
{ \
|
||||
_DO_MATRIX_SET_RESIZE(3,3); \
|
||||
/* This is overkill, but simplifies size checking: */ \
|
||||
value_type v[3][3] = { \
|
||||
{e00,e01,e02}, \
|
||||
{e10,e11,e12}, \
|
||||
{e20,e21,e22} \
|
||||
}; \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
typedef const value_type element; \
|
||||
cml::matrix<element, external<3,3>, basis_orient, row_major> \
|
||||
src(&v[0][0]); \
|
||||
et::UnrollAssignment<OpT>(*this,src); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
/** Create a matrix from 4x4 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_ASSIGN_MAT_44 \
|
||||
matrix_type& \
|
||||
set( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \
|
||||
ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \
|
||||
ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \
|
||||
ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \
|
||||
ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \
|
||||
ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \
|
||||
ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \
|
||||
) \
|
||||
{ \
|
||||
_DO_MATRIX_SET_RESIZE(4,4); \
|
||||
/* This is overkill, but simplifies size checking: */ \
|
||||
value_type v[4][4] = { \
|
||||
{e00,e01,e02,e03}, \
|
||||
{e10,e11,e12,e13}, \
|
||||
{e20,e21,e22,e23}, \
|
||||
{e30,e31,e32,e33} \
|
||||
}; \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
typedef const value_type element; \
|
||||
cml::matrix<element, external<4,4>, basis_orient, row_major> \
|
||||
src(&v[0][0]); \
|
||||
et::UnrollAssignment<OpT>(*this,src); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
/** Create a matrix from 2x2 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_CONSTRUCT_MAT_22 \
|
||||
matrix( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \
|
||||
) \
|
||||
{ \
|
||||
set( \
|
||||
e00,e01, \
|
||||
e10,e11 \
|
||||
); \
|
||||
}
|
||||
|
||||
/** Create a matrix from 3x3 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_CONSTRUCT_MAT_33 \
|
||||
matrix( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \
|
||||
ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \
|
||||
) \
|
||||
{ \
|
||||
set( \
|
||||
e00,e01,e02, \
|
||||
e10,e11,e12, \
|
||||
e20,e21,e22 \
|
||||
); \
|
||||
}
|
||||
|
||||
/** Create a matrix from 4x4 values.
|
||||
*
|
||||
* The layout assumed for the values is that of the matrix being assigned.
|
||||
*/
|
||||
#define CML_CONSTRUCT_MAT_44 \
|
||||
matrix( \
|
||||
ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \
|
||||
ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \
|
||||
ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \
|
||||
ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \
|
||||
ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \
|
||||
ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \
|
||||
ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \
|
||||
ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \
|
||||
) \
|
||||
{ \
|
||||
set( \
|
||||
e00,e01,e02,e03, \
|
||||
e10,e11,e12,e13, \
|
||||
e20,e21,e22,e23, \
|
||||
e30,e31,e32,e33 \
|
||||
); \
|
||||
}
|
||||
|
||||
/** Copy-construct a matrix from a fixed-size array of values. */
|
||||
#define CML_MAT_COPY_FROM_FIXED_ARRAY(_R_,_C_) \
|
||||
matrix(const value_type m[_R_][_C_]) { \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
cml::matrix<const value_type, external<_R_,_C_>, \
|
||||
basis_orient, row_major> src(&m[0][0]); \
|
||||
et::UnrollAssignment<OpT>(*this,src); \
|
||||
}
|
||||
|
||||
/** Copy-construct a matrix from a runtime-sized array of values. */
|
||||
#define CML_MAT_COPY_FROM_ARRAY(_add_) \
|
||||
matrix(const value_type* const v, size_t R, size_t C) _add_ { \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
cml::matrix<value_type, external<>, basis_orient, \
|
||||
row_major > src(const_cast<value_type*>(v),R,C); \
|
||||
et::UnrollAssignment<OpT>(*this,src); \
|
||||
}
|
||||
|
||||
/** Copy this matrix from another using the given elementwise op.
|
||||
*
|
||||
* @internal This is required for GCC4, since it won't elide the default
|
||||
* copy constructor.
|
||||
*/
|
||||
#define CML_MAT_COPY_FROM_MATTYPE \
|
||||
matrix(const matrix_type& m) : array_type() { \
|
||||
typedef et::OpAssign <Element,Element> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,m); \
|
||||
}
|
||||
|
||||
/** Copy this matrix from another using the given elementwise op.
|
||||
*
|
||||
* This allows copies from arbitrary matrix types.
|
||||
*/
|
||||
#define CML_MAT_COPY_FROM_MAT \
|
||||
template<typename E, class AT, typename BO, typename L> \
|
||||
matrix(const TEMPLATED_MATRIX_MACRO& m) { \
|
||||
typedef et::OpAssign <Element,E> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,m); \
|
||||
}
|
||||
|
||||
/** Declare a function to copy this matrix from a matrix expression. */
|
||||
#define CML_MAT_COPY_FROM_MATXPR \
|
||||
template<class XprT> \
|
||||
matrix(MATXPR_ARG_TYPE e) { \
|
||||
/* Verify that a promotion exists at compile time: */ \
|
||||
typedef typename et::MatrixPromote< \
|
||||
matrix_type, typename XprT::result_type>::type result_type; \
|
||||
typedef typename XprT::value_type src_value_type; \
|
||||
typedef et::OpAssign <Element,src_value_type> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,e); \
|
||||
}
|
||||
|
||||
#if defined(CML_USE_GENERATED_MATRIX_ASSIGN_OP)
|
||||
#define CML_MAT_ASSIGN_FROM_MATTYPE
|
||||
#else
|
||||
/** Assign from the same matrix type.
|
||||
*
|
||||
* @param m the matrix to copy from.
|
||||
*
|
||||
* @note This is required for GCC4, otherwise it generates a slow
|
||||
* assignment operator using memcpy.
|
||||
*
|
||||
* @note ICC9/Linux-x86 seems to prefer its own assignment operator (need
|
||||
* to figure out why).
|
||||
*/
|
||||
#define CML_MAT_ASSIGN_FROM_MATTYPE \
|
||||
matrix_type& operator=(const matrix_type& m) { \
|
||||
typedef et::OpAssign<Element,Element> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,m); \
|
||||
return *this; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** Assign this matrix from another using the given elementwise op.
|
||||
*
|
||||
* This allows assignment from arbitrary matrix types.
|
||||
*
|
||||
* @param _op_ the operator (e.g. +=)
|
||||
* @param _op_name_ the op functor (e.g. et::OpAssign)
|
||||
*/
|
||||
#define CML_MAT_ASSIGN_FROM_MAT(_op_, _op_name_) \
|
||||
template<typename E, class AT, typename BO, typename L> matrix_type& \
|
||||
operator _op_ (const TEMPLATED_MATRIX_MACRO& m) { \
|
||||
typedef _op_name_ <Element,E> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,m); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
/** Declare a function to assign this matrix from a matrix expression.
|
||||
*
|
||||
* @param _op_ the operator (e.g. +=)
|
||||
* @param _op_name_ the op functor (e.g. et::OpAssign)
|
||||
*/
|
||||
#define CML_MAT_ASSIGN_FROM_MATXPR(_op_, _op_name_) \
|
||||
template<class XprT> matrix_type& \
|
||||
operator _op_ (MATXPR_ARG_TYPE e) { \
|
||||
/* Verify that a promotion exists at compile time: */ \
|
||||
typedef typename et::MatrixPromote< \
|
||||
matrix_type, typename XprT::result_type>::type result_type; \
|
||||
typedef typename XprT::value_type src_value_type; \
|
||||
typedef _op_name_ <Element,src_value_type> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,e); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
/** Declare a function to assign this matrix from a scalar.
|
||||
*
|
||||
* @param _op_ the operator (e.g. +=)
|
||||
* @param _op_name_ the op functor (e.g. et::OpAssign)
|
||||
*
|
||||
* @internal This shouldn't be used for ops, like +=, which aren't
|
||||
* defined in vector algebra.
|
||||
*/
|
||||
#define CML_MAT_ASSIGN_FROM_SCALAR(_op_, _op_name_) \
|
||||
matrix_type& operator _op_ (ELEMENT_ARG_TYPE s) { \
|
||||
typedef _op_name_ <Element,value_type> OpT; \
|
||||
et::UnrollAssignment<OpT>(*this,s); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
|
||||
/** Accumulated matrix multiplication.
|
||||
*
|
||||
* @throws std::invalid_argument if the matrices are not square.
|
||||
*/
|
||||
#define CML_ACCUMULATED_MATRIX_MULT(_arg_type_) \
|
||||
matrix_type& operator*=(_arg_type_ m) { \
|
||||
typedef typename et::MatrixPromote< \
|
||||
matrix_type, _arg_type_>::type result_type; \
|
||||
cml::et::CheckedSquare(*this, typename result_type::size_tag()); \
|
||||
return (*this = (*this)*m); \
|
||||
}
|
||||
|
||||
|
||||
/* These should only be used for testing: */
|
||||
#define CML_MATRIX_BRACE_OPERATORS \
|
||||
template<class Matrix> struct row_ref { \
|
||||
typedef typename Matrix::reference reference; \
|
||||
reference operator[](size_t col) { return m(row,col); } \
|
||||
Matrix& m; \
|
||||
size_t row; \
|
||||
}; \
|
||||
\
|
||||
template<class Matrix> struct const_row_ref { \
|
||||
typedef typename Matrix::const_reference const_reference; \
|
||||
const_reference operator[](size_t col) const { return m(row,col); } \
|
||||
const Matrix& m; \
|
||||
size_t row; \
|
||||
}; \
|
||||
\
|
||||
row_ref<matrix_type> operator[](size_t row) { \
|
||||
row_ref<matrix_type> ref = { *this, row }; return ref; \
|
||||
} \
|
||||
\
|
||||
const_row_ref<matrix_type> operator[](size_t row) const { \
|
||||
const_row_ref<matrix_type> ref = { *this, row }; return ref; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
192
Lib/Include/CML/matrix/determinant.h
Normal file
192
Lib/Include/CML/matrix/determinant.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Compute the determinant of a square matrix using LU factorization.
|
||||
*
|
||||
* @todo This should be specialized on the matrix size for small matrices.
|
||||
*/
|
||||
|
||||
#ifndef determinant_h
|
||||
#define determinant_h
|
||||
|
||||
#include <cml/matrix/lu.h>
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/* Need to use a functional, since template functions cannot be
|
||||
* specialized. N is used to differentiate dimension only, so this can be
|
||||
* used for any matrix size type:
|
||||
*/
|
||||
template<typename MatT, int N> struct determinant_f;
|
||||
|
||||
/* 2x2 determinant. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct determinant_f<MatT,2>
|
||||
{
|
||||
typename MatT::value_type operator()(const MatT& M) const
|
||||
{
|
||||
return M(0,0)*M(1,1) - M(1,0)*M(0,1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* 3x3 determinant. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct determinant_f<MatT,3>
|
||||
{
|
||||
/* [00 01 02]
|
||||
* M = [10 11 12]
|
||||
* [20 21 22]
|
||||
*/
|
||||
typename MatT::value_type operator()(const MatT& M) const
|
||||
{
|
||||
return M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
|
||||
+ M(0,1)*(M(1,2)*M(2,0) - M(1,0)*M(2,2))
|
||||
+ M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* 4x4 determinant. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct determinant_f<MatT,4>
|
||||
{
|
||||
/* [00 01 02 03]
|
||||
* M = [10 11 12 13]
|
||||
* [20 21 22 23]
|
||||
* [30 31 32 33]
|
||||
*
|
||||
* |11 12 13| |10 12 13|
|
||||
* C00 = |21 22 23| C01 = |20 22 23|
|
||||
* |31 32 33| |30 32 33|
|
||||
*
|
||||
* |10 11 13| |10 11 12|
|
||||
* C02 = |20 21 23| C03 = |20 21 22|
|
||||
* |30 31 33| |30 31 32|
|
||||
*
|
||||
* d00 = 11 * (22*33 - 23*32) d01 = 10 * (22*33 - 23*32)
|
||||
* + 12 * (23*31 - 21*33) + 12 * (23*30 - 20*33)
|
||||
* + 13 * (21*32 - 22*31) + 13 * (20*32 - 22*30)
|
||||
*
|
||||
* d02 = 10 * (21*33 - 23*31) d03 = 10 * (21*32 - 22*31)
|
||||
* + 11 * (23*30 - 20*33) + 11 * (22*30 - 20*32)
|
||||
* + 13 * (20*31 - 21*30) + 12 * (20*31 - 21*30)
|
||||
*/
|
||||
typename MatT::value_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef typename MatT::value_type value_type;
|
||||
|
||||
/* Common cofactors: */
|
||||
value_type m_22_33_23_32 = M(2,2)*M(3,3) - M(2,3)*M(3,2);
|
||||
value_type m_23_30_20_33 = M(2,3)*M(3,0) - M(2,0)*M(3,3);
|
||||
value_type m_20_31_21_30 = M(2,0)*M(3,1) - M(2,1)*M(3,0);
|
||||
value_type m_21_32_22_31 = M(2,1)*M(3,2) - M(2,2)*M(3,1);
|
||||
value_type m_23_31_21_33 = M(2,3)*M(3,1) - M(2,1)*M(3,3);
|
||||
value_type m_20_32_22_30 = M(2,0)*M(3,2) - M(2,2)*M(3,0);
|
||||
|
||||
value_type d00 = M(0,0)*(
|
||||
M(1,1) * m_22_33_23_32
|
||||
+ M(1,2) * m_23_31_21_33
|
||||
+ M(1,3) * m_21_32_22_31);
|
||||
|
||||
value_type d01 = M(0,1)*(
|
||||
M(1,0) * m_22_33_23_32
|
||||
+ M(1,2) * m_23_30_20_33
|
||||
+ M(1,3) * m_20_32_22_30);
|
||||
|
||||
value_type d02 = M(0,2)*(
|
||||
M(1,0) * - m_23_31_21_33
|
||||
+ M(1,1) * m_23_30_20_33
|
||||
+ M(1,3) * m_20_31_21_30);
|
||||
|
||||
value_type d03 = M(0,3)*(
|
||||
M(1,0) * m_21_32_22_31
|
||||
+ M(1,1) * - m_20_32_22_30
|
||||
+ M(1,2) * m_20_31_21_30);
|
||||
|
||||
return d00 - d01 + d02 - d03;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* General NxN determinant by LU factorization: */
|
||||
template<typename MatT, int N>
|
||||
struct determinant_f
|
||||
{
|
||||
typename MatT::value_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Compute the LU factorization: */
|
||||
typename MatT::temporary_type LU = lu(M);
|
||||
|
||||
/* The product of the diagonal entries is the determinant: */
|
||||
typename MatT::value_type det = LU(0,0);
|
||||
for(size_t i = 1; i < LU.rows(); ++ i)
|
||||
det *= LU(i,i);
|
||||
return det;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Generator for the determinant functional for fixed-size matrices: */
|
||||
template<typename MatT> typename MatT::value_type
|
||||
determinant(const MatT& M, fixed_size_tag)
|
||||
{
|
||||
/* Require a square matrix: */
|
||||
cml::et::CheckedSquare(M, fixed_size_tag());
|
||||
return determinant_f<MatT,MatT::array_rows>()(M);
|
||||
}
|
||||
|
||||
/* Generator for the determinant functional for dynamic-size matrices: */
|
||||
template<typename MatT> typename MatT::value_type
|
||||
determinant(const MatT& M, dynamic_size_tag)
|
||||
{
|
||||
/* Require a square matrix: */
|
||||
cml::et::CheckedSquare(M, dynamic_size_tag());
|
||||
|
||||
/* Dispatch based upon the matrix dimension: */
|
||||
switch(M.rows()) {
|
||||
case 2: return determinant_f<MatT,2>()(M);
|
||||
case 3: return determinant_f<MatT,3>()(M);
|
||||
case 4: return determinant_f<MatT,4>()(M);
|
||||
default: return determinant_f<MatT,0>()(M); // > 4x4.
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Determinant of a matrix. */
|
||||
template<typename E, class AT, class BO, class L> inline E
|
||||
determinant(const matrix<E,AT,BO,L>& M)
|
||||
{
|
||||
typedef typename matrix<E,AT,BO,L>::size_tag size_tag;
|
||||
return detail::determinant(M,size_tag());
|
||||
}
|
||||
|
||||
/** Determinant of a matrix expression. */
|
||||
template<typename XprT> inline typename XprT::value_type
|
||||
determinant(const et::MatrixXpr<XprT>& e)
|
||||
{
|
||||
typedef typename et::MatrixXpr<XprT>::size_tag size_tag;
|
||||
return detail::determinant(e,size_tag());
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
320
Lib/Include/CML/matrix/dynamic.h
Normal file
320
Lib/Include/CML/matrix/dynamic.h
Normal file
@@ -0,0 +1,320 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef dynamic_matrix_h
|
||||
#define dynamic_matrix_h
|
||||
|
||||
#include <cml/core/dynamic_2D.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
#include <cml/matrix/class_ops.h>
|
||||
#include <cml/matrix/matrix_unroller.h>
|
||||
|
||||
namespace cml {
|
||||
|
||||
/** Resizeable, dynamic-memory matrix. */
|
||||
template<typename Element, typename Alloc,
|
||||
typename BasisOrient, typename Layout>
|
||||
class matrix<Element,dynamic<Alloc>,BasisOrient,Layout>
|
||||
: public dynamic_2D<Element,Layout,Alloc>
|
||||
{
|
||||
public:
|
||||
|
||||
/* Shorthand for the generator: */
|
||||
typedef dynamic<Alloc> generator_type;
|
||||
|
||||
/* Shorthand for the array type: */
|
||||
typedef dynamic_2D<Element,Layout,Alloc> array_type;
|
||||
|
||||
/* Shorthand for the type of this matrix: */
|
||||
typedef matrix<Element,generator_type,BasisOrient,Layout> matrix_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type expr_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type temporary_type;
|
||||
|
||||
/* Standard: */
|
||||
typedef typename array_type::value_type value_type;
|
||||
typedef typename array_type::reference reference;
|
||||
typedef typename array_type::const_reference const_reference;
|
||||
|
||||
/* For integration into the expression templates code: */
|
||||
typedef matrix_type& expr_reference;
|
||||
typedef const matrix_type& expr_const_reference;
|
||||
|
||||
/* For matching by basis: */
|
||||
typedef BasisOrient basis_orient;
|
||||
|
||||
/* For matching by memory layout: */
|
||||
typedef typename array_type::layout layout;
|
||||
|
||||
/* For matching by storage type: */
|
||||
typedef typename array_type::memory_tag memory_tag;
|
||||
|
||||
/* For matching by size type if necessary: */
|
||||
typedef typename array_type::size_tag size_tag;
|
||||
|
||||
/* For matching by resizability: */
|
||||
typedef typename array_type::resizing_tag resizing_tag;
|
||||
|
||||
/* For matching by result type: */
|
||||
typedef cml::et::matrix_result_tag result_tag;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::assignable_tag assignable_tag;
|
||||
|
||||
/* To simplify the matrix transpose operator: */
|
||||
typedef matrix<
|
||||
Element,
|
||||
typename array_type::transposed_type::generator_type,
|
||||
BasisOrient,
|
||||
Layout
|
||||
> transposed_type;
|
||||
|
||||
/* To simplify the matrix row and column operators: */
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::row_array_type::generator_type
|
||||
> row_vector_type;
|
||||
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::col_array_type::generator_type
|
||||
> col_vector_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Set this matrix to zero. */
|
||||
matrix_type& zero() {
|
||||
typedef cml::et::OpAssign<Element,Element> OpT;
|
||||
cml::et::UnrollAssignment<OpT>(*this,Element(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to the identity.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& identity() {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) {
|
||||
(*this)(i,j) = value_type((i == j)?1:0);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its transpose.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& transpose() {
|
||||
/* transpose() returns a temporary: */
|
||||
*this = cml::transpose(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its inverse.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& inverse() {
|
||||
/* inverse() returns a temporary: */
|
||||
*this = cml::inverse(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* NOTE: minimize() and maximize() no longer supported (Jesse) */
|
||||
|
||||
#if 0
|
||||
/** Pairwise minimum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void minimize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::min((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pairwise maximum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void maximize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::max((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set each element to a random number in the range [min,max] */
|
||||
void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) {
|
||||
for(size_t i = 0; i < this->rows(); ++i) {
|
||||
for(size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = cml::random_real(min,max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Default constructor. */
|
||||
matrix() {}
|
||||
|
||||
/** Constructor for dynamically-sized arrays.
|
||||
*
|
||||
* @param rows specify the number of rows.
|
||||
* @param cols specify the number of cols.
|
||||
*/
|
||||
explicit matrix(size_t rows, size_t cols)
|
||||
: array_type(rows,cols) {}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the matrix size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return element j of basis vector i. */
|
||||
value_type basis_element(size_t i, size_t j) const {
|
||||
return basis_element(i,j,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the given basis element. */
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) {
|
||||
set_basis_element(i,j,s,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the matrix row from the given vector. */
|
||||
void set_row(size_t i, const row_vector_type& row) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j];
|
||||
}
|
||||
|
||||
/** Set the matrix column from the given vector. */
|
||||
void set_col(size_t j, const col_vector_type& col) {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i];
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Define common class operators: */
|
||||
|
||||
CML_CONSTRUCT_MAT_22
|
||||
CML_CONSTRUCT_MAT_33
|
||||
CML_CONSTRUCT_MAT_44
|
||||
|
||||
CML_MAT_COPY_FROM_ARRAY(: array_type())
|
||||
CML_MAT_COPY_FROM_MATTYPE
|
||||
CML_MAT_COPY_FROM_MAT
|
||||
CML_MAT_COPY_FROM_MATXPR
|
||||
|
||||
CML_ASSIGN_MAT_22
|
||||
CML_ASSIGN_MAT_33
|
||||
CML_ASSIGN_MAT_44
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATTYPE
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign)
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign)
|
||||
|
||||
/** Accumulated matrix multiplication.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& operator*=(const matrix_type& m) {
|
||||
/* Matrix multiplication returns a temporary: */
|
||||
*this = (*this)*m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Accumulated matrix multiplication.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
template<typename E, class AT, typename BO, typename L> matrix_type&
|
||||
operator*=(const matrix<E,AT,BO,L>& m) {
|
||||
/* Matrix multiplication returns a temporary: */
|
||||
*this = (*this)*m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Accumulated matrix multiplication.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
template<class XprT> matrix_type&
|
||||
operator*=(MATXPR_ARG_TYPE e) {
|
||||
/* Verify that a promotion exists at compile time: */
|
||||
typedef typename et::MatrixPromote<
|
||||
matrix_type, typename XprT::result_type>::type result_type;
|
||||
/* Matrix multiplication returns a temporary: */
|
||||
*this = (*this)*e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
value_type basis_element(size_t i, size_t j, row_basis) const {
|
||||
return (*this)(i,j);
|
||||
}
|
||||
|
||||
value_type basis_element(size_t i, size_t j, col_basis) const {
|
||||
return (*this)(j,i);
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) {
|
||||
(*this)(i,j) = s;
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) {
|
||||
(*this)(j,i) = s;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Braces should only be used for testing: */
|
||||
#if defined(CML_ENABLE_MATRIX_BRACES)
|
||||
CML_MATRIX_BRACE_OPERATORS
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
543
Lib/Include/CML/matrix/external.h
Normal file
543
Lib/Include/CML/matrix/external.h
Normal file
@@ -0,0 +1,543 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef external_matrix_h
|
||||
#define external_matrix_h
|
||||
|
||||
#include <cml/core/external_2D.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
#include <cml/matrix/class_ops.h>
|
||||
#include <cml/matrix/matrix_unroller.h>
|
||||
#include <cml/matrix/dynamic.h>
|
||||
|
||||
namespace cml {
|
||||
|
||||
/** Fixed-size, external-memory matrix. */
|
||||
template<typename Element, int Rows, int Cols,
|
||||
typename BasisOrient, typename Layout>
|
||||
class matrix<Element,external<Rows,Cols>,BasisOrient,Layout>
|
||||
: public external_2D<Element,Rows,Cols,Layout>
|
||||
{
|
||||
public:
|
||||
|
||||
/* Shorthand for the generator: */
|
||||
typedef external<Rows,Cols> generator_type;
|
||||
|
||||
/* Shorthand for the array type: */
|
||||
typedef external_2D<Element,Rows,Cols,Layout> array_type;
|
||||
|
||||
/* Shorthand for the type of this matrix: */
|
||||
typedef matrix<Element,generator_type,BasisOrient,Layout> matrix_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type expr_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix<Element,fixed<Rows,Cols>,BasisOrient,Layout> temporary_type;
|
||||
/* Note: this ensures that an external matrix is copied into the proper
|
||||
* temporary; external<> temporaries are not allowed.
|
||||
*/
|
||||
|
||||
/* Standard: */
|
||||
typedef typename array_type::value_type value_type;
|
||||
typedef typename array_type::reference reference;
|
||||
typedef typename array_type::const_reference const_reference;
|
||||
|
||||
typedef matrix_type& expr_reference;
|
||||
typedef const matrix_type& expr_const_reference;
|
||||
|
||||
/* For matching by basis: */
|
||||
typedef BasisOrient basis_orient;
|
||||
|
||||
/* For matching by memory layout: */
|
||||
typedef typename array_type::layout layout;
|
||||
|
||||
/* For matching by storage type if necessary: */
|
||||
typedef typename array_type::memory_tag memory_tag;
|
||||
|
||||
/* For matching by size type if necessary: */
|
||||
typedef typename array_type::size_tag size_tag;
|
||||
|
||||
/* For matching by resizability: */
|
||||
typedef typename array_type::resizing_tag resizing_tag;
|
||||
|
||||
/* For matching by result-type: */
|
||||
typedef cml::et::matrix_result_tag result_tag;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::assignable_tag assignable_tag;
|
||||
|
||||
/* To simplify the matrix transpose operator: */
|
||||
typedef matrix<
|
||||
typename cml::remove_const<Element>::type,
|
||||
typename array_type::transposed_type::generator_type,
|
||||
BasisOrient,
|
||||
Layout
|
||||
> transposed_type;
|
||||
|
||||
/* To simplify the matrix row and column operators: */
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::row_array_type::generator_type
|
||||
> row_vector_type;
|
||||
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::col_array_type::generator_type
|
||||
> col_vector_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Set this matrix to zero. */
|
||||
matrix_type& zero() {
|
||||
typedef cml::et::OpAssign<Element,Element> OpT;
|
||||
cml::et::UnrollAssignment<OpT>(*this,Element(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to the identity.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& identity() {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) {
|
||||
(*this)(i,j) = value_type((i == j)?1:0);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its transpose.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& transpose() {
|
||||
/* transpose() returns a temporary: */
|
||||
*this = transpose(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its inverse.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& inverse() {
|
||||
/* inverse() returns a temporary: */
|
||||
*this = cml::inverse(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* NOTE: minimize() and maximize() no longer supported (Jesse) */
|
||||
|
||||
#if 0
|
||||
/** Pairwise minimum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void minimize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::min((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pairwise maximum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void maximize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::max((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set each element to a random number in the range [min,max] */
|
||||
void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) {
|
||||
for(size_t i = 0; i < this->rows(); ++i) {
|
||||
for(size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = random_real(min,max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for fixed-size external matrices.
|
||||
*
|
||||
* The array must be given as a pointer to Element*, not a
|
||||
* multi-dimensional array. The caller owns the pointer, and is
|
||||
* responsible for doing any necessary memory management.
|
||||
*
|
||||
* @param ptr specify the external pointer.
|
||||
*
|
||||
* @throws same as the ArrayType constructor.
|
||||
*/
|
||||
explicit matrix(value_type ptr[Rows][Cols]) : array_type(ptr) {}
|
||||
|
||||
/** Constructor for fixed-size external matrices.
|
||||
*
|
||||
* The array must be given as a pointer to Element*, not a
|
||||
* multi-dimensional array. The caller owns the pointer, and is
|
||||
* responsible for doing any necessary memory management.
|
||||
*
|
||||
* @param ptr specify the external pointer.
|
||||
*
|
||||
* @throws same as the ArrayType constructor.
|
||||
*/
|
||||
explicit matrix(value_type* ptr) : array_type(ptr) {}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the matrix size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return element j of basis vector i. */
|
||||
value_type basis_element(size_t i, size_t j) const {
|
||||
return basis_element(i,j,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the given basis element. */
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) {
|
||||
set_basis_element(i,j,s,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the matrix row from the given vector. */
|
||||
void set_row(size_t i, const row_vector_type& row) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j];
|
||||
}
|
||||
|
||||
/** Set the matrix column from the given vector. */
|
||||
void set_col(size_t j, const col_vector_type& col) {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i];
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CML_ASSIGN_MAT_22
|
||||
CML_ASSIGN_MAT_33
|
||||
CML_ASSIGN_MAT_44
|
||||
|
||||
/* Define class operators for external matrices. Note: external matrices
|
||||
* cannot be copy-constructed, but they can be assigned to:
|
||||
*/
|
||||
CML_MAT_ASSIGN_FROM_MATTYPE
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign)
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign)
|
||||
|
||||
CML_ACCUMULATED_MATRIX_MULT(const matrix_type&)
|
||||
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&)
|
||||
|
||||
template<class XprT>
|
||||
CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE)
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
value_type basis_element(size_t i, size_t j, row_basis) const {
|
||||
return (*this)(i,j);
|
||||
}
|
||||
|
||||
value_type basis_element(size_t i, size_t j, col_basis) const {
|
||||
return (*this)(j,i);
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) {
|
||||
(*this)(i,j) = s;
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) {
|
||||
(*this)(j,i) = s;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Braces should only be used for testing: */
|
||||
#if defined(CML_ENABLE_MATRIX_BRACES)
|
||||
CML_MATRIX_BRACE_OPERATORS
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Dynamic-size, external-memory matrix. */
|
||||
template<typename Element, typename BasisOrient, typename Layout>
|
||||
class matrix<Element,external<-1,-1>,BasisOrient,Layout>
|
||||
: public external_2D<Element,-1,-1,Layout>
|
||||
{
|
||||
public:
|
||||
|
||||
/* Shorthand for the generator: */
|
||||
typedef external<> generator_type;
|
||||
|
||||
/* Shorthand for the array type: */
|
||||
typedef external_2D<Element,-1,-1,Layout> array_type;
|
||||
|
||||
/* Shorthand for the type of this matrix: */
|
||||
typedef matrix<Element,generator_type,BasisOrient,Layout> matrix_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type expr_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix<Element,dynamic<>,BasisOrient,Layout> temporary_type;
|
||||
/* Note: this ensures that an external matrix is copied into the proper
|
||||
* temporary; external<> temporaries are not allowed.
|
||||
*/
|
||||
|
||||
/* Standard: */
|
||||
typedef typename array_type::value_type value_type;
|
||||
typedef typename array_type::reference reference;
|
||||
typedef typename array_type::const_reference const_reference;
|
||||
|
||||
typedef matrix_type& expr_reference;
|
||||
typedef const matrix_type& expr_const_reference;
|
||||
|
||||
/* For matching by basis: */
|
||||
typedef BasisOrient basis_orient;
|
||||
|
||||
/* For matching by memory layout: */
|
||||
typedef typename array_type::layout layout;
|
||||
|
||||
/* For matching by storage type if necessary: */
|
||||
typedef typename array_type::memory_tag memory_tag;
|
||||
|
||||
/* For matching by size type if necessary: */
|
||||
typedef typename array_type::size_tag size_tag;
|
||||
|
||||
/* For matching by resizability: */
|
||||
typedef typename array_type::resizing_tag resizing_tag;
|
||||
|
||||
/* For matching by result-type: */
|
||||
typedef cml::et::matrix_result_tag result_tag;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::assignable_tag assignable_tag;
|
||||
|
||||
/* To simplify the matrix transpose operator: */
|
||||
typedef matrix<
|
||||
Element,
|
||||
typename array_type::transposed_type::generator_type,
|
||||
BasisOrient,
|
||||
Layout
|
||||
> transposed_type;
|
||||
|
||||
/* To simplify the matrix row and column operators: */
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::row_array_type::generator_type
|
||||
> row_vector_type;
|
||||
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::col_array_type::generator_type
|
||||
> col_vector_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Set this matrix to zero. */
|
||||
matrix_type& zero() {
|
||||
typedef cml::et::OpAssign<Element,Element> OpT;
|
||||
cml::et::UnrollAssignment<OpT>(*this,Element(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to the identity.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& identity() {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) {
|
||||
(*this)(i,j) = value_type((i == j)?1:0);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its transpose.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& transpose() {
|
||||
/* transpose() returns a temporary: */
|
||||
*this = cml::transpose(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its inverse.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& inverse() {
|
||||
/* inverse() returns a temporary: */
|
||||
*this = inverse(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Pairwise minimum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void minimize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)[i] = std::min((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pairwise maximum of this matrix with another. */
|
||||
template<typename E, class AT, class BO, typename L>
|
||||
void maximize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)[i] = std::max((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set each element to a random number in the range [min,max] */
|
||||
void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) {
|
||||
for(size_t i = 0; i < this->rows(); ++i) {
|
||||
for(size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = cml::random_real(min,max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for fixed-size external matrices.
|
||||
*
|
||||
* The array must be given as a pointer to Element*, not a
|
||||
* multi-dimensional array. The caller owns the pointer, and is
|
||||
* responsible for doing any necessary memory management.
|
||||
*
|
||||
* @param ptr specify the external pointer.
|
||||
* @param rows the number of rows in the C array.
|
||||
* @param cols the number of columns in the C array.
|
||||
*
|
||||
* @throws same as the ArrayType constructor.
|
||||
*/
|
||||
explicit matrix(value_type* const ptr, size_t rows, size_t cols)
|
||||
: array_type(ptr,rows,cols) {}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the matrix size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return element j of basis vector i. */
|
||||
value_type basis_element(size_t i, size_t j) const {
|
||||
return basis_element(i,j,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the given basis element. */
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) {
|
||||
set_basis_element(i,j,s,basis_orient());
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CML_ASSIGN_MAT_22
|
||||
CML_ASSIGN_MAT_33
|
||||
CML_ASSIGN_MAT_44
|
||||
|
||||
/* Define class operators for external matrices. Note: external matrices
|
||||
* cannot be copy-constructed, but they can be assigned to:
|
||||
*/
|
||||
CML_MAT_ASSIGN_FROM_MATTYPE
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign)
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign)
|
||||
|
||||
CML_ACCUMULATED_MATRIX_MULT(const matrix_type&)
|
||||
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&)
|
||||
|
||||
template<class XprT>
|
||||
CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE)
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
value_type basis_element(size_t i, size_t j, row_basis) const {
|
||||
return (*this)(i,j);
|
||||
}
|
||||
|
||||
value_type basis_element(size_t i, size_t j, col_basis) const {
|
||||
return (*this)(j,i);
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) {
|
||||
(*this)(i,j) = s;
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) {
|
||||
(*this)(j,i) = s;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Braces should only be used for testing: */
|
||||
#if defined(CML_ENABLE_MATRIX_BRACES)
|
||||
CML_MATRIX_BRACE_OPERATORS
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
284
Lib/Include/CML/matrix/fixed.h
Normal file
284
Lib/Include/CML/matrix/fixed.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef fixed_matrix_h
|
||||
#define fixed_matrix_h
|
||||
|
||||
#include <cml/core/fixed_2D.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
#include <cml/matrix/class_ops.h>
|
||||
#include <cml/matrix/matrix_unroller.h>
|
||||
|
||||
namespace cml {
|
||||
|
||||
/** Fixed-size, fixed-memory matrix. */
|
||||
template<typename Element, int Rows, int Cols,
|
||||
typename BasisOrient, typename Layout>
|
||||
class matrix<Element,fixed<Rows,Cols>,BasisOrient,Layout>
|
||||
: public fixed_2D<Element,Rows,Cols,Layout>
|
||||
{
|
||||
public:
|
||||
|
||||
/* Shorthand for the generator: */
|
||||
typedef fixed<Rows,Cols> generator_type;
|
||||
|
||||
/* Shorthand for the array type: */
|
||||
typedef fixed_2D<Element,Rows,Cols,Layout> array_type;
|
||||
|
||||
/* Shorthand for the type of this matrix: */
|
||||
typedef matrix<Element,generator_type,BasisOrient,Layout> matrix_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type expr_type;
|
||||
|
||||
/* For integration into the expression template code: */
|
||||
typedef matrix_type temporary_type;
|
||||
|
||||
/* Standard: */
|
||||
typedef typename array_type::value_type value_type;
|
||||
typedef typename array_type::reference reference;
|
||||
typedef typename array_type::const_reference const_reference;
|
||||
|
||||
typedef matrix_type& expr_reference;
|
||||
typedef const matrix_type& expr_const_reference;
|
||||
|
||||
/* For matching by basis: */
|
||||
typedef BasisOrient basis_orient;
|
||||
|
||||
/* For matching by memory layout: */
|
||||
typedef typename array_type::layout layout;
|
||||
|
||||
/* For matching by storage type if necessary: */
|
||||
typedef typename array_type::memory_tag memory_tag;
|
||||
|
||||
/* For matching by size type if necessary: */
|
||||
typedef typename array_type::size_tag size_tag;
|
||||
|
||||
/* For matching by result type: */
|
||||
typedef cml::et::matrix_result_tag result_tag;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::assignable_tag assignable_tag;
|
||||
|
||||
/* To simplify the matrix transpose operator: */
|
||||
typedef matrix<
|
||||
typename cml::remove_const<Element>::type,
|
||||
typename array_type::transposed_type::generator_type,
|
||||
BasisOrient, Layout
|
||||
> transposed_type;
|
||||
|
||||
/* To simplify the matrix row and column operators: */
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::row_array_type::generator_type
|
||||
> row_vector_type;
|
||||
|
||||
typedef vector<
|
||||
Element,
|
||||
typename array_type::col_array_type::generator_type
|
||||
> col_vector_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Set this matrix to zero. */
|
||||
matrix_type& zero() {
|
||||
typedef cml::et::OpAssign<Element,Element> OpT;
|
||||
cml::et::UnrollAssignment<OpT>(*this,Element(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to the identity.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& identity() {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) {
|
||||
(*this)(i,j) = value_type((i == j)?1:0);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its transpose.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& transpose() {
|
||||
/* transpose() returns a temporary: */
|
||||
*this = cml::transpose(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set this matrix to its inverse.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*/
|
||||
matrix_type& inverse() {
|
||||
/* inverse() returns a temporary: */
|
||||
*this = cml::inverse(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* NOTE: minimize() and maximize() no longer supported (Jesse) */
|
||||
|
||||
#if 0
|
||||
/** Pairwise minimum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void minimize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::min((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pairwise maximum of this matrix with another. */
|
||||
template<typename E, class AT, typename L>
|
||||
void maximize(const matrix<E,AT,basis_orient,L>& v) {
|
||||
/* XXX This should probably use ScalarPromote: */
|
||||
for (size_t i = 0; i < this->rows(); ++i) {
|
||||
for (size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = std::max((*this)(i,j),v(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set each element to a random number in the range [min,max] */
|
||||
void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) {
|
||||
for(size_t i = 0; i < this->rows(); ++i) {
|
||||
for(size_t j = 0; j < this->cols(); ++j) {
|
||||
(*this)(i,j) = cml::random_real(min,max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Default constructor.
|
||||
*
|
||||
* @throws same as the ArrayType constructor.
|
||||
* @sa cml::fixed
|
||||
* @sa cml::dynamic
|
||||
*/
|
||||
matrix() {}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the matrix size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return element j of basis vector i. */
|
||||
value_type basis_element(size_t i, size_t j) const {
|
||||
return basis_element(i,j,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the given basis element. */
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) {
|
||||
set_basis_element(i,j,s,basis_orient());
|
||||
}
|
||||
|
||||
/** Set the matrix row from the given vector. */
|
||||
void set_row(size_t i, const row_vector_type& row) {
|
||||
for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j];
|
||||
}
|
||||
|
||||
/** Set the matrix column from the given vector. */
|
||||
void set_col(size_t j, const col_vector_type& col) {
|
||||
for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i];
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Define common class operators: */
|
||||
|
||||
CML_CONSTRUCT_MAT_22
|
||||
CML_CONSTRUCT_MAT_33
|
||||
CML_CONSTRUCT_MAT_44
|
||||
|
||||
CML_MAT_COPY_FROM_FIXED_ARRAY(
|
||||
array_type::array_rows, array_type::array_cols)
|
||||
|
||||
CML_MAT_COPY_FROM_MATTYPE
|
||||
CML_MAT_COPY_FROM_MAT
|
||||
CML_MAT_COPY_FROM_MATXPR
|
||||
|
||||
CML_ASSIGN_MAT_22
|
||||
CML_ASSIGN_MAT_33
|
||||
CML_ASSIGN_MAT_44
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATTYPE
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign)
|
||||
CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign)
|
||||
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign)
|
||||
CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign)
|
||||
|
||||
CML_ACCUMULATED_MATRIX_MULT(const matrix_type&)
|
||||
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&)
|
||||
|
||||
template<class XprT>
|
||||
CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE)
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
value_type basis_element(size_t i, size_t j, row_basis) const {
|
||||
return (*this)(i,j);
|
||||
}
|
||||
|
||||
value_type basis_element(size_t i, size_t j, col_basis) const {
|
||||
return (*this)(j,i);
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) {
|
||||
(*this)(i,j) = s;
|
||||
}
|
||||
|
||||
void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) {
|
||||
(*this)(j,i) = s;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* Braces should only be used for testing: */
|
||||
#if defined(CML_ENABLE_MATRIX_BRACES)
|
||||
CML_MATRIX_BRACE_OPERATORS
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
444
Lib/Include/CML/matrix/inverse.h
Normal file
444
Lib/Include/CML/matrix/inverse.h
Normal file
@@ -0,0 +1,444 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Compute the inverse of a matrix by LU factorization.
|
||||
*/
|
||||
|
||||
#ifndef matrix_inverse_h
|
||||
#define matrix_inverse_h
|
||||
|
||||
#include <vector>
|
||||
#include <cml/matrix/lu.h>
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/* Need to use a functional, since template functions cannot be
|
||||
* specialized. _tag is used to specialize based upon dimension:
|
||||
*/
|
||||
template<typename MatT, int _tag> struct inverse_f;
|
||||
|
||||
/* @todo: Reciprocal optimization for division by determinant.
|
||||
*/
|
||||
|
||||
/* 2x2 inverse. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct inverse_f<MatT,2>
|
||||
{
|
||||
typename MatT::temporary_type operator()(const MatT& M) const
|
||||
{
|
||||
typedef typename MatT::temporary_type temporary_type;
|
||||
typedef typename temporary_type::value_type value_type;
|
||||
|
||||
/* Matrix containing the inverse: */
|
||||
temporary_type Z;
|
||||
cml::et::detail::Resize(Z,2,2);
|
||||
|
||||
/* Compute determinant and inverse: */
|
||||
value_type D = value_type(1) / (M(0,0)*M(1,1) - M(0,1)*M(1,0));
|
||||
Z(0,0) = M(1,1)*D; Z(0,1) = - M(0,1)*D;
|
||||
Z(1,0) = - M(1,0)*D; Z(1,1) = M(0,0)*D;
|
||||
|
||||
return Z;
|
||||
}
|
||||
};
|
||||
|
||||
/* 3x3 inverse. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct inverse_f<MatT,3>
|
||||
{
|
||||
/* [00 01 02]
|
||||
* M = [10 11 12]
|
||||
* [20 21 22]
|
||||
*/
|
||||
typename MatT::temporary_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef typename MatT::value_type value_type;
|
||||
|
||||
/* Compute cofactors for each entry: */
|
||||
value_type m_00 = M(1,1)*M(2,2) - M(1,2)*M(2,1);
|
||||
value_type m_01 = M(1,2)*M(2,0) - M(1,0)*M(2,2);
|
||||
value_type m_02 = M(1,0)*M(2,1) - M(1,1)*M(2,0);
|
||||
|
||||
value_type m_10 = M(0,2)*M(2,1) - M(0,1)*M(2,2);
|
||||
value_type m_11 = M(0,0)*M(2,2) - M(0,2)*M(2,0);
|
||||
value_type m_12 = M(0,1)*M(2,0) - M(0,0)*M(2,1);
|
||||
|
||||
value_type m_20 = M(0,1)*M(1,2) - M(0,2)*M(1,1);
|
||||
value_type m_21 = M(0,2)*M(1,0) - M(0,0)*M(1,2);
|
||||
value_type m_22 = M(0,0)*M(1,1) - M(0,1)*M(1,0);
|
||||
|
||||
/* Compute determinant from the minors: */
|
||||
value_type D =
|
||||
value_type(1) / (M(0,0)*m_00 + M(0,1)*m_01 + M(0,2)*m_02);
|
||||
|
||||
/* Matrix containing the inverse: */
|
||||
typename MatT::temporary_type Z;
|
||||
cml::et::detail::Resize(Z,3,3);
|
||||
|
||||
/* Assign the inverse as (1/D) * (cofactor matrix)^T: */
|
||||
Z(0,0) = m_00*D; Z(0,1) = m_10*D; Z(0,2) = m_20*D;
|
||||
Z(1,0) = m_01*D; Z(1,1) = m_11*D; Z(1,2) = m_21*D;
|
||||
Z(2,0) = m_02*D; Z(2,1) = m_12*D; Z(2,2) = m_22*D;
|
||||
|
||||
return Z;
|
||||
}
|
||||
};
|
||||
|
||||
/* 4x4 inverse. Despite being marked for fixed_size matrices, this can
|
||||
* be used for dynamic-sized ones also:
|
||||
*/
|
||||
template<typename MatT>
|
||||
struct inverse_f<MatT,4>
|
||||
{
|
||||
/* [00 01 02 03]
|
||||
* M = [10 11 12 13]
|
||||
* [20 21 22 23]
|
||||
* [30 31 32 33]
|
||||
*
|
||||
* |11 12 13| |10 12 13|
|
||||
* C00 = |21 22 23| C01 = |20 22 23|
|
||||
* |31 32 33| |30 32 33|
|
||||
*
|
||||
* |10 11 13| |10 11 12|
|
||||
* C02 = |20 21 23| C03 = |20 21 22|
|
||||
* |30 31 33| |30 31 32|
|
||||
*/
|
||||
typename MatT::temporary_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef typename MatT::value_type value_type;
|
||||
|
||||
/* Common cofactors, rows 0,1: */
|
||||
value_type m_22_33_23_32 = M(2,2)*M(3,3) - M(2,3)*M(3,2);
|
||||
value_type m_23_30_20_33 = M(2,3)*M(3,0) - M(2,0)*M(3,3);
|
||||
value_type m_20_31_21_30 = M(2,0)*M(3,1) - M(2,1)*M(3,0);
|
||||
value_type m_21_32_22_31 = M(2,1)*M(3,2) - M(2,2)*M(3,1);
|
||||
value_type m_23_31_21_33 = M(2,3)*M(3,1) - M(2,1)*M(3,3);
|
||||
value_type m_20_32_22_30 = M(2,0)*M(3,2) - M(2,2)*M(3,0);
|
||||
|
||||
/* Compute minors: */
|
||||
value_type d00
|
||||
= M(1,1)*m_22_33_23_32+M(1,2)*m_23_31_21_33+M(1,3)*m_21_32_22_31;
|
||||
|
||||
value_type d01
|
||||
= M(1,0)*m_22_33_23_32+M(1,2)*m_23_30_20_33+M(1,3)*m_20_32_22_30;
|
||||
|
||||
value_type d02
|
||||
= M(1,0)*-m_23_31_21_33+M(1,1)*m_23_30_20_33+M(1,3)*m_20_31_21_30;
|
||||
|
||||
value_type d03
|
||||
= M(1,0)*m_21_32_22_31+M(1,1)*-m_20_32_22_30+M(1,2)*m_20_31_21_30;
|
||||
|
||||
/* Compute minors: */
|
||||
value_type d10
|
||||
= M(0,1)*m_22_33_23_32+M(0,2)*m_23_31_21_33+M(0,3)*m_21_32_22_31;
|
||||
|
||||
value_type d11
|
||||
= M(0,0)*m_22_33_23_32+M(0,2)*m_23_30_20_33+M(0,3)*m_20_32_22_30;
|
||||
|
||||
value_type d12
|
||||
= M(0,0)*-m_23_31_21_33+M(0,1)*m_23_30_20_33+M(0,3)*m_20_31_21_30;
|
||||
|
||||
value_type d13
|
||||
= M(0,0)*m_21_32_22_31+M(0,1)*-m_20_32_22_30+M(0,2)*m_20_31_21_30;
|
||||
|
||||
/* Common cofactors, rows 2,3: */
|
||||
value_type m_02_13_03_12 = M(0,2)*M(1,3) - M(0,3)*M(1,2);
|
||||
value_type m_03_10_00_13 = M(0,3)*M(1,0) - M(0,0)*M(1,3);
|
||||
value_type m_00_11_01_10 = M(0,0)*M(1,1) - M(0,1)*M(1,0);
|
||||
value_type m_01_12_02_11 = M(0,1)*M(1,2) - M(0,2)*M(1,1);
|
||||
value_type m_03_11_01_13 = M(0,3)*M(1,1) - M(0,1)*M(1,3);
|
||||
value_type m_00_12_02_10 = M(0,0)*M(1,2) - M(0,2)*M(1,0);
|
||||
|
||||
/* Compute minors (uses row 3 as the multipliers instead of row 0,
|
||||
* which uses the same signs as row 0):
|
||||
*/
|
||||
value_type d20
|
||||
= M(3,1)*m_02_13_03_12+M(3,2)*m_03_11_01_13+M(3,3)*m_01_12_02_11;
|
||||
|
||||
value_type d21
|
||||
= M(3,0)*m_02_13_03_12+M(3,2)*m_03_10_00_13+M(3,3)*m_00_12_02_10;
|
||||
|
||||
value_type d22
|
||||
= M(3,0)*-m_03_11_01_13+M(3,1)*m_03_10_00_13+M(3,3)*m_00_11_01_10;
|
||||
|
||||
value_type d23
|
||||
= M(3,0)*m_01_12_02_11+M(3,1)*-m_00_12_02_10+M(3,2)*m_00_11_01_10;
|
||||
|
||||
/* Compute minors: */
|
||||
value_type d30
|
||||
= M(2,1)*m_02_13_03_12+M(2,2)*m_03_11_01_13+M(2,3)*m_01_12_02_11;
|
||||
|
||||
value_type d31
|
||||
= M(2,0)*m_02_13_03_12+M(2,2)*m_03_10_00_13+M(2,3)*m_00_12_02_10;
|
||||
|
||||
value_type d32
|
||||
= M(2,0)*-m_03_11_01_13+M(2,1)*m_03_10_00_13+M(2,3)*m_00_11_01_10;
|
||||
|
||||
value_type d33
|
||||
= M(2,0)*m_01_12_02_11+M(2,1)*-m_00_12_02_10+M(2,2)*m_00_11_01_10;
|
||||
|
||||
/* Finally, compute determinant from the minors, and assign the
|
||||
* inverse as (1/D) * (cofactor matrix)^T:
|
||||
*/
|
||||
typename MatT::temporary_type Z;
|
||||
cml::et::detail::Resize(Z,4,4);
|
||||
|
||||
value_type D = value_type(1) /
|
||||
(M(0,0)*d00 - M(0,1)*d01 + M(0,2)*d02 - M(0,3)*d03);
|
||||
Z(0,0) = +d00*D; Z(0,1) = -d10*D; Z(0,2) = +d20*D; Z(0,3) = -d30*D;
|
||||
Z(1,0) = -d01*D; Z(1,1) = +d11*D; Z(1,2) = -d21*D; Z(1,3) = +d31*D;
|
||||
Z(2,0) = +d02*D; Z(2,1) = -d12*D; Z(2,2) = +d22*D; Z(2,3) = -d32*D;
|
||||
Z(3,0) = -d03*D; Z(3,1) = +d13*D; Z(3,2) = -d23*D; Z(3,3) = +d33*D;
|
||||
|
||||
return Z;
|
||||
}
|
||||
};
|
||||
|
||||
/* If more extensive general linear algebra functionality is offered in
|
||||
* future versions it may be useful to make the elementary row and column
|
||||
* operations separate functions. For now they're simply performed in place,
|
||||
* but the commented-out lines of code show where the calls to these functions
|
||||
* should go if and when they become available.
|
||||
*/
|
||||
|
||||
/* @todo: In-place version, and address memory allocation for pivot vector.
|
||||
*/
|
||||
|
||||
/* General NxN inverse by Gauss-Jordan elimination with full pivoting: */
|
||||
template<typename MatT, int _tag>
|
||||
struct inverse_f
|
||||
{
|
||||
typename MatT::temporary_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef typename MatT::value_type value_type;
|
||||
|
||||
/* Size of matrix */
|
||||
size_t N = M.rows();
|
||||
|
||||
/* Matrix containing the inverse: */
|
||||
typename MatT::temporary_type Z;
|
||||
cml::et::detail::Resize(Z,N,N);
|
||||
Z = M;
|
||||
|
||||
/* For tracking pivots */
|
||||
std::vector<size_t> row_index(N);
|
||||
std::vector<size_t> col_index(N);
|
||||
std::vector<size_t> pivoted(N,0);
|
||||
|
||||
/* For each column */
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
|
||||
/* Find the pivot */
|
||||
size_t row = 0, col = 0;
|
||||
value_type max = value_type(0);
|
||||
for (size_t j = 0; j < N; ++j) {
|
||||
if (!pivoted[j]) {
|
||||
for (size_t k = 0; k < N; ++k) {
|
||||
if (!pivoted[k]) {
|
||||
value_type mag = std::fabs(Z(j,k));
|
||||
if (mag > max) {
|
||||
max = mag;
|
||||
row = j;
|
||||
col = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Check max against epsilon here to catch singularity */
|
||||
|
||||
row_index[i] = row;
|
||||
col_index[i] = col;
|
||||
|
||||
/* Swap rows if necessary */
|
||||
if (row != col) {
|
||||
/*Z.row_op_swap(row,col);*/
|
||||
for (size_t j = 0; j < Z.cols(); ++j) {
|
||||
std::swap(Z(row,j),Z(col,j));
|
||||
}
|
||||
}
|
||||
|
||||
/* Process pivot row */
|
||||
pivoted[col] = true;
|
||||
value_type pivot = Z(col,col);
|
||||
Z(col,col) = value_type(1);
|
||||
/*Z.row_op_mult(col,value_type(1)/pivot);*/
|
||||
value_type k = value_type(1)/pivot;
|
||||
for (size_t j = 0; j < Z.cols(); ++j) {
|
||||
Z(col,j) *= k;
|
||||
}
|
||||
|
||||
/* Process other rows */
|
||||
for (size_t j = 0; j < N; ++j) {
|
||||
if (j != col) {
|
||||
value_type mult = -Z(j,col);
|
||||
Z(j,col) = value_type(0);
|
||||
/*Z.row_op_add_mult(col,j,mult);*/
|
||||
for (size_t k = 0; k < Z.cols(); ++k) {
|
||||
Z(j,k) += mult * Z(col,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Swap columns if necessary */
|
||||
for (int i = N-1; i >= 0; --i) {
|
||||
if (row_index[i] != col_index[i]) {
|
||||
/*Z.col_op_swap(row_index[i],col_index[i]);*/
|
||||
for (size_t j = 0; j < Z.rows(); ++j) {
|
||||
std::swap(Z(j,row_index[i]),Z(j,col_index[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return result */
|
||||
return Z;
|
||||
}
|
||||
};
|
||||
|
||||
/* Inversion by LU factorization is turned off for now due to lack of
|
||||
* pivoting in the implementation, but we may switch back to it at some future
|
||||
* time.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
/* General NxN inverse by LU factorization: */
|
||||
template<typename MatT, int _tag>
|
||||
struct inverse_f
|
||||
{
|
||||
typename MatT::temporary_type operator()(const MatT& M) const
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef typename MatT::value_type value_type;
|
||||
|
||||
/* Compute LU factorization: */
|
||||
size_t N = M.rows();
|
||||
typename MatT::temporary_type LU;
|
||||
cml::et::detail::Resize(LU,N,N);
|
||||
LU = lu(M);
|
||||
|
||||
/* Matrix containing the inverse: */
|
||||
typename MatT::temporary_type Z;
|
||||
cml::et::detail::Resize(Z,N,N);
|
||||
|
||||
typename MatT::col_vector_type v, x;
|
||||
cml::et::detail::Resize(v,N);
|
||||
cml::et::detail::Resize(x,N);
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
v[i] = value_type(0);
|
||||
/* XXX Need a fill() function here. */
|
||||
|
||||
/* Use lu_solve to solve M*x = v for x, where v = [0 ... 1 ... 0]^T: */
|
||||
for(size_t i = 0; i < N; ++i) {
|
||||
v[i] = 1.;
|
||||
x = lu_solve(LU,v);
|
||||
|
||||
/* x is column i of the inverse of LU: */
|
||||
for(size_t k = 0; k < N; ++ k) {
|
||||
Z(k,i) = x[k];
|
||||
}
|
||||
v[i] = 0.;
|
||||
}
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Note: force_NxN is for checking general NxN inversion against the special-
|
||||
* case 2x2, 3x3 and 4x4 code. I'm leaving it in for now since we may need to
|
||||
* test the NxN code further if the implementation changes. At some future
|
||||
* time when the implementation is stable, everything related to force_NxN can
|
||||
* be taken out.
|
||||
*/
|
||||
|
||||
/* Note: Commenting the force_NxN stuff out, but leaving the code here in
|
||||
* case we need to do more testing in the future.
|
||||
*/
|
||||
|
||||
/* Generator for the inverse functional for fixed-size matrices: */
|
||||
template<typename MatT> typename MatT::temporary_type
|
||||
inverse(const MatT& M, fixed_size_tag/*, bool force_NxN*/)
|
||||
{
|
||||
/* Require a square matrix: */
|
||||
cml::et::CheckedSquare(M, fixed_size_tag());
|
||||
|
||||
/*
|
||||
if (force_NxN) {
|
||||
return inverse_f<MatT,0>()(M);
|
||||
} else {
|
||||
*/
|
||||
return inverse_f<MatT,MatT::array_rows>()(M);
|
||||
/*
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* Generator for the inverse functional for dynamic-size matrices: */
|
||||
template<typename MatT> typename MatT::temporary_type
|
||||
inverse(const MatT& M, dynamic_size_tag/*, bool force_NxN*/)
|
||||
{
|
||||
/* Require a square matrix: */
|
||||
cml::et::CheckedSquare(M, dynamic_size_tag());
|
||||
|
||||
/*
|
||||
if (force_NxN) {
|
||||
return inverse_f<MatT,0>()(M);
|
||||
} else {
|
||||
*/
|
||||
/* Dispatch based upon the matrix dimension: */
|
||||
switch(M.rows()) {
|
||||
case 2: return inverse_f<MatT,2>()(M); // 2x2
|
||||
case 3: return inverse_f<MatT,3>()(M); // 3x3
|
||||
case 4: return inverse_f<MatT,4>()(M); // 4x4
|
||||
default: return inverse_f<MatT,0>()(M); // > 4x4 (or 1x1)
|
||||
}
|
||||
/*
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Inverse of a matrix. */
|
||||
template<typename E, class AT, typename BO, typename L> inline
|
||||
typename matrix<E,AT,BO,L>::temporary_type
|
||||
inverse(const matrix<E,AT,BO,L>& M/*, bool force_NxN = false*/)
|
||||
{
|
||||
typedef typename matrix<E,AT,BO,L>::size_tag size_tag;
|
||||
return detail::inverse(M,size_tag()/*,force_NxN*/);
|
||||
}
|
||||
|
||||
/** Inverse of a matrix expression. */
|
||||
template<typename XprT> inline
|
||||
typename et::MatrixXpr<XprT>::temporary_type
|
||||
inverse(const et::MatrixXpr<XprT>& e/*, bool force_NxN = false*/)
|
||||
{
|
||||
typedef typename et::MatrixXpr<XprT>::size_tag size_tag;
|
||||
return detail::inverse(e,size_tag()/*,force_NxN*/);
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
176
Lib/Include/CML/matrix/lu.h
Normal file
176
Lib/Include/CML/matrix/lu.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Implements LU decomposition for square matrix expressions.
|
||||
*
|
||||
* @todo The LU implementation does not check for a zero diagonal entry
|
||||
* (implying that the input has no LU factorization).
|
||||
*
|
||||
* @todo Should also have a pivoting implementation.
|
||||
*
|
||||
* @todo need to throw a numeric error if the determinant of the matrix
|
||||
* given to lu(), lu_solve(), or inverse() is 0.
|
||||
*
|
||||
* @internal The implementation is the same for fixed- and dynamic-size
|
||||
* matrices. It can be sped up for small matrices later.
|
||||
*/
|
||||
|
||||
#ifndef lu_h
|
||||
#define lu_h
|
||||
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
#include <cml/matvec/matvec_promotions.h>
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* lu is not provided with a matrix or MatrixExpr argument:
|
||||
*/
|
||||
struct lu_expects_a_matrix_arg_error;
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* lu_inplace is not provided with an assignable matrix argument:
|
||||
*/
|
||||
struct lu_inplace_expects_an_assignable_matrix_arg_error;
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/* Compute the LU decomposition in-place: */
|
||||
template<class MatT> inline
|
||||
void lu_inplace(MatT& A)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<MatT> arg_traits;
|
||||
typedef typename arg_traits::result_tag arg_result;
|
||||
typedef typename arg_traits::assignable_tag arg_assignment;
|
||||
typedef typename arg_traits::size_tag size_tag;
|
||||
typedef typename arg_traits::value_type value_type;
|
||||
|
||||
/* lu_inplace() requires an assignable matrix expression: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(same_type<arg_result, et::matrix_result_tag>::is_true
|
||||
&& same_type<arg_assignment, et::assignable_tag>::is_true),
|
||||
lu_inplace_expects_an_assignable_matrix_arg_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas.
|
||||
*/
|
||||
|
||||
/* Verify that the matrix is square, and get the size: */
|
||||
ssize_t N = (ssize_t) cml::et::CheckedSquare(A, size_tag());
|
||||
|
||||
|
||||
for(ssize_t k = 0; k < N-1; ++k) {
|
||||
/* XXX Should check if A(k,k) = 0! */
|
||||
for(ssize_t i = k+1; i < N; ++i) {
|
||||
value_type n = (A(i,k) /= A(k,k));
|
||||
for(ssize_t j = k+1; j < N; ++ j) {
|
||||
A(i,j) -= n*A(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the LU decomposition, and return a copy of the result: */
|
||||
template<class MatT>
|
||||
inline typename MatT::temporary_type
|
||||
lu_copy(const MatT& M)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<MatT> arg_traits;
|
||||
typedef typename arg_traits::result_tag arg_result;
|
||||
|
||||
/* lu_with_copy() requires a matrix expression: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(same_type<arg_result, et::matrix_result_tag>::is_true),
|
||||
lu_expects_a_matrix_arg_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas.
|
||||
*/
|
||||
|
||||
/* Use the in-place LU function, and return the result: */
|
||||
typename MatT::temporary_type A;
|
||||
cml::et::detail::Resize(A,M.rows(),M.cols());
|
||||
A = M;
|
||||
lu_inplace(A);
|
||||
return A;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** LU factorization for a matrix. */
|
||||
template<typename E, class AT, typename BO, class L>
|
||||
inline typename matrix<E,AT,BO,L>::temporary_type
|
||||
lu(const matrix<E,AT,BO,L>& m)
|
||||
{
|
||||
return detail::lu_copy(m);
|
||||
}
|
||||
|
||||
/** LU factorization for a matrix expression. */
|
||||
template<typename XprT>
|
||||
inline typename et::MatrixXpr<XprT>::temporary_type
|
||||
lu(const et::MatrixXpr<XprT>& e)
|
||||
{
|
||||
return detail::lu_copy(e);
|
||||
}
|
||||
|
||||
/** Solve y = LUx for x.
|
||||
*
|
||||
* This solves Lb = y for b by forward substitution, then Ux = b for x by
|
||||
* backward substitution.
|
||||
*/
|
||||
template<typename MatT, typename VecT> inline
|
||||
typename et::MatVecPromote<MatT,VecT>::temporary_type
|
||||
lu_solve(const MatT& LU, const VecT& b)
|
||||
{
|
||||
/* Shorthand. */
|
||||
typedef et::ExprTraits<MatT> lu_traits;
|
||||
typedef typename et::MatVecPromote<MatT,VecT>::temporary_type vector_type;
|
||||
typedef typename vector_type::value_type value_type;
|
||||
|
||||
/* Verify that the matrix is square, and get the size: */
|
||||
ssize_t N = (ssize_t) cml::et::CheckedSquare(
|
||||
LU, typename lu_traits::size_tag());
|
||||
|
||||
/* Verify that the matrix and vector have compatible sizes: */
|
||||
et::CheckedSize(LU, b, typename vector_type::size_tag());
|
||||
|
||||
/* Solve Ly = b for y by forward substitution. The entries below the
|
||||
* diagonal of LU correspond to L, understood to be below a diagonal of
|
||||
* 1's:
|
||||
*/
|
||||
vector_type y; cml::et::detail::Resize(y,N);
|
||||
for(ssize_t i = 0; i < N; ++i) {
|
||||
y[i] = b[i];
|
||||
for(ssize_t j = 0; j < i; ++j) {
|
||||
y[i] -= LU(i,j)*y[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve Ux = y for x by backward substitution. The entries at and above
|
||||
* the diagonal of LU correspond to U:
|
||||
*/
|
||||
vector_type x; cml::et::detail::Resize(x,N);
|
||||
for(ssize_t i = N-1; i >= 0; --i) {
|
||||
x[i] = y[i];
|
||||
for(ssize_t j = i+1; j < N; ++j) {
|
||||
x[i] -= LU(i,j)*x[j];
|
||||
}
|
||||
x[i] /= LU(i,i);
|
||||
}
|
||||
|
||||
/* Return x: */
|
||||
return x;
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
236
Lib/Include/CML/matrix/matop_macros.h
Normal file
236
Lib/Include/CML/matrix/matop_macros.h
Normal file
@@ -0,0 +1,236 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Defines the various combinations of matrix expressions.
|
||||
*
|
||||
* Create unary and binary operators with macros. The available combinations
|
||||
* are:
|
||||
*
|
||||
* Unary expressions:
|
||||
*
|
||||
* op Matrix -> Matrix
|
||||
* op MatXpr -> Matrix
|
||||
*
|
||||
* Binary expressions:
|
||||
*
|
||||
* Matrix op Matrix -> Matrix
|
||||
* MatXpr op Matrix -> MatXpr
|
||||
* Matrix op MatXpr -> MatXpr
|
||||
* MatXpr op MatXpr -> MatXpr
|
||||
*
|
||||
* Matrix op Scalar -> Matrix
|
||||
* Scalar op Matrix -> Matrix
|
||||
* MatXpr op Scalar -> MatXpr
|
||||
* Scalar op MatXpr -> MatXpr
|
||||
*
|
||||
* All of the generator functions compress the expression tree by hoisting
|
||||
* subexpressions into the containing expression. This has the effect of
|
||||
* forcing only the root node of the expression tree to be a MatrixXpr.
|
||||
* Every other node is a Unary or BinaryMatrixOp.
|
||||
*/
|
||||
#ifndef matop_macros_h
|
||||
#define matop_macros_h
|
||||
|
||||
/** Declare a unary operator taking a matrix operand. */
|
||||
#define CML_MAT_UNIOP(_op_, _OpT_) \
|
||||
template<typename E, class AT, typename BO, typename L> \
|
||||
inline et::MatrixXpr< \
|
||||
et::UnaryMatrixOp< matrix<E,AT,BO,L>, _OpT_ <E> > \
|
||||
> \
|
||||
\
|
||||
_op_ (const matrix<E,AT,BO,L>& arg) \
|
||||
{ \
|
||||
typedef et::UnaryMatrixOp< \
|
||||
matrix<E,AT,BO,L>, _OpT_ <E> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(arg)); \
|
||||
}
|
||||
|
||||
/** Declare a unary operator taking a et::MatrixXpr operand. */
|
||||
#define CML_MATXPR_UNIOP(_op_, _OpT_) \
|
||||
template<class XprT> \
|
||||
inline et::MatrixXpr< \
|
||||
et::UnaryMatrixOp<XprT, _OpT_<typename XprT::value_type> > \
|
||||
> \
|
||||
\
|
||||
_op_ (MATXPR_ARG_TYPE arg) \
|
||||
{ \
|
||||
typedef et::UnaryMatrixOp< \
|
||||
XprT, _OpT_<typename XprT::value_type> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(arg.expression())); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking two matrix operands. */
|
||||
#define CML_MAT_MAT_BINOP(_op_, _OpT_) \
|
||||
template<typename E1, class AT1, typename L1, \
|
||||
typename E2, class AT2, typename L2, typename BO> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
matrix<E1,AT1,BO,L2>, matrix<E2,AT2,BO,L2>, _OpT_<E1,E2> > \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
const matrix<E1,AT1,BO,L1>& left, \
|
||||
const matrix<E2,AT2,BO,L2>& right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
matrix<E1,AT1,BO,L1>, matrix<E2,AT2,BO,L2>, _OpT_<E1,E2> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left,right)); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking a matrix and a et::MatrixXpr. */
|
||||
#define CML_MAT_MATXPR_BINOP(_op_, _OpT_) \
|
||||
template<typename E, class AT, typename BO, typename L, class XprT> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
matrix<E,AT,BO,L>, XprT, _OpT_ <E, typename XprT::value_type> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
const matrix<E,AT,BO,L>& left, \
|
||||
MATXPR_ARG_TYPE right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
matrix<E,AT,BO,L>, XprT, \
|
||||
_OpT_ <E, typename XprT::value_type> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left,right.expression())); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking a et::MatrixXpr and a matrix. */
|
||||
#define CML_MATXPR_MAT_BINOP(_op_, _OpT_) \
|
||||
template<class XprT, typename E, class AT, typename BO, typename L> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
XprT, matrix<E,AT,BO,L>, _OpT_ <typename XprT::value_type, E> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE left, \
|
||||
const matrix<E,AT,BO,L>& right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
XprT, matrix<E,AT,BO,L>, \
|
||||
_OpT_ <typename XprT::value_type, E> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left.expression(),right)); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking two et::MatrixXpr operands. */
|
||||
#define CML_MATXPR_MATXPR_BINOP(_op_, _OpT_) \
|
||||
template<class XprT1, class XprT2> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
XprT1, XprT2, \
|
||||
_OpT_ < \
|
||||
typename XprT1::value_type, \
|
||||
typename XprT2::value_type \
|
||||
> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE_N(1) left, \
|
||||
MATXPR_ARG_TYPE_N(2) right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
XprT1, XprT2, \
|
||||
_OpT_ < \
|
||||
typename XprT1::value_type, \
|
||||
typename XprT2::value_type> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>( \
|
||||
ExprT(left.expression(),right.expression())); \
|
||||
}
|
||||
|
||||
|
||||
/** Declare an operator taking a matrix and a scalar. */
|
||||
#define CML_MAT_SCALAR_BINOP(_op_, _OpT_) \
|
||||
template<typename E, class AT, typename BO, typename L, typename ScalarT>\
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
matrix<E,AT,BO,L>, ScalarT, _OpT_ <E,ScalarT> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
const matrix<E,AT,BO,L>& left, \
|
||||
SCALAR_ARG_TYPE right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
matrix<E,AT,BO,L>, ScalarT, _OpT_ <E,ScalarT > \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left,right)); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking a scalar and a matrix. */
|
||||
#define CML_SCALAR_MAT_BINOP(_op_, _OpT_) \
|
||||
template<typename ScalarT, typename E, class AT, typename BO, typename L>\
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
ScalarT, matrix<E,AT,BO,L>, _OpT_ <ScalarT,E> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
SCALAR_ARG_TYPE left, \
|
||||
const matrix<E,AT,BO,L>& right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
ScalarT, matrix<E,AT,BO,L>, _OpT_<ScalarT,E> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left,right)); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking a et::MatrixXpr and a scalar. */
|
||||
#define CML_MATXPR_SCALAR_BINOP(_op_, _OpT_) \
|
||||
template<class XprT, typename ScalarT> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
XprT, ScalarT, _OpT_ <typename XprT::value_type, ScalarT> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE left, \
|
||||
SCALAR_ARG_TYPE right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
XprT, ScalarT, _OpT_ <typename XprT::value_type,ScalarT> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left.expression(),right)); \
|
||||
}
|
||||
|
||||
/** Declare an operator taking a scalar and a et::MatrixXpr. */
|
||||
#define CML_SCALAR_MATXPR_BINOP(_op_, _OpT_) \
|
||||
template<typename ScalarT, class XprT> \
|
||||
inline et::MatrixXpr< \
|
||||
et::BinaryMatrixOp< \
|
||||
ScalarT, XprT, _OpT_ <ScalarT, typename XprT::value_type> \
|
||||
> \
|
||||
> \
|
||||
\
|
||||
_op_ ( \
|
||||
SCALAR_ARG_TYPE left, \
|
||||
MATXPR_ARG_TYPE right) \
|
||||
{ \
|
||||
typedef et::BinaryMatrixOp< \
|
||||
ScalarT, XprT, _OpT_ <ScalarT, typename XprT::value_type> \
|
||||
> ExprT; \
|
||||
return et::MatrixXpr<ExprT>(ExprT(left,right.expression())); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
245
Lib/Include/CML/matrix/matrix_comparison.h
Normal file
245
Lib/Include/CML/matrix/matrix_comparison.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* @todo The matrix and matrix order operators could probably be combined
|
||||
* into a single templated implementation, since the only thing that is
|
||||
* different is the access method.
|
||||
*/
|
||||
|
||||
#ifndef matrix_comparison_h
|
||||
#define matrix_comparison_h
|
||||
|
||||
#include <cml/core/cml_assert.h>
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/et/scalar_ops.h>
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* matrix_comparison is not provided with matrix or MatrixExpr arguments:
|
||||
*/
|
||||
struct matrix_comparison_expects_matrix_args_error;
|
||||
|
||||
#define CML_MAT_MAT_ORDER(_order_, _op_, _OpT_) \
|
||||
template<typename E1, class AT1, typename L1, \
|
||||
typename E2, class AT2, typename L2, typename BO> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
const matrix<E1,AT1,BO,L1>& left, \
|
||||
const matrix<E2,AT2,BO,L2>& right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, _OpT_ <E1,E2>()); \
|
||||
}
|
||||
|
||||
#define CML_MAT_MATXPR_ORDER(_order_, _op_, _OpT_) \
|
||||
template<typename E, class AT, typename BO, typename L, class XprT> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
const matrix<E,AT,BO,L>& left, \
|
||||
MATXPR_ARG_TYPE right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ <E, typename XprT::value_type>()); \
|
||||
}
|
||||
|
||||
#define CML_MATXPR_MAT_ORDER(_order_, _op_, _OpT_) \
|
||||
template<class XprT, typename E, class AT, typename BO, typename L> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE left, \
|
||||
const matrix<E,AT,BO,L>& right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ <typename XprT::value_type, E>()); \
|
||||
}
|
||||
|
||||
#define CML_MATXPR_MATXPR_ORDER(_order_, _op_, _OpT_) \
|
||||
template<class XprT1, class XprT2> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE_N(1) left, \
|
||||
MATXPR_ARG_TYPE_N(2) right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ < \
|
||||
typename XprT1::value_type, \
|
||||
typename XprT2::value_type>()); \
|
||||
}
|
||||
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/** Matrix strict weak ordering relationship.
|
||||
*
|
||||
* OpT must implement a strict weak order on the matrix element type.
|
||||
* operator< and operator> on integer and floating-point types are
|
||||
* examples.
|
||||
*/
|
||||
template<typename LeftT, typename RightT, typename OpT>
|
||||
inline bool
|
||||
matrix_weak_order(const LeftT& left, const RightT& right, OpT)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<LeftT> left_traits;
|
||||
typedef et::ExprTraits<RightT> right_traits;
|
||||
|
||||
/* matrix_comparison() requires matrix expressions: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(et::MatrixExpressions<LeftT,RightT>::is_true),
|
||||
matrix_comparison_expects_matrix_args_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas:
|
||||
*/
|
||||
|
||||
typedef typename et::MatrixPromote<
|
||||
typename left_traits::result_type,
|
||||
typename right_traits::result_type
|
||||
>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Verify expression size: */
|
||||
matrix_size N = et::CheckedSize(left,right,size_tag());
|
||||
for(ssize_t i = 0; i < N.first; ++ i) {
|
||||
for(ssize_t j = 0; j < N.second; ++ j) {
|
||||
if(OpT().apply(
|
||||
left_traits().get(left,i,j),
|
||||
right_traits().get(right,i,j)
|
||||
))
|
||||
{
|
||||
/* If weak order (a < b) is satisfied, return true: */
|
||||
return true;
|
||||
} else if(OpT().apply(
|
||||
right_traits().get(right,i,j),
|
||||
left_traits().get(left,i,j)
|
||||
))
|
||||
{
|
||||
/* If !(b < a), then return false: */
|
||||
return false;
|
||||
} else {
|
||||
|
||||
/* Have !(a < b) && !(b < a) <=> (a >= b && b >= a)
|
||||
* <=> (a == b). so need to test next element:
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* XXX Can this be unrolled in any reasonable way? */
|
||||
|
||||
/* If we get here, then left == right: */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Matrix total order relationship.
|
||||
*
|
||||
* OpT must implement a total order on the matrix element type. operator<=
|
||||
* and operator>= on integer and floating-point types are examples.
|
||||
*/
|
||||
template<typename LeftT, typename RightT, typename OpT>
|
||||
inline bool
|
||||
matrix_total_order(const LeftT& left, const RightT& right, OpT)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<LeftT> left_traits;
|
||||
typedef et::ExprTraits<RightT> right_traits;
|
||||
|
||||
/* matrix_comparison() requires matrix expressions: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(et::MatrixExpressions<LeftT,RightT>::is_true),
|
||||
matrix_comparison_expects_matrix_args_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas:
|
||||
*/
|
||||
|
||||
typedef typename et::MatrixPromote<
|
||||
typename left_traits::result_type,
|
||||
typename right_traits::result_type
|
||||
>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Verify expression size: */
|
||||
matrix_size N = et::CheckedSize(left,right,size_tag());
|
||||
for(size_t i = 0; i < N.first; ++ i) {
|
||||
for(size_t j = 0; j < N.second; ++ j) {
|
||||
|
||||
/* Test total order: */
|
||||
if(OpT().apply(
|
||||
left_traits().get(left,i,j),
|
||||
right_traits().get(right,i,j)
|
||||
))
|
||||
{
|
||||
/* Automatically true if weak order (a <= b) && !(b <= a)
|
||||
* <=> (a <= b) && (b > a) <=> (a < b) is satisfied:
|
||||
*/
|
||||
if(!OpT().apply(
|
||||
right_traits().get(right,i,j),
|
||||
left_traits().get(left,i,j)
|
||||
))
|
||||
return true;
|
||||
|
||||
/* Otherwise, have equality (a <= b) && (b <= a), so
|
||||
* continue to next element:
|
||||
*/
|
||||
else
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
/* Total order isn't satisfied (a > b), so return false: */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* XXX Can this be unrolled in any reasonable way? */
|
||||
|
||||
/* Total (==) or weak (<) order was satisfied, so return true: */
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* XXX There is a better way to handle these with operator traits... */
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator==, et::OpEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator<, et::OpLess)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator>, et::OpGreater)
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
483
Lib/Include/CML/matrix/matrix_expr.h
Normal file
483
Lib/Include/CML/matrix/matrix_expr.h
Normal file
@@ -0,0 +1,483 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Matrix linear expression classes.
|
||||
*
|
||||
* @todo Dynamic resizing needs to be integrated more naturally into
|
||||
* mul() and matrix transpose():
|
||||
*/
|
||||
|
||||
#ifndef matrix_expr_h
|
||||
#define matrix_expr_h
|
||||
|
||||
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/matrix/matrix_traits.h>
|
||||
#include <cml/matrix/matrix_promotions.h>
|
||||
|
||||
/* XXX Don't know which it should be just yet, since RVO seems to obviate the
|
||||
* need for a reference type. However, copy by value copies the *entire
|
||||
* expression tree rooted at the MatrixXpr<>, so this choice is bound to affect
|
||||
* performance for some compiler or another:
|
||||
*/
|
||||
#define MATXPR_ARG_TYPE const et::MatrixXpr<XprT>&
|
||||
#define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr<XprT##_N_>&
|
||||
|
||||
//#define MATXPR_ARG_TYPE const et::MatrixXpr<XprT>
|
||||
//#define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr<XprT##_N_>
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/** A placeholder for a matrix expression in the expression tree. */
|
||||
template<class ExprT>
|
||||
class MatrixXpr
|
||||
{
|
||||
public:
|
||||
|
||||
typedef MatrixXpr<ExprT> expr_type;
|
||||
|
||||
/* Copy the expression by value into higher-up expressions: */
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename ExprT::value_type value_type;
|
||||
typedef matrix_result_tag result_tag;
|
||||
typedef typename ExprT::size_tag size_tag; // Just inherit size type.
|
||||
|
||||
/* Store the expression traits: */
|
||||
typedef ExprTraits<ExprT> expr_traits;
|
||||
|
||||
/* Get the reference type: */
|
||||
typedef typename expr_traits::const_reference expr_reference;
|
||||
|
||||
/* Get the result type: */
|
||||
typedef typename expr_traits::result_type result_type;
|
||||
|
||||
/* Get the basis type: */
|
||||
typedef typename result_type::basis_orient basis_orient;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::not_assignable_tag assignable_tag;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum (if applicable). */
|
||||
enum { array_rows = ExprT::array_rows, array_cols = ExprT::array_cols };
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return number of rows in the expression (same as subexpression). */
|
||||
size_t rows() const {
|
||||
return expr_traits().rows(m_expr);
|
||||
}
|
||||
|
||||
/** Return number of columns in the expression (same as subexpression). */
|
||||
size_t cols() const {
|
||||
return expr_traits().cols(m_expr);
|
||||
}
|
||||
|
||||
/** Return reference to contained expression. */
|
||||
expr_reference expression() const { return m_expr; }
|
||||
|
||||
/** Compute value at index i,j of the result matrix. */
|
||||
value_type operator()(size_t i, size_t j) const {
|
||||
return expr_traits().get(m_expr,i,j);
|
||||
}
|
||||
|
||||
/** Return element j of basis vector i. */
|
||||
value_type basis_element(size_t i, size_t j) const {
|
||||
return basis_element(i,j,basis_orient());
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the subexpression to store. */
|
||||
explicit MatrixXpr(expr_reference expr) : m_expr(expr) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
MatrixXpr(const expr_type& e) : m_expr(e.m_expr) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
value_type basis_element(size_t i, size_t j, row_basis) const {
|
||||
return (*this)(i,j);
|
||||
}
|
||||
|
||||
value_type basis_element(size_t i, size_t j, col_basis) const {
|
||||
return (*this)(j,i);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
expr_reference m_expr;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits for MatrixXpr<>. */
|
||||
template<class ExprT>
|
||||
struct ExprTraits< MatrixXpr<ExprT> >
|
||||
{
|
||||
typedef MatrixXpr<ExprT> expr_type;
|
||||
typedef ExprT arg_type;
|
||||
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef typename expr_type::assignable_tag assignable_tag;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& e, size_t i, size_t j) const {
|
||||
return e(i,j);
|
||||
}
|
||||
|
||||
|
||||
matrix_size size(const expr_type& e) const { return e.size(); }
|
||||
size_t rows(const expr_type& e) const { return e.rows(); }
|
||||
size_t cols(const expr_type& e) const { return e.cols(); }
|
||||
};
|
||||
|
||||
|
||||
/** A unary matrix expression operating on matrix elements as a list.
|
||||
*
|
||||
* The operator must take exactly one argument.
|
||||
*/
|
||||
template<class ExprT, class OpT>
|
||||
class UnaryMatrixOp
|
||||
{
|
||||
public:
|
||||
|
||||
typedef UnaryMatrixOp<ExprT,OpT> expr_type;
|
||||
|
||||
/* Record ary-ness of the expression: */
|
||||
typedef unary_expression expr_ary;
|
||||
|
||||
/* Copy the expression by value into higher-up expressions: */
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename OpT::value_type value_type;
|
||||
typedef matrix_result_tag result_tag;
|
||||
typedef typename ExprT::size_tag size_tag;
|
||||
|
||||
/* Store the expression traits for the subexpression: */
|
||||
typedef ExprTraits<ExprT> expr_traits;
|
||||
|
||||
/* Reference type for the subexpression: */
|
||||
typedef typename expr_traits::const_reference expr_reference;
|
||||
|
||||
/* Get the result type: */
|
||||
typedef typename expr_traits::result_type result_type;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::not_assignable_tag assignable_tag;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum (if applicable). */
|
||||
enum { array_rows = ExprT::array_rows, array_cols = ExprT::array_cols };
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return number of rows in the expression (same as argument). */
|
||||
size_t rows() const {
|
||||
return expr_traits().rows(m_expr);
|
||||
}
|
||||
|
||||
/** Return number of columns in the expression (same as argument). */
|
||||
size_t cols() const {
|
||||
return expr_traits().cols(m_expr);
|
||||
}
|
||||
|
||||
/** Compute value at index i,j of the result matrix. */
|
||||
value_type operator()(size_t i, size_t j) const {
|
||||
|
||||
/* This uses the expression traits to figure out how to access the
|
||||
* i,j'th element of the subexpression:
|
||||
*/
|
||||
return OpT().apply(expr_traits().get(m_expr,i,j));
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the subexpression. */
|
||||
explicit UnaryMatrixOp(expr_reference expr) : m_expr(expr) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
UnaryMatrixOp(const expr_type& e) : m_expr(e.m_expr) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
expr_reference m_expr;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits for UnaryMatrixOp<>. */
|
||||
template<class ExprT, class OpT>
|
||||
struct ExprTraits< UnaryMatrixOp<ExprT,OpT> >
|
||||
{
|
||||
typedef UnaryMatrixOp<ExprT,OpT> expr_type;
|
||||
typedef ExprT arg_type;
|
||||
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef typename expr_type::assignable_tag assignable_tag;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& e, size_t i, size_t j) const {
|
||||
return e(i,j);
|
||||
}
|
||||
|
||||
matrix_size size(const expr_type& e) const { return e.size(); }
|
||||
size_t rows(const expr_type& e) const { return e.rows(); }
|
||||
size_t cols(const expr_type& e) const { return e.cols(); }
|
||||
};
|
||||
|
||||
|
||||
/** A binary matrix expression. */
|
||||
template<class LeftT, class RightT, class OpT>
|
||||
class BinaryMatrixOp
|
||||
{
|
||||
public:
|
||||
|
||||
typedef BinaryMatrixOp<LeftT,RightT,OpT> expr_type;
|
||||
|
||||
/* Copy the UnaryMatrixOp expression by value into parent
|
||||
* expression tree nodes:
|
||||
*/
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename OpT::value_type value_type;
|
||||
typedef matrix_result_tag result_tag;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::not_assignable_tag assignable_tag;
|
||||
|
||||
/* Record the expression traits for the two subexpressions: */
|
||||
typedef ExprTraits<LeftT> left_traits;
|
||||
typedef ExprTraits<RightT> right_traits;
|
||||
|
||||
/* Reference types for the two subexpressions: */
|
||||
typedef typename left_traits::const_reference left_reference;
|
||||
typedef typename right_traits::const_reference right_reference;
|
||||
|
||||
/* Figure out the expression's resulting (matrix) type: */
|
||||
typedef typename left_traits::result_type left_result;
|
||||
typedef typename right_traits::result_type right_result;
|
||||
typedef typename MatrixPromote<left_result,right_result>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
/* Define a size checker: */
|
||||
typedef GetCheckedSize<LeftT,RightT,size_tag> checked_size;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum (if applicable).
|
||||
*
|
||||
* CheckExprSizes<> ensures that this works as expected.
|
||||
*/
|
||||
enum {
|
||||
array_rows = result_type::array_rows,
|
||||
array_cols = result_type::array_cols
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return CheckedSize(m_left,m_right,size_tag());
|
||||
}
|
||||
|
||||
/** Return number of rows in the result.
|
||||
*
|
||||
* @note Because this calls size() internally, calling both rows()
|
||||
* and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size
|
||||
* checking code to be executed twice.
|
||||
*/
|
||||
size_t rows() const {
|
||||
#if defined(CML_CHECK_MATRIX_EXPR_SIZES)
|
||||
return this->size().first;
|
||||
#else
|
||||
return left_traits().rows(m_left);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return number of cols in the result.
|
||||
*
|
||||
* @note Because this calls size() internally, calling both rows()
|
||||
* and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size
|
||||
* checking code to be executed twice.
|
||||
*/
|
||||
size_t cols() const {
|
||||
#if defined(CML_CHECK_MATRIX_EXPR_SIZES)
|
||||
return this->size().second;
|
||||
#else
|
||||
return right_traits().cols(m_right);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Compute value at index i,j of the result matrix. */
|
||||
value_type operator()(size_t i, size_t j) const {
|
||||
|
||||
/* This uses the expression traits to figure out how to access the
|
||||
* i'th index of the two subexpressions:
|
||||
*/
|
||||
return OpT().apply(
|
||||
left_traits().get(m_left,i,j),
|
||||
right_traits().get(m_right,i,j));
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the two subexpressions.
|
||||
*
|
||||
* @throws std::invalid_argument if the subexpression sizes don't
|
||||
* match.
|
||||
*/
|
||||
explicit BinaryMatrixOp(left_reference left, right_reference right)
|
||||
: m_left(left), m_right(right) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
BinaryMatrixOp(const expr_type& e)
|
||||
: m_left(e.m_left), m_right(e.m_right) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
left_reference m_left;
|
||||
right_reference m_right;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* This ensures that a compile-time size check is executed: */
|
||||
typename checked_size::check_type _dummy;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits for BinaryMatrixOp<>. */
|
||||
template<class LeftT, class RightT, class OpT>
|
||||
struct ExprTraits< BinaryMatrixOp<LeftT,RightT,OpT> >
|
||||
{
|
||||
typedef BinaryMatrixOp<LeftT,RightT,OpT> expr_type;
|
||||
typedef LeftT left_type;
|
||||
typedef RightT right_type;
|
||||
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef typename expr_type::assignable_tag assignable_tag;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& e, size_t i, size_t j) const {
|
||||
return e(i,j);
|
||||
}
|
||||
|
||||
matrix_size size(const expr_type& e) const { return e.size(); }
|
||||
size_t rows(const expr_type& e) const { return e.rows(); }
|
||||
size_t cols(const expr_type& e) const { return e.cols(); }
|
||||
};
|
||||
|
||||
/* Helper struct to verify that both arguments are matrix expressions: */
|
||||
template<typename LeftTraits, typename RightTraits>
|
||||
struct MatrixExpressions
|
||||
{
|
||||
/* Require that both arguments are matrix expressions: */
|
||||
typedef typename LeftTraits::result_tag left_result;
|
||||
typedef typename RightTraits::result_tag right_result;
|
||||
enum { is_true = (same_type<left_result,et::matrix_result_tag>::is_true
|
||||
&& same_type<right_result,et::matrix_result_tag>::is_true) };
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* XXX These are temporary helpers until dynamic resizing is integrated more
|
||||
* naturally into mul() and matrix transpose():
|
||||
*/
|
||||
template<typename MatT, typename MT> inline
|
||||
void Resize(MatT&, size_t, size_t, fixed_size_tag, MT) {}
|
||||
|
||||
template<typename MatT> inline
|
||||
void Resize(MatT& m,
|
||||
size_t R, size_t C, dynamic_size_tag, dynamic_memory_tag)
|
||||
{
|
||||
m.resize(R,C);
|
||||
}
|
||||
|
||||
template<typename MatT> inline
|
||||
void Resize(MatT& m, size_t R, size_t C) {
|
||||
Resize(m, R, C, typename MatT::size_tag(), typename MatT::memory_tag());
|
||||
}
|
||||
|
||||
template<typename MatT> inline
|
||||
void Resize(MatT& m, matrix_size N) {
|
||||
Resize(m, N.first, N.second,
|
||||
typename MatT::size_tag(), typename MatT::memory_tag());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
43
Lib/Include/CML/matrix/matrix_functions.h
Normal file
43
Lib/Include/CML/matrix/matrix_functions.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef matrix_functions_h
|
||||
#define matrix_functions_h
|
||||
|
||||
namespace cml {
|
||||
|
||||
/** Set the given matrix to the identity matrix.
|
||||
*
|
||||
* This only makes sense for a square matrix, but no error will be
|
||||
* signaled if the matrix is not square.
|
||||
*
|
||||
* @todo This should return a MatrixXpr to allow loop unrolling, as should
|
||||
* the class method.
|
||||
*/
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
inline matrix<E,AT,BO,L>
|
||||
identity(const matrix<E,AT,BO,L>& m)
|
||||
{
|
||||
typename matrix<E,AT,BO,L>::temporary_type result;
|
||||
|
||||
/* This is a no-op for fixed-size matrices: */
|
||||
cml::et::detail::Resize(result, m.size());
|
||||
result.identity();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
205
Lib/Include/CML/matrix/matrix_mul.h
Normal file
205
Lib/Include/CML/matrix/matrix_mul.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Multiply two matrices.
|
||||
*
|
||||
* @todo Does it make sense to put mat-mat multiplication as a node into the
|
||||
* expression tree?
|
||||
*
|
||||
* @internal This does not need to return an expression type, since the
|
||||
* temporary generation for the matrix result is handled automatically by the
|
||||
* compiler. i.e. when used in an expression, the result is automatically
|
||||
* included in the expression tree as a temporary by the compiler.
|
||||
*/
|
||||
|
||||
#ifndef matrix_mul_h
|
||||
#define matrix_mul_h
|
||||
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* mul is not provided with matrix or MatrixExpr arguments:
|
||||
*/
|
||||
struct mul_expects_matrix_args_error;
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* fixed-size arguments to mul() have the wrong size:
|
||||
*/
|
||||
struct mul_expressions_have_wrong_size_error;
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/** Verify the sizes of the argument matrices for matrix multiplication.
|
||||
*
|
||||
* @returns a matrix_size containing the size of the resulting matrix.
|
||||
*/
|
||||
template<typename LeftT, typename RightT> inline matrix_size
|
||||
MatMulCheckedSize(const LeftT&, const RightT&, fixed_size_tag)
|
||||
{
|
||||
CML_STATIC_REQUIRE_M(
|
||||
((size_t)LeftT::array_cols == (size_t)RightT::array_rows),
|
||||
mul_expressions_have_wrong_size_error);
|
||||
return matrix_size(LeftT::array_rows,RightT::array_cols);
|
||||
}
|
||||
|
||||
/** Verify the sizes of the argument matrices for matrix multiplication.
|
||||
*
|
||||
* @returns a matrix_size containing the size of the resulting matrix.
|
||||
*/
|
||||
template<typename LeftT, typename RightT> inline matrix_size
|
||||
MatMulCheckedSize(const LeftT& left, const RightT& right, dynamic_size_tag)
|
||||
{
|
||||
matrix_size left_N = left.size(), right_N = right.size();
|
||||
et::GetCheckedSize<LeftT,RightT,dynamic_size_tag>()
|
||||
.equal_or_fail(left_N.second, right_N.first); /* cols,rows */
|
||||
return matrix_size(left_N.first, right_N.second); /* rows,cols */
|
||||
}
|
||||
|
||||
|
||||
/** Matrix multiplication.
|
||||
*
|
||||
* Computes C = A x B (O(N^3), non-blocked algorithm).
|
||||
*/
|
||||
template<class LeftT, class RightT>
|
||||
inline typename et::MatrixPromote<
|
||||
typename et::ExprTraits<LeftT>::result_type,
|
||||
typename et::ExprTraits<RightT>::result_type
|
||||
>::temporary_type
|
||||
mul(const LeftT& left, const RightT& right)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<LeftT> left_traits;
|
||||
typedef et::ExprTraits<RightT> right_traits;
|
||||
typedef typename left_traits::result_type left_result;
|
||||
typedef typename right_traits::result_type right_result;
|
||||
|
||||
/* First, require matrix expressions: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(et::MatrixExpressions<LeftT,RightT>::is_true),
|
||||
mul_expects_matrix_args_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas.
|
||||
*/
|
||||
|
||||
/* Deduce size type to ensure that a run-time check is performed if
|
||||
* necessary:
|
||||
*/
|
||||
typedef typename et::MatrixPromote<
|
||||
typename left_traits::result_type,
|
||||
typename right_traits::result_type
|
||||
>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Require that left has the same number of columns as right has rows.
|
||||
* This automatically checks fixed-size matrices at compile time, and
|
||||
* throws at run-time if the sizes don't match:
|
||||
*/
|
||||
matrix_size N = detail::MatMulCheckedSize(left, right, size_tag());
|
||||
|
||||
/* Create an array with the right size (resize() is a no-op for
|
||||
* fixed-size matrices):
|
||||
*/
|
||||
result_type C;
|
||||
cml::et::detail::Resize(C, N);
|
||||
|
||||
/* XXX Specialize this for fixed-size matrices: */
|
||||
typedef typename result_type::value_type value_type;
|
||||
for(size_t i = 0; i < left.rows(); ++i) { /* rows */
|
||||
for(size_t j = 0; j < right.cols(); ++j) { /* cols */
|
||||
value_type sum(left(i,0)*right(0,j));
|
||||
for(size_t k = 1; k < right.rows(); ++k) {
|
||||
sum += (left(i,k)*right(k,j));
|
||||
}
|
||||
C(i,j) = sum;
|
||||
}
|
||||
}
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/** operator*() for two matrices. */
|
||||
template<typename E1, class AT1, typename L1,
|
||||
typename E2, class AT2, typename L2,
|
||||
typename BO>
|
||||
inline typename et::MatrixPromote<
|
||||
matrix<E1,AT1,BO,L1>, matrix<E2,AT2,BO,L2>
|
||||
>::temporary_type
|
||||
operator*(const matrix<E1,AT1,BO,L1>& left,
|
||||
const matrix<E2,AT2,BO,L2>& right)
|
||||
{
|
||||
return detail::mul(left,right);
|
||||
}
|
||||
|
||||
/** operator*() for a matrix and a MatrixXpr. */
|
||||
template<typename E, class AT, typename BO, typename L, typename XprT>
|
||||
inline typename et::MatrixPromote<
|
||||
matrix<E,AT,BO,L>, typename XprT::result_type
|
||||
>::temporary_type
|
||||
operator*(const matrix<E,AT,BO,L>& left,
|
||||
const et::MatrixXpr<XprT>& right)
|
||||
{
|
||||
/* Generate a temporary, and compute the right-hand expression: */
|
||||
typedef typename et::MatrixXpr<XprT>::temporary_type expr_tmp;
|
||||
expr_tmp tmp;
|
||||
cml::et::detail::Resize(tmp,right.rows(),right.cols());
|
||||
tmp = right;
|
||||
|
||||
return detail::mul(left,tmp);
|
||||
}
|
||||
|
||||
/** operator*() for a MatrixXpr and a matrix. */
|
||||
template<typename XprT, typename E, class AT, typename BO, typename L>
|
||||
inline typename et::MatrixPromote<
|
||||
typename XprT::result_type , matrix<E,AT,BO,L>
|
||||
>::temporary_type
|
||||
operator*(const et::MatrixXpr<XprT>& left,
|
||||
const matrix<E,AT,BO,L>& right)
|
||||
{
|
||||
/* Generate a temporary, and compute the left-hand expression: */
|
||||
typedef typename et::MatrixXpr<XprT>::temporary_type expr_tmp;
|
||||
expr_tmp tmp;
|
||||
cml::et::detail::Resize(tmp,left.rows(),left.cols());
|
||||
tmp = left;
|
||||
|
||||
return detail::mul(tmp,right);
|
||||
}
|
||||
|
||||
/** operator*() for two MatrixXpr's. */
|
||||
template<typename XprT1, typename XprT2>
|
||||
inline typename et::MatrixPromote<
|
||||
typename XprT1::result_type, typename XprT2::result_type
|
||||
>::temporary_type
|
||||
operator*(const et::MatrixXpr<XprT1>& left,
|
||||
const et::MatrixXpr<XprT2>& right)
|
||||
{
|
||||
/* Generate temporaries and compute expressions: */
|
||||
typedef typename et::MatrixXpr<XprT1>::temporary_type left_tmp;
|
||||
left_tmp ltmp;
|
||||
cml::et::detail::Resize(ltmp,left.rows(),left.cols());
|
||||
ltmp = left;
|
||||
|
||||
typedef typename et::MatrixXpr<XprT2>::temporary_type right_tmp;
|
||||
right_tmp rtmp;
|
||||
cml::et::detail::Resize(rtmp,right.rows(),right.cols());
|
||||
rtmp = right;
|
||||
|
||||
return detail::mul(ltmp,rtmp);
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
50
Lib/Include/CML/matrix/matrix_ops.h
Normal file
50
Lib/Include/CML/matrix/matrix_ops.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Defines matrix operators.
|
||||
*/
|
||||
#ifndef matrix_ops_h
|
||||
#define matrix_ops_h
|
||||
|
||||
#include <cml/et/scalar_ops.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
#include <cml/matrix/matop_macros.h>
|
||||
|
||||
namespace cml {
|
||||
|
||||
CML_MAT_UNIOP( operator+, et::OpPos)
|
||||
CML_MATXPR_UNIOP( operator+, et::OpPos)
|
||||
|
||||
CML_MAT_UNIOP( operator-, et::OpNeg)
|
||||
CML_MATXPR_UNIOP( operator-, et::OpNeg)
|
||||
|
||||
CML_MAT_MAT_BINOP( operator+, et::OpAdd)
|
||||
CML_MATXPR_MAT_BINOP( operator+, et::OpAdd)
|
||||
CML_MAT_MATXPR_BINOP( operator+, et::OpAdd)
|
||||
CML_MATXPR_MATXPR_BINOP( operator+, et::OpAdd)
|
||||
|
||||
CML_MAT_MAT_BINOP( operator-, et::OpSub)
|
||||
CML_MATXPR_MAT_BINOP( operator-, et::OpSub)
|
||||
CML_MAT_MATXPR_BINOP( operator-, et::OpSub)
|
||||
CML_MATXPR_MATXPR_BINOP( operator-, et::OpSub)
|
||||
|
||||
CML_MAT_SCALAR_BINOP( operator*, et::OpMul)
|
||||
CML_SCALAR_MAT_BINOP( operator*, et::OpMul)
|
||||
CML_MATXPR_SCALAR_BINOP( operator*, et::OpMul)
|
||||
CML_SCALAR_MATXPR_BINOP( operator*, et::OpMul)
|
||||
|
||||
CML_MAT_SCALAR_BINOP( operator/, et::OpDiv)
|
||||
CML_MATXPR_SCALAR_BINOP( operator/, et::OpDiv)
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
59
Lib/Include/CML/matrix/matrix_print.h
Normal file
59
Lib/Include/CML/matrix/matrix_print.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef matrix_print_h
|
||||
#define matrix_print_h
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace cml {
|
||||
|
||||
/** Output a matrix to a std::ostream. */
|
||||
template<typename E, class AT, typename BO, class L> inline std::ostream&
|
||||
operator<<(std::ostream& os, const matrix<E,AT,BO,L>& m)
|
||||
{
|
||||
for(size_t i = 0; i < m.rows(); ++i) {
|
||||
os << "[";
|
||||
for(size_t j = 0; j < m.cols(); ++j) {
|
||||
os << " " << m(i,j);
|
||||
}
|
||||
os << " ]";
|
||||
if (i != m.rows()-1) {
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/** Output a matrix expression to a std::ostream. */
|
||||
template< class XprT > inline std::ostream&
|
||||
operator<<(std::ostream& os, const et::MatrixXpr<XprT>& m)
|
||||
{
|
||||
for(size_t i = 0; i < m.rows(); ++i) {
|
||||
os << "[";
|
||||
for(size_t j = 0; j < m.cols(); ++j) {
|
||||
os << " " << m(i,j);
|
||||
}
|
||||
os << " ]";
|
||||
if (i != m.rows()-1) {
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
187
Lib/Include/CML/matrix/matrix_promotions.h
Normal file
187
Lib/Include/CML/matrix/matrix_promotions.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* Defines promotions for matrices used in matrix/matrix or matrix/scalar
|
||||
* expressions.
|
||||
*
|
||||
* @sa UnaryMat4_TOp
|
||||
* @sa BinaryMat4_TOp
|
||||
*/
|
||||
|
||||
#ifndef matrix_promotions_h
|
||||
#define matrix_promotions_h
|
||||
|
||||
#include <cml/core/cml_meta.h>
|
||||
#include <cml/et/scalar_promotions.h>
|
||||
#include <cml/et/array_promotions.h>
|
||||
#include <cml/fixed.h>
|
||||
#include <cml/dynamic.h>
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* either argument to OuterPromote has the wrong orientation.
|
||||
*/
|
||||
struct outer_promote_expects_properly_oriented_args_error;
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/** Promote two types to a matrixt type. */
|
||||
template<typename LeftT, typename RightT> struct MatrixPromote
|
||||
{
|
||||
/* Default matrix type promotion template. */
|
||||
template<typename M1, typename M2> struct MatrixPromoteHelper;
|
||||
|
||||
/** Type promotion for two matrix types.
|
||||
*
|
||||
* @note This always uses the basis orientation of the left-hand matrix.
|
||||
* @bug This always uses the basis orientation of the left-hand matrix,
|
||||
* which is not always correct.
|
||||
*/
|
||||
template<typename E1, class AT1, typename L1, typename BO1,
|
||||
typename E2, class AT2, typename L2, typename BO2>
|
||||
struct MatrixPromoteHelper<
|
||||
cml::matrix<E1,AT1,BO1,L1>, cml::matrix<E2,AT2,BO2,L2>
|
||||
>
|
||||
{
|
||||
/* Promote the arrays: */
|
||||
typedef typename ArrayPromote<
|
||||
typename cml::matrix<E1,AT1,BO1,L1>::array_type,
|
||||
typename cml::matrix<E2,AT2,BO2,L2>::array_type
|
||||
>::type promoted_array;
|
||||
|
||||
/* The deduced matrix result type: */
|
||||
typedef cml::matrix<
|
||||
typename promoted_array::value_type,
|
||||
typename promoted_array::generator_type,
|
||||
BO1,
|
||||
typename promoted_array::layout
|
||||
> type;
|
||||
|
||||
/* The deduced temporary type: */
|
||||
typedef typename type::temporary_type temporary_type;
|
||||
};
|
||||
|
||||
/** Type promotion for a matrix and a scalar. */
|
||||
template<typename E, class AT, typename BO, typename L, typename S>
|
||||
struct MatrixPromoteHelper<cml::matrix<E,AT,BO,L>, S>
|
||||
{
|
||||
/* The deduced matrix result type (the array type is the same): */
|
||||
typedef cml::matrix<typename ScalarPromote<E,S>::type, AT, BO, L> type;
|
||||
|
||||
/* The deduced temporary type: */
|
||||
typedef typename type::temporary_type temporary_type;
|
||||
};
|
||||
|
||||
/** Type promotion for a scalar and a matrix. */
|
||||
template<typename S, typename E, class AT, typename BO, typename L>
|
||||
struct MatrixPromoteHelper<S, cml::matrix<E,AT,BO,L> >
|
||||
{
|
||||
/* The deduced matrix result type (the array type is the same): */
|
||||
typedef cml::matrix<typename ScalarPromote<S,E>::type, AT, BO, L> type;
|
||||
|
||||
/* The deduced temporary type: */
|
||||
typedef typename type::temporary_type temporary_type;
|
||||
};
|
||||
|
||||
/** Type promotion for outer product. */
|
||||
template<typename E1, class AT1, typename E2, class AT2>
|
||||
struct MatrixPromoteHelper< cml::vector<E1,AT1>, cml::vector<E2,AT2> >
|
||||
{
|
||||
typedef cml::vector<E1,AT1> left_type;
|
||||
typedef cml::vector<E2,AT2> right_type;
|
||||
typedef CML_DEFAULT_BASIS_ORIENTATION basis_orient;
|
||||
|
||||
/* Get matrix size: */
|
||||
enum {
|
||||
array_rows = left_type::array_size,
|
||||
array_cols = right_type::array_size
|
||||
};
|
||||
|
||||
/* Deduce the corresponding matrix types for the vectors: */
|
||||
typedef CML_DEFAULT_ARRAY_LAYOUT layout;
|
||||
typedef typename select_if<
|
||||
array_rows == -1, dynamic<>, fixed<array_rows,1>
|
||||
>::result left_storage;
|
||||
typedef cml::matrix<E1,left_storage,basis_orient,layout> left_matrix;
|
||||
|
||||
typedef typename select_if<
|
||||
array_cols == -1, dynamic<>, fixed<1,array_cols>
|
||||
>::result right_storage;
|
||||
typedef cml::matrix<E2,right_storage,basis_orient,layout> right_matrix;
|
||||
|
||||
/* Finally, promote the matrix types to get the result: */
|
||||
typedef typename et::MatrixPromote<left_matrix,right_matrix>::type type;
|
||||
typedef typename type::temporary_type temporary_type;
|
||||
};
|
||||
|
||||
/** Remove const and & from the to-be-promoted types. */
|
||||
typedef typename remove_const<
|
||||
typename remove_reference<LeftT>::type>::type LeftBaseT;
|
||||
typedef typename remove_const<
|
||||
typename remove_reference<RightT>::type>::type RightBaseT;
|
||||
|
||||
typedef typename MatrixPromoteHelper<LeftBaseT,RightBaseT>::type type;
|
||||
typedef typename type::temporary_type temporary_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* NOTE: MatrixPromote* are somewhat ad hoc, and were added to
|
||||
* simplify the code for matrix slerp/squad/etc.
|
||||
*/
|
||||
|
||||
/** Type promotion for two matrix types. */
|
||||
template < class Mat1_T, class Mat2_T >
|
||||
struct MatrixPromote2
|
||||
{
|
||||
typedef typename MatrixPromote<
|
||||
typename Mat1_T::temporary_type, typename Mat2_T::temporary_type
|
||||
>::temporary_type temporary_type;
|
||||
typedef typename temporary_type::value_type value_type;
|
||||
};
|
||||
|
||||
/** Type promotion for three matrix types. */
|
||||
template < class Mat1_T, class Mat2_T, class Mat3_T >
|
||||
struct MatrixPromote3
|
||||
{
|
||||
typedef typename MatrixPromote<
|
||||
typename Mat1_T::temporary_type,
|
||||
typename MatrixPromote<
|
||||
typename Mat2_T::temporary_type,
|
||||
typename Mat3_T::temporary_type
|
||||
>::temporary_type
|
||||
>::temporary_type temporary_type;
|
||||
typedef typename temporary_type::value_type value_type;
|
||||
};
|
||||
|
||||
/** Type promotion for four matrix types. */
|
||||
template < class Mat1_T, class Mat2_T, class Mat3_T, class Mat4_T >
|
||||
struct MatrixPromote4
|
||||
{
|
||||
typedef typename MatrixPromote<
|
||||
typename Mat1_T::temporary_type,
|
||||
typename MatrixPromote<
|
||||
typename Mat2_T::temporary_type,
|
||||
typename MatrixPromote<
|
||||
typename Mat3_T::temporary_type,
|
||||
typename Mat4_T::temporary_type
|
||||
>::temporary_type
|
||||
>::temporary_type
|
||||
>::temporary_type temporary_type;
|
||||
typedef typename temporary_type::value_type value_type;
|
||||
};
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
273
Lib/Include/CML/matrix/matrix_rowcol.h
Normal file
273
Lib/Include/CML/matrix/matrix_rowcol.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief Expressions to extract a row or column of a matrix.
|
||||
*/
|
||||
|
||||
#ifndef matrix_rowcol_h
|
||||
#define matrix_rowcol_h
|
||||
|
||||
#include <cml/vector/vector_expr.h>
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
template<class ExprT>
|
||||
class MatrixRowOp
|
||||
{
|
||||
public:
|
||||
|
||||
typedef MatrixRowOp<ExprT> expr_type;
|
||||
|
||||
/* Record ary-ness of the expression: */
|
||||
typedef unary_expression expr_ary;
|
||||
|
||||
/* Copy the expression by value into higher-up expressions: */
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename ExprT::value_type value_type;
|
||||
typedef vector_result_tag result_tag;
|
||||
typedef typename ExprT::size_tag size_tag;
|
||||
|
||||
/* Store the expression traits: */
|
||||
typedef ExprTraits<ExprT> expr_traits;
|
||||
|
||||
/* Get the reference type: */
|
||||
typedef typename expr_traits::const_reference expr_reference;
|
||||
|
||||
/* Get the result vector type: */
|
||||
typedef typename expr_traits::result_type::row_vector_type result_type;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum. */
|
||||
enum { array_size = result_type::array_size };
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return expr_traits().rows(m_expr);
|
||||
}
|
||||
|
||||
/** Return the result as a normalized vector. */
|
||||
result_type normalize() const {
|
||||
result_type v(VectorXpr<expr_type>(*this));
|
||||
return v.normalize();
|
||||
}
|
||||
|
||||
/** Return reference to contained expression. */
|
||||
expr_reference expression() const { return m_expr; }
|
||||
|
||||
/** Compute value at index i of the row vector. */
|
||||
value_type operator[](size_t i) const {
|
||||
return expr_traits().get(m_expr,m_row,i);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the subexpression to store. */
|
||||
explicit MatrixRowOp(const ExprT& expr, size_t row)
|
||||
: m_expr(expr), m_row(row) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
MatrixRowOp(const expr_type& e)
|
||||
: m_expr(e.m_expr), m_row(e.m_row) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
expr_reference m_expr;
|
||||
const size_t m_row;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits class for MatrixRowOp<>. */
|
||||
template<class ExprT>
|
||||
struct ExprTraits< MatrixRowOp<ExprT> >
|
||||
{
|
||||
typedef MatrixRowOp<ExprT> expr_type;
|
||||
typedef ExprT arg_type;
|
||||
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& v, size_t i) const { return v[i]; }
|
||||
size_t size(const expr_type& e) const { return e.size(); }
|
||||
};
|
||||
|
||||
template<class ExprT>
|
||||
class MatrixColOp
|
||||
{
|
||||
public:
|
||||
|
||||
typedef MatrixColOp<ExprT> expr_type;
|
||||
|
||||
/* Record ary-ness of the expression: */
|
||||
typedef unary_expression expr_ary;
|
||||
|
||||
/* Copy the expression by value into higher-up expressions: */
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename ExprT::value_type value_type;
|
||||
typedef vector_result_tag result_tag;
|
||||
typedef typename ExprT::size_tag size_tag;
|
||||
|
||||
/* Store the expression traits: */
|
||||
typedef ExprTraits<ExprT> expr_traits;
|
||||
|
||||
/* Get the reference type: */
|
||||
typedef typename expr_traits::const_reference expr_reference;
|
||||
|
||||
/* Get the result vector type: */
|
||||
typedef typename expr_traits::result_type::col_vector_type result_type;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum. */
|
||||
enum { array_size = result_type::array_size };
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return expr_traits().cols(m_expr);
|
||||
}
|
||||
|
||||
/** Return reference to contained expression. */
|
||||
expr_reference expression() const { return m_expr; }
|
||||
|
||||
/** Return the result as a normalized vector. */
|
||||
result_type normalize() const {
|
||||
result_type v(VectorXpr<expr_type>(*this));
|
||||
return v.normalize();
|
||||
}
|
||||
|
||||
/** Compute value at index i of the col vector. */
|
||||
value_type operator[](size_t i) const {
|
||||
return expr_traits().get(m_expr,i,m_col);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the subexpression to store. */
|
||||
explicit MatrixColOp(const ExprT& expr, size_t col)
|
||||
: m_expr(expr), m_col(col) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
MatrixColOp(const expr_type& e)
|
||||
: m_expr(e.m_expr), m_col(e.m_col) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
expr_reference m_expr;
|
||||
const size_t m_col;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits class for MatrixColOp<>. */
|
||||
template<class ExprT>
|
||||
struct ExprTraits< MatrixColOp<ExprT> >
|
||||
{
|
||||
typedef MatrixColOp<ExprT> expr_type;
|
||||
typedef ExprT arg_type;
|
||||
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& v, size_t i) const { return v[i]; }
|
||||
size_t size(const expr_type& e) const { return e.size(); }
|
||||
};
|
||||
|
||||
} // namespace et
|
||||
|
||||
/* Define the row and column operators in the cml namespace: */
|
||||
|
||||
/** Matrix row operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
et::VectorXpr< et::MatrixRowOp< matrix<E,AT,BO,L> > >
|
||||
row(const matrix<E,AT,BO,L>& expr, size_t i)
|
||||
{
|
||||
typedef et::MatrixRowOp< matrix<E,AT,BO,L> > ExprT;
|
||||
return et::VectorXpr<ExprT>(ExprT(expr,i));
|
||||
}
|
||||
|
||||
/** Matrix row operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixRowOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
et::VectorXpr< et::MatrixRowOp<XprT> >
|
||||
row(const et::MatrixXpr<XprT>& expr, size_t i)
|
||||
{
|
||||
typedef et::MatrixRowOp<XprT> ExprT;
|
||||
return et::MatrixXpr<ExprT>(ExprT(expr.expression(),i));
|
||||
}
|
||||
|
||||
/** Matrix col operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
et::VectorXpr< et::MatrixColOp< matrix<E,AT,BO,L> > >
|
||||
col(const matrix<E,AT,BO,L>& expr, size_t i)
|
||||
{
|
||||
typedef et::MatrixColOp< matrix<E,AT,BO,L> > ExprT;
|
||||
return et::VectorXpr<ExprT>(ExprT(expr,i));
|
||||
}
|
||||
|
||||
/** Matrix col operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixColOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
et::VectorXpr< et::MatrixColOp<XprT> >
|
||||
col(const et::MatrixXpr<XprT>& expr, size_t i)
|
||||
{
|
||||
typedef et::MatrixColOp<XprT> ExprT;
|
||||
return et::VectorXpr<ExprT>(ExprT(expr.expression(),i));
|
||||
}
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
49
Lib/Include/CML/matrix/matrix_traits.h
Normal file
49
Lib/Include/CML/matrix/matrix_traits.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef matrix_traits_h
|
||||
#define matrix_traits_h
|
||||
|
||||
#include <cml/et/traits.h>
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
struct ExprTraits< cml::matrix<E,AT,BO,L> >
|
||||
{
|
||||
typedef typename cml::matrix<E,AT,BO,L> expr_type;
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_reference reference;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::assignable_tag assignable_tag;
|
||||
typedef expr_type result_type;
|
||||
typedef expr_leaf_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& m, size_t i, size_t j) const {
|
||||
return m(i,j);
|
||||
}
|
||||
|
||||
matrix_size size(const expr_type& e) const { return e.size(); }
|
||||
size_t rows(const expr_type& m) const { return m.rows(); }
|
||||
size_t cols(const expr_type& m) const { return m.cols(); }
|
||||
};
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
305
Lib/Include/CML/matrix/matrix_transpose.h
Normal file
305
Lib/Include/CML/matrix/matrix_transpose.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* @todo Currently, the transpose() and T() functions copy the transposed
|
||||
* result into a temporary, and return it to avoid aliasing problems, e.g.
|
||||
* C = transpose(C). By checking for C on the right-hand side, this can
|
||||
* be avoided, but experimentation is needed to determine the impact on
|
||||
* performance. Another option is to use a function to explicitly specify
|
||||
* when a temporary is needed; e.g. C = transpose(temp(C)).
|
||||
*/
|
||||
|
||||
#ifndef matrix_transpose_h
|
||||
#define matrix_transpose_h
|
||||
|
||||
#include <cml/matrix/matrix_expr.h>
|
||||
|
||||
#define MATRIX_TRANSPOSE_RETURNS_TEMP
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/** "Transpose" the given matrix expression.
|
||||
*
|
||||
* This does nothing more than change the result type of the expression
|
||||
* into one with the opposite orientation (i.e. row->col, col->row).
|
||||
*/
|
||||
template<class ExprT>
|
||||
class MatrixTransposeOp
|
||||
{
|
||||
public:
|
||||
|
||||
typedef MatrixTransposeOp<ExprT> expr_type;
|
||||
|
||||
/* Record ary-ness of the expression: */
|
||||
typedef unary_expression expr_ary;
|
||||
|
||||
/* Copy the expression by value into higher-up expressions: */
|
||||
typedef expr_type expr_const_reference;
|
||||
|
||||
typedef typename ExprT::value_type value_type;
|
||||
typedef matrix_result_tag result_tag;
|
||||
typedef typename ExprT::size_tag size_tag;
|
||||
|
||||
/* Store the expression traits: */
|
||||
typedef ExprTraits<ExprT> expr_traits;
|
||||
|
||||
/* Get the reference type: */
|
||||
typedef typename expr_traits::const_reference expr_reference;
|
||||
|
||||
/* Swap the orientation: */
|
||||
typedef typename expr_traits::result_type::transposed_type result_type;
|
||||
|
||||
/* Get the temporary type: */
|
||||
typedef typename result_type::temporary_type temporary_type;
|
||||
|
||||
/* For matching by assignability: */
|
||||
typedef cml::et::not_assignable_tag assignable_tag;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Record result size as an enum. */
|
||||
enum {
|
||||
array_rows = result_type::array_rows,
|
||||
array_cols = result_type::array_cols
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Return the expression size as a pair. */
|
||||
matrix_size size() const {
|
||||
return matrix_size(this->rows(),this->cols());
|
||||
}
|
||||
|
||||
/** Return result rows.
|
||||
*
|
||||
* The tranpose has the same number of rows as the original has
|
||||
* columns.
|
||||
*/
|
||||
size_t rows() const {
|
||||
return expr_traits().cols(m_expr);
|
||||
}
|
||||
|
||||
/** Return result cols.
|
||||
*
|
||||
* The tranpose has the same number of columns as the original has
|
||||
* rows.
|
||||
*/
|
||||
size_t cols() const {
|
||||
return expr_traits().rows(m_expr);
|
||||
}
|
||||
|
||||
/** Return reference to contained expression. */
|
||||
expr_reference expression() const { return m_expr; }
|
||||
|
||||
/** Compute value at index i of the result matrix.
|
||||
*
|
||||
* Element (i,j) of the transpose is element (j,i) of the original
|
||||
* expression.
|
||||
*/
|
||||
value_type operator()(size_t i, size_t j) const {
|
||||
return expr_traits().get(m_expr,j,i);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Construct from the subexpression to store. */
|
||||
explicit MatrixTransposeOp(const ExprT& expr) : m_expr(expr) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
MatrixTransposeOp(const expr_type& e) : m_expr(e.m_expr) {}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
expr_reference m_expr;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* Cannot be assigned to: */
|
||||
expr_type& operator=(const expr_type&);
|
||||
};
|
||||
|
||||
/** Expression traits class for VectorTransposeOp<>. */
|
||||
template<class ExprT>
|
||||
struct ExprTraits< MatrixTransposeOp<ExprT> >
|
||||
{
|
||||
typedef MatrixTransposeOp<ExprT> expr_type;
|
||||
typedef typename expr_type::value_type value_type;
|
||||
typedef typename expr_type::expr_const_reference const_reference;
|
||||
typedef typename expr_type::result_tag result_tag;
|
||||
typedef typename expr_type::size_tag size_tag;
|
||||
typedef typename expr_type::result_type result_type;
|
||||
typedef typename expr_type::assignable_tag assignable_tag;
|
||||
typedef expr_node_tag node_tag;
|
||||
|
||||
value_type get(const expr_type& m, size_t i, size_t j) const {
|
||||
return m(i,j);
|
||||
}
|
||||
|
||||
matrix_size size(const expr_type& e) const { return e.size(); }
|
||||
size_t rows(const expr_type& e) const { return e.rows(); }
|
||||
size_t cols(const expr_type& e) const { return e.cols(); }
|
||||
};
|
||||
|
||||
} // namespace et
|
||||
|
||||
|
||||
/* Define the transpose operators in the cml namespace: */
|
||||
#if defined(MATRIX_TRANSPOSE_RETURNS_TEMP)
|
||||
|
||||
/** Matrix transpose operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
typename et::MatrixTransposeOp<
|
||||
matrix<E,AT,BO,L>
|
||||
>::temporary_type
|
||||
transpose(const matrix<E,AT,BO,L>& expr)
|
||||
{
|
||||
/* Record the matrix type: */
|
||||
typedef matrix<E,AT,BO,L> matrix_type;
|
||||
|
||||
/* Record the type of the transpose op: */
|
||||
typedef et::MatrixTransposeOp<matrix_type> Op;
|
||||
|
||||
/* Determine the returned matrix type: */
|
||||
typedef typename et::MatrixTransposeOp<
|
||||
matrix_type
|
||||
>::temporary_type tmp_type;
|
||||
|
||||
/* The expression to use to assign the temporary: */
|
||||
typedef et::MatrixXpr<Op> ExprT;
|
||||
|
||||
/* Create the temporary and return it: */
|
||||
tmp_type tmp;
|
||||
cml::et::detail::Resize(tmp,expr.rows(),expr.cols());
|
||||
tmp = ExprT(Op(expr));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/** Matrix transpose operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixTransposeOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
typename et::MatrixTransposeOp<
|
||||
XprT
|
||||
>::temporary_type
|
||||
transpose(MATXPR_ARG_TYPE expr)
|
||||
{
|
||||
/* Record the type of the transpose op: */
|
||||
typedef et::MatrixTransposeOp<XprT> Op;
|
||||
|
||||
/* Determine the returned matrix type: */
|
||||
typedef typename et::MatrixTransposeOp<XprT>::temporary_type tmp_type;
|
||||
|
||||
/* The expression to use to assign the temporary: */
|
||||
typedef et::MatrixXpr<Op> ExprT;
|
||||
|
||||
/* Create the temporary and return it: */
|
||||
tmp_type tmp;
|
||||
cml::et::detail::Resize(tmp,expr.rows(),expr.cols());
|
||||
tmp = ExprT(Op(expr.expression()));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/* For notational convenience: */
|
||||
|
||||
/** Matrix transpose operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
typename et::MatrixTransposeOp<
|
||||
matrix<E,AT,BO,L>
|
||||
>::temporary_type
|
||||
T(const matrix<E,AT,BO,L>& expr)
|
||||
{
|
||||
return transpose(expr);
|
||||
}
|
||||
|
||||
/** Matrix transpose operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixTransposeOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
typename et::MatrixTransposeOp<
|
||||
XprT
|
||||
>::temporary_type
|
||||
T(MATXPR_ARG_TYPE expr)
|
||||
{
|
||||
return transpose(expr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* XXX For this to work correctly, matrix assignment and copy have to be
|
||||
* changed to either use a temporary all the time, or to create a temporary
|
||||
* when the same matrix appears on both sides of an assignment, and a
|
||||
* temporary was not already created on the RHS by the ET code.
|
||||
*/
|
||||
|
||||
/** Matrix transpose operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
et::MatrixXpr< et::MatrixTransposeOp< matrix<E,AT,BO,L> > >
|
||||
transpose(const matrix<E,AT,BO,L>& expr)
|
||||
{
|
||||
typedef et::MatrixTransposeOp< matrix<E,AT,BO,L> > ExprT;
|
||||
return et::MatrixXpr<ExprT>(ExprT(expr));
|
||||
}
|
||||
|
||||
/** Matrix transpose operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixTransposeOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
et::MatrixXpr< et::MatrixTransposeOp<XprT> >
|
||||
transpose(MATXPR_ARG_TYPE expr)
|
||||
{
|
||||
typedef et::MatrixTransposeOp<XprT> ExprT;
|
||||
return et::MatrixXpr<ExprT>(ExprT(expr.expression()));
|
||||
}
|
||||
|
||||
|
||||
/* For notational convenience: */
|
||||
|
||||
/** Matrix transpose operator taking a matrix operand. */
|
||||
template<typename E, class AT, typename BO, typename L>
|
||||
et::MatrixXpr< et::MatrixTransposeOp< matrix<E,AT,BO,L> > >
|
||||
T(const matrix<E,AT,BO,L>& expr)
|
||||
{
|
||||
return transpose(expr);
|
||||
}
|
||||
|
||||
/** Matrix transpose operator taking an et::MatrixXpr operand.
|
||||
*
|
||||
* The parse tree is automatically compressed by hoisting the MatrixXpr's
|
||||
* subexpression into the subexpression of the MatrixTransposeOp.
|
||||
*/
|
||||
template<class XprT>
|
||||
et::MatrixXpr< et::MatrixTransposeOp<XprT> >
|
||||
T(MATXPR_ARG_TYPE expr)
|
||||
{
|
||||
return transpose(expr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
293
Lib/Include/CML/matrix/matrix_unroller.h
Normal file
293
Lib/Include/CML/matrix/matrix_unroller.h
Normal file
@@ -0,0 +1,293 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* @todo Need to implement unrolling for efficient col-major array access.
|
||||
*
|
||||
* @todo Does it make sense to unroll an assignment if either side of the
|
||||
* assignment has a fixed size, or just when the target matrix is fixed
|
||||
* size?
|
||||
*/
|
||||
|
||||
#ifndef matrix_unroller_h
|
||||
#define matrix_unroller_h
|
||||
|
||||
#include <cml/et/traits.h>
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/et/scalar_ops.h>
|
||||
|
||||
#if !defined(CML_2D_UNROLLER) && !defined(CML_NO_2D_UNROLLER)
|
||||
#error "The matrix unroller has not been defined."
|
||||
#endif
|
||||
|
||||
#if defined(CML_2D_UNROLLER) && !defined(CML_MATRIX_UNROLL_LIMIT)
|
||||
#error "CML_MATRIX_UNROLL_LIMIT is undefined."
|
||||
#endif
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
namespace detail {
|
||||
|
||||
/** Unroll a binary assignment operator on a fixed-size matrix.
|
||||
*
|
||||
* This uses a forward iteration to make better use of the cache.
|
||||
*
|
||||
* @sa cml::matrix
|
||||
* @sa cml::et::OpAssign
|
||||
*
|
||||
* @bug Need to verify that OpT is actually an assignment operator.
|
||||
* @bug The 2D unroller needs to be specified for efficient col-major
|
||||
* access.
|
||||
*/
|
||||
template<class OpT, typename E, class AT, typename BO, typename L, class SrcT>
|
||||
class MatrixAssignmentUnroller
|
||||
{
|
||||
protected:
|
||||
|
||||
/* The matrix type being assigned to: */
|
||||
typedef cml::matrix<E,AT,BO,L> matrix_type;
|
||||
|
||||
/* Record traits for the arguments: */
|
||||
typedef ExprTraits<matrix_type> dest_traits;
|
||||
typedef ExprTraits<SrcT> src_traits;
|
||||
|
||||
#if defined(CML_2D_UNROLLER)
|
||||
|
||||
/* Forward declare: */
|
||||
template<int R, int C, int LastRow, int LastCol, bool can_unroll>
|
||||
struct Eval;
|
||||
|
||||
/* XXX This needs to be specified for efficient col-major access also! */
|
||||
|
||||
/** Evaluate the binary operator at element R,C. */
|
||||
template<int R, int C, int LastRow, int LastCol>
|
||||
struct Eval<R,C,LastRow,LastCol,true> {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
|
||||
/* Apply to current R,C: */
|
||||
OpT().apply(dest(R,C), src_traits().get(src,R,C));
|
||||
|
||||
/* Evaluate at R,C+1: */
|
||||
Eval<R,C+1,LastRow,LastCol,true>()(dest,src);
|
||||
}
|
||||
};
|
||||
|
||||
/** Evaluate the binary operator at element R,LastCol. */
|
||||
template<int R, int LastRow, int LastCol>
|
||||
struct Eval<R,LastCol,LastRow,LastCol,true> {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
|
||||
/* Apply to R,LastCol: */
|
||||
OpT().apply(dest(R,LastCol), src_traits().get(src,R,LastCol));
|
||||
|
||||
/* Evaluate at R+1,0; i.e. move to next row and start the
|
||||
* col iteration from 0:
|
||||
*/
|
||||
Eval<R+1,0,LastRow,LastCol,true>()(dest,src);
|
||||
}
|
||||
};
|
||||
|
||||
/** Evaluate the binary operator at element LastRow,C. */
|
||||
template<int C, int LastRow, int LastCol>
|
||||
struct Eval<LastRow,C,LastRow,LastCol,true> {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
|
||||
/* Apply to LastRow,C: */
|
||||
OpT().apply(dest(LastRow,C), src_traits().get(src,LastRow,C));
|
||||
|
||||
/* Evaluate at LastRow,C+1: */
|
||||
Eval<LastRow,C+1,LastRow,LastCol,true>()(dest,src);
|
||||
}
|
||||
};
|
||||
|
||||
/** Evaluate the binary operator at element LastRow,LastCol. */
|
||||
template<int LastRow, int LastCol>
|
||||
struct Eval<LastRow,LastCol,LastRow,LastCol,true> {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
|
||||
/* Apply to LastRow,LastCol: */
|
||||
OpT().apply(
|
||||
dest(LastRow,LastCol),
|
||||
src_traits().get(src,LastRow,LastCol));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Evaluate operators on large matrices using a loop. */
|
||||
template<int R, int C, int LastRow, int LastCol>
|
||||
struct Eval<R,C,LastRow,LastCol,false> {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
for(size_t i = 0; i <= LastRow; ++i) {
|
||||
for(size_t j = 0; j <= LastCol; ++j) {
|
||||
OpT().apply(dest(i,j), src_traits().get(src,i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CML_2D_UNROLLER
|
||||
|
||||
#if defined(CML_NO_2D_UNROLLER)
|
||||
|
||||
/** Evaluate the binary operator using a loop. */
|
||||
template<int R, int C, int LastRow, int LastCol> struct Eval {
|
||||
void operator()(matrix_type& dest, const SrcT& src) const {
|
||||
for(size_t i = 0; i <= LastRow; ++i) {
|
||||
for(size_t j = 0; j <= LastCol; ++j) {
|
||||
OpT().apply(dest(i,j), src_traits().get(src,i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CML_NO_2D_UNROLLER
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** Unroll assignment for a fixed-sized matrix. */
|
||||
void operator()(
|
||||
cml::matrix<E,AT,BO,L>& dest, const SrcT& src, cml::fixed_size_tag)
|
||||
{
|
||||
typedef cml::matrix<E,AT,BO,L> matrix_type;
|
||||
enum {
|
||||
LastRow = matrix_type::array_rows-1,
|
||||
LastCol = matrix_type::array_cols-1,
|
||||
Max = (LastRow+1)*(LastCol+1)
|
||||
};
|
||||
|
||||
#if defined(CML_2D_UNROLLER)
|
||||
typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
|
||||
::template Eval<0, 0, LastRow, LastCol,
|
||||
(Max <= CML_MATRIX_UNROLL_LIMIT)> Unroller;
|
||||
#endif
|
||||
|
||||
#if defined(CML_NO_2D_UNROLLER)
|
||||
/* Use a loop: */
|
||||
typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
|
||||
::template Eval<0, 0, LastRow, LastCol> Unroller;
|
||||
#endif
|
||||
|
||||
/* Use a run-time check if src is a run-time sized expression: */
|
||||
typedef typename ExprTraits<SrcT>::size_tag src_size;
|
||||
typedef typename select_if<
|
||||
same_type<src_size,dynamic_size_tag>::is_true,
|
||||
dynamic_size_tag, fixed_size_tag>::result size_tag;
|
||||
|
||||
/* Check the expression size (the returned size isn't needed): */
|
||||
CheckedSize(dest,src,size_tag());
|
||||
/* Note: for two fixed-size expressions, the if-statements and
|
||||
* comparisons should be completely eliminated as dead code. If
|
||||
* src is a dynamic-sized expression, the check will still happen.
|
||||
*/
|
||||
|
||||
Unroller()(dest,src);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */
|
||||
matrix_size hack_actual_size(
|
||||
matrix_type& dest, const SrcT& /*src*/, scalar_result_tag
|
||||
)
|
||||
{
|
||||
typedef ExprTraits<matrix_type> dest_traits;
|
||||
return dest_traits().size(dest);
|
||||
}
|
||||
|
||||
matrix_size hack_actual_size(
|
||||
matrix_type& /*dest*/, const SrcT& src, matrix_result_tag
|
||||
)
|
||||
{
|
||||
typedef ExprTraits<SrcT> src_traits;
|
||||
return src_traits().size(src);
|
||||
}
|
||||
|
||||
matrix_size CheckOrResize(
|
||||
matrix_type& dest, const SrcT& src, cml::resizable_tag)
|
||||
{
|
||||
#if defined(CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT)
|
||||
/* Get the size of src. This also causes src to check its size: */
|
||||
matrix_size N = hack_actual_size(
|
||||
dest, src, typename src_traits::result_tag());
|
||||
|
||||
/* Set the destination matrix's size: */
|
||||
dest.resize(N.first,N.second);
|
||||
#else
|
||||
matrix_size N = CheckedSize(dest,src,dynamic_size_tag());
|
||||
#endif
|
||||
return N;
|
||||
}
|
||||
|
||||
matrix_size CheckOrResize(
|
||||
matrix_type& dest, const SrcT& src, cml::not_resizable_tag)
|
||||
{
|
||||
return CheckedSize(dest,src,dynamic_size_tag());
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/** Use a loop for dynamic-sized matrix assignment.
|
||||
*
|
||||
* @note The target matrix must already have the correct size.
|
||||
*
|
||||
* @todo This needs to be specialized for efficient row-major or col-major
|
||||
* layout access.
|
||||
*/
|
||||
void operator()(matrix_type& dest, const SrcT& src, cml::dynamic_size_tag)
|
||||
{
|
||||
typedef ExprTraits<SrcT> src_traits;
|
||||
matrix_size N = this->CheckOrResize(
|
||||
dest,src,typename matrix_type::resizing_tag());
|
||||
for(size_t i = 0; i < N.first; ++i) {
|
||||
for(size_t j = 0; j < N.second; ++j) {
|
||||
OpT().apply(dest(i,j), src_traits().get(src,i,j));
|
||||
/* Note: we don't need get(), since dest is a matrix. */
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** This constructs an assignment unroller for fixed-size arrays.
|
||||
*
|
||||
* The operator must be an assignment op (otherwise, this doesn't make any
|
||||
* sense). Also, automatic unrolling is only performed for fixed-size
|
||||
* matrices; a loop is used for dynamic-sized matrices.
|
||||
*
|
||||
* @sa cml::matrix
|
||||
* @sa cml::et::OpAssign
|
||||
*
|
||||
* @bug Need to verify that OpT is actually an assignment operator.
|
||||
*/
|
||||
template<class OpT, class SrcT, typename E, class AT, typename BO, typename L>
|
||||
inline void UnrollAssignment(cml::matrix<E,AT,BO,L>& dest, const SrcT& src)
|
||||
{
|
||||
/* Record the destination matrix type, and the expression traits: */
|
||||
typedef cml::matrix<E,AT,BO,L> matrix_type;
|
||||
|
||||
/* Record the type of the unroller: */
|
||||
typedef detail::MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT> unroller;
|
||||
|
||||
/* Finally, do the unroll call: */
|
||||
unroller()(dest, src, typename matrix_type::size_tag());
|
||||
/* XXX It may make sense to unroll if either side is a fixed size. */
|
||||
}
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
Reference in New Issue
Block a user