X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fcml%2Fmatrix%2Fmatrix_comparison.h;fp=src%2Fcml%2Fmatrix%2Fmatrix_comparison.h;h=d8772b04f929fd7f06b287668689e77d804af74d;hp=0000000000000000000000000000000000000000;hb=0fffd0097d7b496454413e57b398c903ecc252e4;hpb=79becf045222f385da5a1b9eb79081f6f5266c86 diff --git a/src/cml/matrix/matrix_comparison.h b/src/cml/matrix/matrix_comparison.h new file mode 100644 index 0000000..d8772b0 --- /dev/null +++ b/src/cml/matrix/matrix_comparison.h @@ -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 +#include +#include + +/* 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 \ +inline bool \ +_op_ ( \ + const matrix& left, \ + const matrix& right) \ +{ \ + return detail::matrix_##_order_ (left, right, _OpT_ ()); \ +} + +#define CML_MAT_MATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const matrix& left, \ + MATXPR_ARG_TYPE right) \ +{ \ + return detail::matrix_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_MATXPR_MAT_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + MATXPR_ARG_TYPE left, \ + const matrix& right) \ +{ \ + return detail::matrix_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_MATXPR_MATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +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 +inline bool +matrix_weak_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* matrix_comparison() requires matrix expressions: */ + CML_STATIC_REQUIRE_M( + (et::MatrixExpressions::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 +inline bool +matrix_total_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* matrix_comparison() requires matrix expressions: */ + CML_STATIC_REQUIRE_M( + (et::MatrixExpressions::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) { + + /* 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; +} + +} + +} // namespace cml + +/* XXX There is a better way to handle these with operator traits... */ + +CML_MAT_VEC_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_VECXPR_ORDER( total_order, operator==, et::OpEqual) + +CML_MAT_VEC_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_VECXPR_ORDER( weak_order, operator!=, et::OpNotEqual) + +CML_MAT_VEC_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_VECXPR_ORDER( weak_order, operator<, et::OpLess) + +CML_MAT_VEC_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_VECXPR_ORDER( weak_order, operator>, et::OpGreater) + +CML_MAT_VEC_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_VECXPR_ORDER( total_order, operator<=, et::OpLessEqual) + +CML_MAT_VEC_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_VECXPR_ORDER( total_order, operator>=, et::OpGreaterEqual) + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp