Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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