/*
 * Tiny Vector Matrix Library
 * Dense Vector Matrix Libary of Tiny size using Expression Templates
 *
 * Copyright (C) 2001, 2002 Olaf Petzold <opetzold@wit.regiocom.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * "$Id:"
 */

#ifndef TVMET_MATRIX_EVAL_H
#define TVMET_MATRIX_EVAL_H

/* forwards */
template <class T> class std::complex;


namespace tvmet {

/**
 * \fn bool all_elements(const XprMatrix<E, Rows, Cols>& e)
 * \brief check on statements for all elements
 * \ingroup _unary_function
 * This is for use with boolean operators like
 * \par Example:
 * \code
 * all_elements(mat_xpr > 0)
 * \endcode
 */
template<class E, std::size_t Rows, std::size_t Cols>
inline
bool all_elements(const XprMatrix<E, Rows, Cols>& e) {
  return meta::Matrix<Rows, Cols, 0, 0>::all_elements(e);
}

/**
 * \fn bool any_elements(const XprMatrix<E, Rows, Cols>& e)
 * \brief check on statements for any elements
 * \ingroup _unary_function
 * This is for use with boolean operators like
 * \par Example:
 * \code
 * any_elements(mat_xpr > 0)
 * \endcode
 */
template<class E, std::size_t Rows, std::size_t Cols>
inline
bool any_elements(const XprMatrix<E, Rows, Cols>& e) {
  return meta::Matrix<Rows, Cols, 0, 0>::any_elements(e);
}

/**
 * \fn bool eval(XprMatrix<E, Rows, Cols> e)
 * \brief Evals the matrix expressions to bool.
 * \ingroup _unary_function
 * This eval is for use for branches, like
 * \par Example:
 * \code
 * if(Matrix1 > Matrix2) {
 *     // true branch
 * } else {
 *     // false branch
 * }\endcode
 */
template<class E, std::size_t Rows, std::size_t Cols>
inline
bool eval(XprMatrix<E, Rows, Cols> e) {
  return meta::Matrix<Rows, Cols, 0, 0>::eval(e);
}

/*
 * XprMatrix<E1, Rows, Cols> ? Matrix<T2, Rows, Cols> : Matrix<T3, Rows, Cols>
 * XprMatrix<E1, Rows, Cols> ? Matrix<T2, Rows, Cols> : XprMatrix<E3, Rows, Cols>
 * XprMatrix<E1, Rows, Cols> ? XprMatrix<E2, Rows, Cols> : Matrix<T3, Rows, Cols>
 * XprMatrix<E1, Rows, Cols> ? XprMatrix<E2, Rows, Cols> : XprMatrix<E3, Rows, Cols>
 */

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, const Matrix<T2, Rows, Cols>& m2, const Matrix<T3, Rows, Cols>& m3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class T2, class T3, std::size_t Rows, std::size_t Cols>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    MatrixConstReference<T2, Rows, Cols>,
    MatrixConstReference<T3, Rows, Cols>
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1,
     const Matrix<T2, Rows, Cols>& m2,
     const Matrix<T3, Rows, Cols>& m3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    MatrixConstReference<T2, Rows, Cols>,
    MatrixConstReference<T3, Rows, Cols>
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, m2.cref(), m3.cref()));
}

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, const Matrix<T2, Rows, Cols>& m2, XprMatrix<E3, Rows, Cols> e3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class T2, class E3, std::size_t Rows, std::size_t Cols>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    MatrixConstReference<T2, Rows, Cols>,
    XprMatrix<E3, Rows, Cols>
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1,
     const Matrix<T2, Rows, Cols>& m2,
     XprMatrix<E3, Rows, Cols> e3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    MatrixConstReference<T2, Rows, Cols>,
    XprMatrix<E3, Rows, Cols>
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, m2.cref(), e3));
}

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, XprMatrix<E2, Rows, Cols> e2, const Matrix<T3, Rows, Cols>& m3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class E2, class T3, std::size_t Rows, std::size_t Cols>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    MatrixConstReference<T3, Rows, Cols>
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1,
     XprMatrix<E2, Rows, Cols> e2,
     const Matrix<T3, Rows, Cols>& m3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    MatrixConstReference<T3, Rows, Cols>
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, e2, m3.cref()));
}

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, XprMatrix<E2, Rows, Cols> e2, XprMatrix<E3, Rows, Cols> e3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class E2, class E3, std::size_t Rows, std::size_t Cols>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    XprMatrix<E3, Rows, Cols>
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1,
     XprMatrix<E2, Rows, Cols> e2,
     XprMatrix<E3, Rows, Cols> e3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    XprMatrix<E3, Rows, Cols>
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, e2, e3));
}

/*
 * XprMatrix<E, Rows, Cols> ? POD1 : POD2
 * XprMatrix<E1, Rows, Cols> ? POD : XprMatrix<E3, Rows, Cols>
 * XprMatrix<E1, Rows, Cols> ? XprMatrix<E2, Rows, Cols> : POD
 */
#define TVMET_EVAL(POD)               					\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline               							\
XprMatrix<               						\
  XprEval<               						\
    XprMatrix<E, Rows, Cols>,               			      	\
    XprLiteral< POD >,               					\
    XprLiteral< POD >               					\
  >,                							\
  Rows, Cols								\
>               							\
eval(XprMatrix<E, Rows, Cols> e, POD x2, POD x3) {             		\
  typedef XprEval<               					\
    XprMatrix<E, Rows, Cols>,               				\
    XprLiteral< POD >,                					\
    XprLiteral< POD >                					\
  > 							expr_type; 	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e, XprLiteral< POD >(x2), XprLiteral< POD >(x3))); \
}               							\
               								\
template<class E1, class E3, std::size_t Rows, std::size_t Cols> 	\
inline               							\
XprMatrix<               						\
  XprEval<               						\
    XprMatrix<E1, Rows, Cols>,               				\
    XprLiteral< POD >,               					\
    XprMatrix<E3, Rows, Cols>               				\
  >,                							\
  Rows, Cols								\
>               							\
eval(XprMatrix<E1, Rows, Cols> e1, POD x2, XprMatrix<E3, Rows, Cols> e3) { \
  typedef XprEval<               					\
    XprMatrix<E1, Rows, Cols>,               				\
    XprLiteral< POD >,                					\
    XprMatrix<E3, Rows, Cols>               				\
  > 							expr_type; 	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, XprLiteral< POD >(x2), e3)); \
}               							\
               								\
template<class E1, class E2, std::size_t Rows, std::size_t Cols>	\
inline               							\
XprMatrix<               						\
  XprEval<               						\
    XprMatrix<E1, Rows, Cols>,               				\
    XprMatrix<E2, Rows, Cols>,               				\
    XprLiteral< POD >               					\
  >,                							\
  Rows, Cols								\
>               							\
eval(XprMatrix<E1, Rows, Cols> e1, XprMatrix<E2, Rows, Cols> e2, POD x3) { \
  typedef XprEval<               					\
    XprMatrix<E1, Rows, Cols>,               				\
    XprMatrix<E2, Rows, Cols>,               				\
    XprLiteral< POD >                					\
  > 							expr_type; 	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, e2, XprLiteral< POD >(x3))); \
}

TVMET_EVAL(int)
TVMET_EVAL(float)
TVMET_EVAL(double)
#ifdef TVMET_HAVE_LONG_DOUBLE
TVMET_EVAL(long double)
#endif // TVMET_HAVE_LONG_DOUBLE

#undef TVMET_EVAL

#ifdef TVMET_HAVE_COMPLEX

/*
 * eval with complex<> types
 */

/**
 * \fn eval(XprMatrix<E, Rows, Cols> e, std::complex<T> x2, std::complex<T> x3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E, std::size_t Rows, std::size_t Cols, class T>
inline
XprMatrix<
  XprEval<
    XprMatrix<E, Rows, Cols>,
    XprLiteral< std::complex<T> >,
    XprLiteral< std::complex<T> >
  >,
  Rows, Cols
>
eval(XprMatrix<E, Rows, Cols> e, std::complex<T> x2, std::complex<T> x3) {
  typedef XprEval<
    XprMatrix<E, Rows, Cols>,
    XprLiteral< std::complex<T> >,
    XprLiteral< std::complex<T> >
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e, XprLiteral< std::complex<T> >(x2), XprLiteral< std::complex<T> >(x3)));
}

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, std::complex<T> x2, XprMatrix<E3, Rows, Cols> e3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class E3, std::size_t Rows, std::size_t Cols, class T>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprLiteral< std::complex<T> >,
    XprMatrix<E3, Rows, Cols>
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1, std::complex<T> x2, XprMatrix<E3, Rows, Cols> e3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprLiteral< std::complex<T> >,
    XprMatrix<E3, Rows, Cols>
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, XprLiteral< std::complex<T> >(x2), e3));
}

/**
 * \fn eval(XprMatrix<E1, Rows, Cols> e1, XprMatrix<E2, Rows, Cols> e2, std::complex<T> x3)
 * \brief Evals the matrix expressions.
 * \ingroup _trinary_function
 * This eval is for the a?b:c syntax, since it's not allowed to overload
 * these operators.
 */
template<class E1, class E2, std::size_t Rows, std::size_t Cols, class T>
inline
XprMatrix<
  XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    XprLiteral< std::complex<T> >
  >,
  Rows, Cols
>
eval(XprMatrix<E1, Rows, Cols> e1, XprMatrix<E2, Rows, Cols> e2, std::complex<T> x3) {
  typedef XprEval<
    XprMatrix<E1, Rows, Cols>,
    XprMatrix<E2, Rows, Cols>,
    XprLiteral< std::complex<T> >
  > 							expr_type;
  return XprMatrix<expr_type, Rows, Cols>(expr_type(e1, e2, XprLiteral< std::complex<T> >(x3)));
}

#endif // TVMET_HAVE_COMPLEX


} // namespace tvmet

#endif // TVMET_MATRIX_EVAL_H

// Local Variables:
// mode:C++
// End:
