// -*- C++ -*- /*************************************************************************** * * The IPPL Framework * * * Visit http://people.web.psi.ch/adelmann/ for more details * ***************************************************************************/ /////////////////////////////////////////////////////////////////////////// // // FILE NAME // IpplExpressions.h // // CREATED // July 11, 1997 // // DESCRIPTION // This header file defines custom objects and operators necessary to use // expression templates in IPPL. // /////////////////////////////////////////////////////////////////////////// #ifndef IPPL_EXPRESSIONS_H #define IPPL_EXPRESSIONS_H // We need to construct a custom version of Reduction. We must define // this macro before including PETE.h. #define PETE_USER_REDUCTION_CODE \ R global_ret; \ reduce_masked(ret, global_ret, acc_op, 0 < n ); \ ret = global_ret; // include files #include "Message/Message.h" #include "PETE/IpplTypeComputations.h" #include "PETE/PETE.h" //========================================================================= // // UNARY OPERATIONS // //========================================================================= // Abs is handled rather strangely. There appears to be two versions // that do the same thing: abs and Abs. PETE_DefineUnary(Abs, (0 < a ? a : -a), FnAbs) inline double PETE_apply(FnAbs, std::complex a) { return abs(a); } template inline PETE_TUTree abs(const PETE_Expr& l) { return PETE_TUTree (l.PETE_unwrap().MakeExpression()); } PETE_DefineUnary(conj, (conj(a)), FnConj) PETE_DefineUnary(arg, (arg(a)), FnArg) PETE_DefineUnary(norm, (norm(a)), FnNorm) PETE_DefineUnary(real, (real(a)), FnReal) PETE_DefineUnary(imag, (imag(a)), FnImag) PETE_DefineUnary(sign, (sign(a)), FnSign) PETE_DefineUnary(trace, (trace(a)), FnTrace) PETE_DefineUnary(transpose, (transpose(a)), FnTranspose) PETE_DefineUnary(det, (det(a)), FnDet) PETE_DefineUnary(cofactors, (cofactors(a)), FnCofactors) //========================================================================= // // BINARY OPERATIONS // //========================================================================= // define min/max for built-in scalar types #define PETE_DefineScalarMinMax(Sca) \ inline Sca \ Min(const Sca& a, const Sca& b) \ { \ return (a) PETE_DefineBinaryWithScalars(eq, OpEQ, std::complex) PETE_DefineBinaryWithScalars(ne, OpNE, std::complex) #undef PETE_DefineIPPLScalar // Now we need to provide special cases for Vektors, SymTenzors, and Tenzors // so we can remove PETE_Expr base class. #define PETE_DefineBinaryWithVSTScalars(Fun,Op,Sca) \ template \ inline PETE_TBTree >, \ typename T2::PETE_Expr_t> \ Fun(const Sca &l, const PETE_Expr& r) \ { \ typedef PETE_TBTree >, \ typename T2::PETE_Expr_t> ret; \ return ret(PETE_Scalar< Sca >(l), \ r.PETE_unwrap().MakeExpression()); \ } \ template \ inline PETE_TBTree > > \ Fun(const PETE_Expr& l, const Sca &r) \ { \ typedef PETE_TBTree > > ret; \ return ret(l.PETE_unwrap().MakeExpression(), \ PETE_Scalar< Sca >(r)); \ } #define PETE_DefineTrinaryWithVSTScalars(Fun, Op, Sca) \ template \ inline PETE_TTTree > > \ Fun(const PETE_Expr& c, const PETE_Expr& t, \ const Sca &f) \ { \ typedef PETE_TTTree > > ret; \ return ret(c.PETE_unwrap().MakeExpression(), \ t.PETE_unwrap().MakeExpression(), PETE_Scalar< Sca >(f)); \ } \ template \ inline PETE_TTTree >, typename False_t::PETE_Expr_t > \ Fun(const PETE_Expr& c, const Sca &t, \ const PETE_Expr& f) \ { \ typedef PETE_TTTree >, \ typename False_t::PETE_Expr_t > ret; \ return ret(c.PETE_unwrap().MakeExpression(), \ PETE_Scalar< Sca >(t), f.PETE_unwrap().MakeExpression()); \ } \ template \ inline PETE_TTTree >, PETE_Scalar< Sca > > \ Fun(const PETE_Expr& c, const Sca &t, const Sca &f) \ { \ typedef PETE_TTTree >, PETE_Scalar< Sca > > ret; \ return ret(c.PETE_unwrap().MakeExpression(), \ PETE_Scalar< Sca >(t), PETE_Scalar< Sca >(f)); \ } //tjw: make sure kosher to have "cross" down there (added in) #define PETE_DefineVSTScalar(Sca) \ PETE_DefineBinaryWithVSTScalars(operator+, OpAdd, Sca) \ PETE_DefineBinaryWithVSTScalars(operator-, OpSubtract, Sca) \ PETE_DefineBinaryWithVSTScalars(operator*, OpMultipply, Sca) \ PETE_DefineBinaryWithVSTScalars(operator/, OpDivide, Sca) \ PETE_DefineBinaryWithVSTScalars(operator%, OpMod, Sca) \ PETE_DefineBinaryWithVSTScalars(operator<, OpLT, Sca) \ PETE_DefineBinaryWithVSTScalars(operator<=, OpLE, Sca) \ PETE_DefineBinaryWithVSTScalars(operator>, OpGT, Sca) \ PETE_DefineBinaryWithVSTScalars(operator>=, OpGE, Sca) \ PETE_DefineBinaryWithVSTScalars(operator==, OpEQ, Sca) \ PETE_DefineBinaryWithVSTScalars(operator!=, OpNE, Sca) \ PETE_DefineBinaryWithVSTScalars(operator&&, OpAnd, Sca) \ PETE_DefineBinaryWithVSTScalars(operator||, OpOr, Sca) \ PETE_DefineBinaryWithVSTScalars(operator&, OpBitwiseAnd, Sca) \ PETE_DefineBinaryWithVSTScalars(operator|, OpBitwiseOr, Sca) \ PETE_DefineBinaryWithVSTScalars(operator^, OpBitwiseXor, Sca) \ PETE_DefineBinaryWithVSTScalars(copysign, FnCopysign, Sca) \ PETE_DefineBinaryWithVSTScalars(ldexp, FnLdexp, Sca) \ PETE_DefineBinaryWithVSTScalars(pow, FnPow, Sca) \ PETE_DefineBinaryWithVSTScalars(fmod, FnFmod, Sca) \ PETE_DefineBinaryWithVSTScalars(atan2, FnArcTan2, Sca) \ PETE_DefineTrinaryWithVSTScalars(where, OpWhere, Sca) \ PETE_DefineBinaryWithVSTScalars(Min, FnMin, Sca) \ PETE_DefineBinaryWithVSTScalars(Max, FnMax, Sca) \ PETE_DefineBinaryWithVSTScalars(dot, FnDot, Sca) \ PETE_DefineBinaryWithVSTScalars(dotdot, FnDotDot, Sca) \ PETE_DefineBinaryWithVSTScalars(outerProduct, FnOuterProduct, Sca) \ PETE_DefineBinaryWithVSTScalars(cross, FnCross, Sca) \ PETE_DefineBinaryWithVSTScalars(lt, OpLT, Sca) \ PETE_DefineBinaryWithVSTScalars(le, OpLE, Sca) \ PETE_DefineBinaryWithVSTScalars(gt, OpGT, Sca) \ PETE_DefineBinaryWithVSTScalars(ge, OpGE, Sca) \ PETE_DefineBinaryWithVSTScalars(eq, OpEQ, Sca) \ PETE_DefineBinaryWithVSTScalars(ne, OpNE, Sca) PETE_DefineVSTScalar(Vektor) PETE_DefineVSTScalar(SymTenzor) PETE_DefineVSTScalar(Tenzor) #undef PETE_DefineVSTScalar //========================================================================= // // ASSIGNMENT OPERATIONS // //========================================================================= PETE_DefineAssign((a = Min(a,b)),(a = Min(a,b.value)), OpMinAssign) PETE_DefineAssign((a = Max(a,b)),(a = Max(a,b.value)), OpMaxAssign) PETE_DefineAssign((a = (a&&b)) ,(a = (a&&b.value)) , OpAndAssign) PETE_DefineAssign((a = (a||b)) ,(a = (a||b.value)) , OpOrAssign) //========================================================================= // // MIN and MAX REDUCTIONS // //========================================================================= template inline typename T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr& expr) { typename T::PETE_Expr_t::PETE_Return_t val ; Reduction(val, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMinAssign()); return val; } template inline typename T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr& expr) { typename T::PETE_Expr_t::PETE_Return_t val ; Reduction(val, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMaxAssign()); return val; } //========================================================================= // // MINMAX REDUCTION // //========================================================================= template struct MinMaxHolder { T a; T b; MinMaxHolder() { } MinMaxHolder(const MinMaxHolder& rhs) : a(rhs.a), b(rhs.b) { } const MinMaxHolder& operator=(const MinMaxHolder& rhs) { a = rhs.a; b = rhs.b; return *this; } const MinMaxHolder& operator=(const T& rhs) { T c = rhs; a = c; b = c; return *this; } const MinMaxHolder& operator*=(const MinMaxHolder& rhs) { a = (a < rhs.a ? a : rhs.a); b = (rhs.b < b ? b : rhs.b); return *this; } const MinMaxHolder& operator*=(const T& rhs) { T c = rhs; a = (a < c ? a : c); b = (c < b ? b : c); return *this; } Message& putMessage(Message& m) { m.put(a); m.put(b); return m; } Message& getMessage(Message& m) { m.get(a); m.get(b); return m; } }; template inline void minmax(const PETE_Expr& expr, T2& minval, T2& maxval) { typedef typename T1::PETE_Expr_t::PETE_Return_t val_t; MinMaxHolder ret; Reduction(ret, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMultipplyAssign()); minval = static_cast(ret.a); maxval = static_cast(ret.b); } ////////////////////////////////////////////////////////////////////// // // The 'any' function finds if there is any location in the expression // where a condition is true. // ////////////////////////////////////////////////////////////////////// template struct AnyHolder { bool Test; T Val; OP Op; AnyHolder() : Test(false), Val(T(0)), Op(OP()) {} AnyHolder(const T& t, OP op) : Test(false), Val(t), Op(op) {} AnyHolder(const AnyHolder& rhs) : Test(rhs.Test), Val(rhs.Val), Op(rhs.Op) { } const AnyHolder& operator=(const T& rhs) { if ( PETE_apply(Op,rhs,Val) ) Test = true; return *this; } const AnyHolder& operator=(const AnyHolder& rhs) { Test = rhs.Test; Val = rhs.Val; Op = rhs.Op; return *this; } const AnyHolder& operator*=(const T& rhs) { if ( PETE_apply(Op,rhs,Val) ) Test = true; return *this; } const AnyHolder& operator*=(const AnyHolder& rhs) { Test = (Test || rhs.Test); return *this; } Message& putMessage(Message& m) { m.put(Test); return m; } Message& getMessage(Message& m) { m.get(Test); return m; } }; template inline bool any(const PETE_Expr& expr, T2 val) { AnyHolder ret(val,OpEQ()); Reduction(ret, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMultipplyAssign()); return ret.Test; } template inline bool any(const PETE_Expr& expr, T2 val, Op op) { AnyHolder ret(val,op); Reduction(ret, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMultipplyAssign()); return ret.Test; } //========================================================================= // // BOUNDS REDUCTION - find bounding box of Vektor expression // for scalars, use minmax // for tensors, extend this code to include them as well // //========================================================================= template struct BoundsHolder { Vektor a; Vektor b; BoundsHolder() { } BoundsHolder(const BoundsHolder& rhs) : a(rhs.a), b(rhs.b) { } const BoundsHolder& operator=(const BoundsHolder& rhs) { a = rhs.a; b = rhs.b; return *this; } const BoundsHolder& operator=(const Vektor& rhs) { Vektor c(rhs); a = c; b = c; return *this; } const BoundsHolder& operator=(const T& rhs) { Vektor c(rhs); a = c; b = c; return *this; } const BoundsHolder& operator*=(const BoundsHolder& rhs) { for (unsigned int d=0; d < D; ++d) { a[d] = (a[d] < rhs.a[d] ? a[d] : rhs.a[d]); b[d] = (rhs.b[d] < b[d] ? b[d] : rhs.b[d]); } return *this; } const BoundsHolder& operator*=(const Vektor& rhs) { Vektor c(rhs); for (unsigned int d=0; d < D; ++d) { a[d] = (a[d] < c[d] ? a[d] : c[d]); b[d] = (c[d] < b[d] ? b[d] : c[d]); } return *this; } const BoundsHolder& operator*=(const T& rhs) { Vektor c(rhs); for (unsigned int d=0; d < D; ++d) { a[d] = (a[d] < c[d] ? a[d] : c[d]); b[d] = (c[d] < b[d] ? b[d] : c[d]); } return *this; } Message& putMessage(Message& m) { m.put(a); m.put(b); return m; } Message& getMessage(Message& m) { m.get(a); m.get(b); return m; } }; template inline void bounds(const PETE_Expr& expr, Vektor& minval, Vektor& maxval) { BoundsHolder ret; Reduction(ret, Expressionize::apply(expr.PETE_unwrap().MakeExpression()), OpAssign(), OpMultipplyAssign()); minval = ret.a; maxval = ret.b; } //========================================================================= // // OPERATOR() // //========================================================================= template inline typename PETEUnaryReturn >::type PETE_apply(OpParens op, const T& a) { return a(op.Arg); } //========================================================================= // // MISCELLANEOUS // //========================================================================= // When figuring out data dependencies you sometimes need to know // if the left hand side of an assignment needs to be read // before being it is written. // The following trait will set IsAssign to 1 for OpAssign // and to zero for all the other assignment functions. template struct OperatorTraits { enum { IsAssign=0 }; }; template<> struct OperatorTraits { enum { IsAssign=1 }; }; /////////////////////////////////////////////////////////////////////////// // // END OF FILE // /////////////////////////////////////////////////////////////////////////// #endif // IPPL_EXPRESSIONS_H /*************************************************************************** * $RCSfile: IpplExpressions.h,v $ $Author: adelmann $ * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:28 $ * IPPL_VERSION_ID: $Id: IpplExpressions.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $ ***************************************************************************/