/*
 * 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_XPR_FUNCTIONS_H
#define TVMET_XPR_FUNCTIONS_H

namespace tvmet {

/************************************************************************
 * global binary math functions
 ************************************************************************/

/*
 * XprVector<E1, Sz> and XprVector<E2, Sz>
 * XprMatrix<E1, Rows, Cols> and XprMatrix<E2, Rows, Cols>
 */
#define TVMET_BINARY_FUNCTION(FUNC, FUNCTIONAL)                 	\
template<class E1, class E2, std::size_t Sz>                   		\
inline                 			      			      	\
XprVector<                    	      					\
  XprBinOp<                    			      			\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprVector<E1, Sz>,         			      			\
    XprVector<E2, Sz>          			      			\
  >,									\
  Sz									\
>                   			      		      		\
FUNC(XprVector<E1, Sz> lhs, XprVector<E2, Sz> rhs) {			\
  typedef XprBinOp<							\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprVector<E1, Sz>,							\
    XprVector<E2, Sz>          			      			\
  >		    					expr_type; 	\
  return XprVector<expr_type, Sz>(expr_type(lhs.cref(), rhs.cref()));   \
}                   			      		      		\
                   			      		      		\
template<class E1, class E2, std::size_t Rows, std::size_t Cols>	\
inline                 			      			      	\
XprMatrix<                    	      					\
  XprBinOp<                    			      			\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprMatrix<E1, Rows, Cols>,         			      		\
    XprMatrix<E2, Rows, Cols>         			      		\
  >,                   			      			      	\
  Rows, Cols           			      			      	\
>                   			      		      		\
FUNC(XprMatrix<E1, Rows, Cols> lhs, XprMatrix<E2, Rows, Cols> rhs) {	\
  typedef XprBinOp<							\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprMatrix<E1, Rows, Cols>,						\
    XprMatrix<E2, Rows, Cols>						\
  >		    					expr_type; 	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, rhs));		\
}


TVMET_BINARY_FUNCTION(atan2, fcnl_atan2)
TVMET_BINARY_FUNCTION(drem, fcnl_drem)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot)
TVMET_BINARY_FUNCTION(jn, fcnl_jn)
TVMET_BINARY_FUNCTION(yn, fcnl_yn)
TVMET_BINARY_FUNCTION(pow, fcnl_pow)
#undef TVMET_BINARY_FUNCTION

/*
 * XprVector<E, Sz> and POD's
 * XprMatrix<E, Rows, Cols> and POD's
 */
#define TVMET_BINARY_FUNCTION(FUNC, FUNCTIONAL, TP)           		\
template<class E, std::size_t Sz>                  			\
inline                 			      			      	\
XprVector<                						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, TP >,          			\
    XprVector<E, Sz>,         						\
    XprLiteral< TP >          						\
  >,               			      			      	\
  Sz               			      			      	\
>          								\
FUNC(XprVector<E, Sz> lhs, TP rhs) {					\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, TP >, 				\
    XprVector<E, Sz>,  							\
    XprLiteral< TP >          						\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(lhs.cref(), XprLiteral< TP >(rhs))); \
}          								\
          								\
template<class E, std::size_t Sz>					\
inline                 			      			      	\
XprVector<          							\
  XprBinOp<          							\
    FUNCTIONAL< TP, typename E::value_type>,  				\
    XprLiteral< TP >,          						\
    XprVector<E, Sz>         						\
  >,          								\
  Sz               			      			      	\
>          								\
FUNC(TP lhs, XprVector<E, Sz> rhs) {	         			\
  typedef XprBinOp<         						\
    FUNCTIONAL< TP, typename E::value_type>,  				\
    XprLiteral< TP >,          						\
    XprVector<E, Sz>         						\
   >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(XprLiteral< TP >(lhs), rhs.cref())); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline                 			      			      	\
XprMatrix<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, TP >,      			\
    XprMatrix<E, Rows, Cols>,		          			\
    XprLiteral< TP >          						\
  >,          								\
  Rows, Cols   								\
>          								\
FUNC(XprMatrix<E, Rows, Cols> lhs, TP rhs) {				\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, TP >,   				\
    XprMatrix<E, Rows, Cols>,		        			\
    XprLiteral< TP >              			      		\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, XprLiteral< TP >(rhs))); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline                 			      			      	\
XprMatrix<          							\
  XprBinOp<          							\
    FUNCTIONAL<TP, typename E::value_type>,    				\
    XprLiteral< TP >,          						\
    XprMatrix<E, Rows, Cols>			      			\
  >,          								\
  Rows, Cols   								\
