Initial commit
This commit is contained in:
245
Lib/Include/CML/matrix/matrix_comparison.h
Normal file
245
Lib/Include/CML/matrix/matrix_comparison.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/* -*- C++ -*- ------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
|
||||
|
||||
The Configurable Math Library (CML) is distributed under the terms of the
|
||||
Boost Software License, v1.0 (see cml/LICENSE for details).
|
||||
|
||||
*-----------------------------------------------------------------------*/
|
||||
/** @file
|
||||
* @brief
|
||||
*
|
||||
* @todo The matrix and matrix order operators could probably be combined
|
||||
* into a single templated implementation, since the only thing that is
|
||||
* different is the access method.
|
||||
*/
|
||||
|
||||
#ifndef matrix_comparison_h
|
||||
#define matrix_comparison_h
|
||||
|
||||
#include <cml/core/cml_assert.h>
|
||||
#include <cml/et/size_checking.h>
|
||||
#include <cml/et/scalar_ops.h>
|
||||
|
||||
/* This is used below to create a more meaningful compile-time error when
|
||||
* matrix_comparison is not provided with matrix or MatrixExpr arguments:
|
||||
*/
|
||||
struct matrix_comparison_expects_matrix_args_error;
|
||||
|
||||
#define CML_MAT_MAT_ORDER(_order_, _op_, _OpT_) \
|
||||
template<typename E1, class AT1, typename L1, \
|
||||
typename E2, class AT2, typename L2, typename BO> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
const matrix<E1,AT1,BO,L1>& left, \
|
||||
const matrix<E2,AT2,BO,L2>& right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, _OpT_ <E1,E2>()); \
|
||||
}
|
||||
|
||||
#define CML_MAT_MATXPR_ORDER(_order_, _op_, _OpT_) \
|
||||
template<typename E, class AT, typename BO, typename L, class XprT> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
const matrix<E,AT,BO,L>& left, \
|
||||
MATXPR_ARG_TYPE right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ <E, typename XprT::value_type>()); \
|
||||
}
|
||||
|
||||
#define CML_MATXPR_MAT_ORDER(_order_, _op_, _OpT_) \
|
||||
template<class XprT, typename E, class AT, typename BO, typename L> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE left, \
|
||||
const matrix<E,AT,BO,L>& right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ <typename XprT::value_type, E>()); \
|
||||
}
|
||||
|
||||
#define CML_MATXPR_MATXPR_ORDER(_order_, _op_, _OpT_) \
|
||||
template<class XprT1, class XprT2> \
|
||||
inline bool \
|
||||
_op_ ( \
|
||||
MATXPR_ARG_TYPE_N(1) left, \
|
||||
MATXPR_ARG_TYPE_N(2) right) \
|
||||
{ \
|
||||
return detail::matrix_##_order_ (left, right, \
|
||||
_OpT_ < \
|
||||
typename XprT1::value_type, \
|
||||
typename XprT2::value_type>()); \
|
||||
}
|
||||
|
||||
|
||||
namespace cml {
|
||||
namespace detail {
|
||||
|
||||
/** Matrix strict weak ordering relationship.
|
||||
*
|
||||
* OpT must implement a strict weak order on the matrix element type.
|
||||
* operator< and operator> on integer and floating-point types are
|
||||
* examples.
|
||||
*/
|
||||
template<typename LeftT, typename RightT, typename OpT>
|
||||
inline bool
|
||||
matrix_weak_order(const LeftT& left, const RightT& right, OpT)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<LeftT> left_traits;
|
||||
typedef et::ExprTraits<RightT> right_traits;
|
||||
|
||||
/* matrix_comparison() requires matrix expressions: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(et::MatrixExpressions<LeftT,RightT>::is_true),
|
||||
matrix_comparison_expects_matrix_args_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas:
|
||||
*/
|
||||
|
||||
typedef typename et::MatrixPromote<
|
||||
typename left_traits::result_type,
|
||||
typename right_traits::result_type
|
||||
>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Verify expression size: */
|
||||
matrix_size N = et::CheckedSize(left,right,size_tag());
|
||||
for(ssize_t i = 0; i < N.first; ++ i) {
|
||||
for(ssize_t j = 0; j < N.second; ++ j) {
|
||||
if(OpT().apply(
|
||||
left_traits().get(left,i,j),
|
||||
right_traits().get(right,i,j)
|
||||
))
|
||||
{
|
||||
/* If weak order (a < b) is satisfied, return true: */
|
||||
return true;
|
||||
} else if(OpT().apply(
|
||||
right_traits().get(right,i,j),
|
||||
left_traits().get(left,i,j)
|
||||
))
|
||||
{
|
||||
/* If !(b < a), then return false: */
|
||||
return false;
|
||||
} else {
|
||||
|
||||
/* Have !(a < b) && !(b < a) <=> (a >= b && b >= a)
|
||||
* <=> (a == b). so need to test next element:
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* XXX Can this be unrolled in any reasonable way? */
|
||||
|
||||
/* If we get here, then left == right: */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Matrix total order relationship.
|
||||
*
|
||||
* OpT must implement a total order on the matrix element type. operator<=
|
||||
* and operator>= on integer and floating-point types are examples.
|
||||
*/
|
||||
template<typename LeftT, typename RightT, typename OpT>
|
||||
inline bool
|
||||
matrix_total_order(const LeftT& left, const RightT& right, OpT)
|
||||
{
|
||||
/* Shorthand: */
|
||||
typedef et::ExprTraits<LeftT> left_traits;
|
||||
typedef et::ExprTraits<RightT> right_traits;
|
||||
|
||||
/* matrix_comparison() requires matrix expressions: */
|
||||
CML_STATIC_REQUIRE_M(
|
||||
(et::MatrixExpressions<LeftT,RightT>::is_true),
|
||||
matrix_comparison_expects_matrix_args_error);
|
||||
/* Note: parens are required here so that the preprocessor ignores the
|
||||
* commas:
|
||||
*/
|
||||
|
||||
typedef typename et::MatrixPromote<
|
||||
typename left_traits::result_type,
|
||||
typename right_traits::result_type
|
||||
>::type result_type;
|
||||
typedef typename result_type::size_tag size_tag;
|
||||
|
||||
/* Verify expression size: */
|
||||
matrix_size N = et::CheckedSize(left,right,size_tag());
|
||||
for(size_t i = 0; i < N.first; ++ i) {
|
||||
for(size_t j = 0; j < N.second; ++ j) {
|
||||
|
||||
/* Test total order: */
|
||||
if(OpT().apply(
|
||||
left_traits().get(left,i,j),
|
||||
right_traits().get(right,i,j)
|
||||
))
|
||||
{
|
||||
/* Automatically true if weak order (a <= b) && !(b <= a)
|
||||
* <=> (a <= b) && (b > a) <=> (a < b) is satisfied:
|
||||
*/
|
||||
if(!OpT().apply(
|
||||
right_traits().get(right,i,j),
|
||||
left_traits().get(left,i,j)
|
||||
))
|
||||
return true;
|
||||
|
||||
/* Otherwise, have equality (a <= b) && (b <= a), so
|
||||
* continue to next element:
|
||||
*/
|
||||
else
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
/* Total order isn't satisfied (a > b), so return false: */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* XXX Can this be unrolled in any reasonable way? */
|
||||
|
||||
/* Total (==) or weak (<) order was satisfied, so return true: */
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* XXX There is a better way to handle these with operator traits... */
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator==, et::OpEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator==, et::OpEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator<, et::OpLess)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator<, et::OpLess)
|
||||
|
||||
CML_MAT_MAT_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MATXPR_MAT_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MAT_MATXPR_ORDER( weak_order, operator>, et::OpGreater)
|
||||
CML_MATXPR_MATXPR_ORDER( weak_order, operator>, et::OpGreater)
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual)
|
||||
|
||||
CML_MAT_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MATXPR_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MAT_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
CML_MATXPR_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
|
||||
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
Reference in New Issue
Block a user