>          								\
FUNC(TP lhs, XprMatrix<E, Rows, Cols> rhs) {	  			\
  typedef XprBinOp<         						\
    FUNCTIONAL< TP, typename E::value_type>,   				\
    XprLiteral< TP >,         						\
    XprMatrix<E, Rows, Cols>   			      			\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(XprLiteral< TP >(lhs), rhs)); \
}

TVMET_BINARY_FUNCTION(atan2, fcnl_atan2, int)
TVMET_BINARY_FUNCTION(drem, fcnl_drem, int)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod, int)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot, int)
TVMET_BINARY_FUNCTION(jn, fcnl_jn, int)
TVMET_BINARY_FUNCTION(yn, fcnl_yn, int)
TVMET_BINARY_FUNCTION(pow, fcnl_pow, int)

TVMET_BINARY_FUNCTION(atan2, fcnl_atan2, float)
TVMET_BINARY_FUNCTION(drem, fcnl_drem, float)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod, float)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot, float)
TVMET_BINARY_FUNCTION(jn, fcnl_jn, float)
TVMET_BINARY_FUNCTION(yn, fcnl_yn, float)
TVMET_BINARY_FUNCTION(pow, fcnl_pow, float)

TVMET_BINARY_FUNCTION(atan2, fcnl_atan2, double)
TVMET_BINARY_FUNCTION(drem, fcnl_drem, double)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod, double)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot, double)
TVMET_BINARY_FUNCTION(jn, fcnl_jn, double)
TVMET_BINARY_FUNCTION(yn, fcnl_yn, double)
TVMET_BINARY_FUNCTION(pow, fcnl_pow, double)

#ifdef TVMET_HAVE_LONG_DOUBLE
TVMET_BINARY_FUNCTION(atan2, fcnl_atan2, long double)
TVMET_BINARY_FUNCTION(drem, fcnl_drem, long double)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod, long double)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot, long double)
TVMET_BINARY_FUNCTION(jn, fcnl_jn, long double)
TVMET_BINARY_FUNCTION(yn, fcnl_yn, long double)
TVMET_BINARY_FUNCTION(pow, fcnl_pow, long double)
#endif // TVMET_HAVE_LONG_DOUBLE

#undef TVMET_BINARY_FUNCTION

#ifdef TVMET_HAVE_COMPLEX
/*
 * XprVector<E, Sz> and std::complex<>
 * XprMatrix<E, Rows, Cols> and std::complex<>
 */
#define TVMET_BINARY_FUNCTION(FUNC, FUNCTIONAL)	           		\
template<class E, std::size_t Sz, class T>             			\
inline                 			      			      	\
XprVector<                						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, std::complex<T> >, 		\
    XprVector<E, Sz>,         						\
    XprLiteral< std::complex<T> >   					\
  >,               			      			      	\
  Sz               			      			      	\
>          								\
FUNC(XprVector<E, Sz> lhs, const std::complex<T>& rhs) {		\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, std::complex<T> >, 		\
    XprVector<E, Sz>,  							\
    XprLiteral< std::complex<T> >          				\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(lhs.cref(), XprLiteral< std::complex<T> >(rhs))); \
}          								\
          								\
template<class E, std::size_t Sz, class T>				\
inline                 			      			      	\
XprVector<          							\
  XprBinOp<          							\
    FUNCTIONAL< std::complex<T>, typename E::value_type>,  		\
    XprLiteral< std::complex<T> >,          				\
    XprVector<E, Sz>         						\
  >,          								\
  Sz               			      			      	\
>          								\
FUNC(const std::complex<T>& lhs, XprVector<E, Sz> rhs) {  		\
  typedef XprBinOp<         						\
    FUNCTIONAL< std::complex<T>, typename E::value_type>,  		\
    XprLiteral< std::complex<T> >,          				\
    XprVector<E, Sz>         						\
   >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(XprLiteral< std::complex<T> >(lhs), rhs.cref())); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols, class T>		\
inline                 			      			      	\
XprMatrix<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, std::complex<T> >,  		\
    XprMatrix<E, Rows, Cols>,		          			\
    XprLiteral< std::complex<T> >          				\
  >,          								\
  Rows, Cols   								\
>          								\
FUNC(XprMatrix<E, Rows, Cols> lhs, const std::complex<T>& rhs) {	\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, std::complex<T> >, 		\
    XprMatrix<E, Rows, Cols>,		        			\
    XprLiteral< std::complex<T> >         		      		\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, XprLiteral< std::complex<T> >(rhs))); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols, class T>		\
inline                 			      			      	\
XprMatrix<          							\
  XprBinOp<          							\
    FUNCTIONAL<std::complex<T>, typename E::value_type>, 		\
    XprLiteral< std::complex<T> >,          				\
    XprMatrix<E, Rows, Cols>			      			\
  >,          								\
  Rows, Cols   								\
>          								\
FUNC(const std::complex<T>& lhs, XprMatrix<E, Rows, Cols> rhs) { 	\
  typedef XprBinOp<         						\
    FUNCTIONAL< std::complex<T>, typename E::value_type>, 		\
    XprLiteral< std::complex<T> >,         				\
    XprMatrix<E, Rows, Cols>   			      			\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(XprLiteral< std::complex<T> >(lhs), rhs)); \
}

TVMET_BINARY_FUNCTION(atan2, fcnl_atan2)
TVMET_BINARY_FUNCTION(drem, fcnl_drem)
TVMET_BINARY_FUNCTION(fmod, fcnl_fmod)
TVMET_BINARY_FUNCTION(hypot, fcnl_hypot)
TVMET_BINARY_FUNCTION(jn, fcnl_jn)
TVMET_BINARY_FUNCTION(yn, fcnl_yn)
TVMET_BINARY_FUNCTION(pow, fcnl_pow)
#undef TVMET_BINARY_FUNCTION

#endif // TVMET_HAVE_COMPLEX

/************************************************************************
 * global unary math functions
 ************************************************************************/

/*
 * Functions on XprVector<E, Sz>
 */
#define TVMET_UNARY_FUNCTION(FUNC, FUNCTIONAL)				\
template<class E, std::size_t Sz>					\
inline									\
XprVector<								\
  XprUnOp<								\
    FUNCTIONAL<typename E::value_type>, 				\
    XprVector<E, Sz>							\
  >, 									\
  Sz 									\
>									\
FUNC(XprVector<E, Sz> rhs) {						\
  typedef XprUnOp<							\
    FUNCTIONAL<typename E::value_type>, 				\
    XprVector<E, Sz>							\
  > 							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(rhs));			\
}									\
									\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline									\
XprMatrix<								\
  XprUnOp<								\
    FUNCTIONAL<typename E::value_type>, 				\
    XprMatrix<E, Rows, Cols>						\
  >, 									\
  Rows, Cols								\
>									\
FUNC(XprMatrix<E, Rows, Cols> rhs) {					\
  typedef XprUnOp<							\
    FUNCTIONAL<typename E::value_type>, 				\
    XprMatrix<E, Rows, Cols>						\
  > 							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(rhs));		\
}

TVMET_UNARY_FUNCTION(abs, fcnl_abs)
TVMET_UNARY_FUNCTION(cbrt, fcnl_cbrt)
TVMET_UNARY_FUNCTION(floor, fcnl_floor)
TVMET_UNARY_FUNCTION(rint, fcnl_rint)
TVMET_UNARY_FUNCTION(sin, fcnl_sin)
TVMET_UNARY_FUNCTION(sinh, fcnl_sinh)
TVMET_UNARY_FUNCTION(cos, fcnl_cos)
TVMET_UNARY_FUNCTION(cosh, fcnl_cosh)
TVMET_UNARY_FUNCTION(asin, fcnl_asin)
TVMET_UNARY_FUNCTION(acos, fcnl_acos)
TVMET_UNARY_FUNCTION(atan, fcnl_atan)
TVMET_UNARY_FUNCTION(exp, fcnl_exp)
TVMET_UNARY_FUNCTION(log, fcnl_log)
TVMET_UNARY_FUNCTION(log10, fcnl_log10)
TVMET_UNARY_FUNCTION(sqrt, fcnl_sqrt)
#ifdef TVMET_HAVE_IEEE_MATH
TVMET_UNARY_FUNCTION(asinh, fcnl_asinh)
TVMET_UNARY_FUNCTION(acosh, fcnl_acosh)
TVMET_UNARY_FUNCTION(atanh, fcnl_atanh)
TVMET_UNARY_FUNCTION(expm1, fcnl_expm1)
TVMET_UNARY_FUNCTION(log1p, fcnl_log1p)
TVMET_UNARY_FUNCTION(erf, fcnl_erf)
TVMET_UNARY_FUNCTION(erfc, fcnl_erfc)
// XXX default return is int !
TVMET_UNARY_FUNCTION(isnan, fcnl_isnan)
TVMET_UNARY_FUNCTION(isinf, fcnl_isinf)
TVMET_UNARY_FUNCTION(finite, fcnl_finite)
TVMET_UNARY_FUNCTION(j0, fcnl_j0)
TVMET_UNARY_FUNCTION(j1, fcnl_j1)
TVMET_UNARY_FUNCTION(y0, fcnl_y0)
TVMET_UNARY_FUNCTION(y1, fcnl_y1)
TVMET_UNARY_FUNCTION(lgamma, fcnl_lgamma)
#endif
#undef TVMET_UNARY_FUNCTION

} // namespace tvmet

#endif // TVMET_XPR_FUNCTIONS_H

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