realroot_doc 0.1.1
/Users/mourrain/Devel/mmx/realroot/include/realroot/texp_expression.hpp
Go to the documentation of this file.
00001 #ifndef realroot_ARITHM_TEXP_TEMPLATE_EXPRESSION_H
00002 #define realroot_ARITHM_TEXP_TEMPLATE_EXPRESSION_H
00003 #include <iostream>
00004 #include <realroot/assign.hpp>
00005 #include <realroot/texp_sup.hpp>
00006 #include <realroot/texp_structureof.hpp>
00007 
00008 namespace mmx {
00009 
00010 namespace texp {
00011 
00012   template<class F, class X, class Y>
00013   struct operator_iscommutative  
00014   {
00015     enum { V = 0 };
00016     typedef texp::false_t T;
00017   };
00018   // in place example
00019   //  G(r,s,t) (1) ==> r = s; G(r,z) (2)
00020   // (2) is better than (1) if G is "in place" otherwise G(r,z) ==> G(r,s=r,z) (3)
00021   // and (3) is worst than (1).
00022   // note: makes sense if s or t are unevaluated expression, (2) is better because the 
00023   // expression s will be evaluated in the same memory space as the following call to operator.
00024   // note: able to "unroll" (a . b.  c. d) as r = a, r.= b, r .=c, r .=d
00025   template<class F, class X, class Y>
00026   struct operator_isinplace
00027   {
00028     enum { V = 0 };
00029     typedef texp::false_t T;
00030   };
00031   
00032   template<class op, class X>
00033   struct unary_operator_prototype
00034   {
00035     typedef X F;
00036     typedef X U; 
00037   };
00038   
00039   
00040   template<class op, class X, class Y, class SX, class SY>
00041   struct binary_operator_structure_prototype
00042   {
00043     typedef typename sup< X, Y >::T F; 
00044     typedef X                       U;
00045     typedef Y                       V;
00046   };
00047 
00048   template<class op, class X, class Y>
00049   struct binary_operator_prototype
00050   {
00051     typedef binary_operator_structure_prototype< op, X, Y, 
00052                                                  typename structureof<X>::T, 
00053                                                  typename structureof<Y>::T > proto;
00054     typedef typename proto::F F;
00055     typedef typename proto::U U;
00056     typedef typename proto::V V;
00057   };
00058   
00059   template<typename O, typename A>             struct unary_operator  {};
00060   template<typename O, typename A, typename B> struct binary_operator {};
00061   template< class A >
00062   struct template_expression_operand { typedef const A & T; };
00063   template<>
00064   struct template_expression_operand<int> { typedef int  T; };
00065   
00066   template<class A>
00067   struct template_expression 
00068   {
00069     typedef true_t terminal_t;
00070     typedef A            E;
00071     typename template_expression_operand<A>::T  a;
00072     inline const   A & term() const { return a; };
00073     template<class X> operator X() { return X(term()); };
00074     template_expression( const A & a ) : a(a) {};
00075   };
00076   
00077   
00078   template< class O, class A > 
00079   struct template_expression< unary_operator<O,A> > 
00080   {
00081     typedef false_t terminal_t;
00082     typedef typename unary_operator_prototype<O,typename A::E>::F E;
00083     typedef typename unary_operator_prototype<O,typename A::E>::U L;
00084 
00085     A a;
00086     
00087     operator E() 
00088     { 
00089       E tmp; 
00090       eval(tmp); 
00091       return tmp; 
00092     };
00093   
00094     
00095     template<class E> inline template_expression( const E& e ): a(e.a) { };
00096     inline template_expression( const A& _a ): a(_a) {};
00097 
00098     
00099     template<class R>
00100     static inline void  evalterm ( E & r, R & l  ) { L tmp; let::assign(tmp,l); O()(r,l); };
00101     static inline void  evalterm ( E & r, L & l  ) { O()(r,l); };
00102     
00103     inline void  evaltree( E & r ) const 
00104     { 
00105       L tmp; 
00106       a.eval(tmp);
00107       O()(r,tmp);
00108     };
00109     
00110     inline void  eval    ( E & r, const false_t & ) const { evaltree( r );      };
00111     inline void  eval    ( E & r, const true_t& )   const { evalterm( r, a.a ); };
00112     inline void  eval    ( E & r ) const  { eval(r,typename A::terminal_t()); };
00113     template<class R> 
00114     inline void eval( R & r ) const 
00115     { 
00116       E tmp; 
00117       eval(tmp);
00118       let::assign(r,tmp);
00119     };
00120   }; 
00121 
00122 
00123   // evaluation on terminals.
00124 
00125   
00126   template< class O, class A, class B>
00127   struct template_expression< binary_operator< O, A, B > >
00128   {
00129     typedef texp::false_t false_t;
00130     typedef texp::true_t  true_t;
00131     typedef texp::false_t terminal_t;
00132 
00133     A a;
00134     B b;
00135     typedef O Operator;
00136     typedef binary_operator_prototype< O, typename A::E, typename B::E > S;
00137     typedef typename S::F E;
00138     typedef typename S::U L;
00139     typedef typename S::V R;
00140   
00141     inline operator E() { E tmp; eval(tmp); return tmp; };
00142     
00143     inline template_expression(){};
00144     template<class E>
00145     inline template_expression( const E& e ) { a = e.a; b = e.b; };
00146     inline template_expression( const A& _a, const B& _b ) : a(_a), b(_b) {};
00147   
00148     template<class S>
00149     bool operator!=( const S& s )
00150     {
00151       E tmp;
00152       eval(tmp);
00153       return tmp != s;
00154     };
00155     
00156   public:
00157     inline void eval( E & e, const L & l, const R & r ) const { O()(e,l,r); };
00158     
00159     template<class X> inline
00160     void eval( E & r, const  X & a, const R & b )  const
00161     { 
00162       using namespace let;
00163       L _a;
00164       let::assign(_a,a);
00165       O()(r,_a,b);
00166     };
00167     
00168     template<class Y> inline
00169     void eval( E & r, const L & a, const Y & b ) const
00170     {
00171       using namespace let;
00172       R _b;
00173       let::assign(_b,b);
00174       O()(r,a,_b);
00175     };
00176     
00177     template<class X, class Y> inline
00178     void eval( E & r, const X & a, const Y & b ) const
00179     {
00180       L _a;
00181       R _b;
00182       using namespace let;
00183       let::assign(_a,a);
00184       let::assign(_b,b);
00185       O()( r, _a, _b );
00186     };
00187 
00188     inline void _eval_( E& r, const false_t&, const false_t&  ) const
00189     {
00190       /*      if ( isinplace< O, L, R >::V )
00191         { 
00192           a._eval_(r);
00193           R b_;
00194           b.eval(b_);
00195           eval(r,b.a); 
00196         }
00197         else */
00198         { 
00199           L _a; a._eval_(_a);
00200           R _b; b._eval_(_b);
00201           eval(r,_a,_b);
00202         };
00203     };
00204 
00205     inline void eval( E& r, const false_t&, const false_t&  ) const
00206     {
00207       L _a; a._eval_(_a); 
00208       R _b; b._eval_(_b);
00209       eval(r,_a,_b);
00210     };
00211     
00212     inline void _eval_( E & r, const false_t&, const true_t& ) const 
00213     {
00214       /*      if ( isinplace< O, L, R >::V ) (check if E == A::E)
00215         { a._eval_( r ); eval(r,b.a); }
00216       else 
00217       */
00218 
00219         { L _a; a._eval_(_a); eval(r,_a,b.a); };
00220     };
00221     inline void  eval ( E & r, const false_t&, const true_t& ) const 
00222     { 
00223       L _a; 
00224       a._eval_(_a); 
00225       eval(r,_a,b.a); 
00226     };
00227     
00228     inline void _eval_( E & r, const true_t&, const false_t& ) const 
00229     {
00230       /*      if ( isinplace< O, L, R >::V && iscommutative< O, L, R >::V )
00231         {
00232           b._eval_(r);
00233           eval(r,a.a);
00234         }
00235         else */
00236       {
00237         R b_;
00238         b._eval_(b_);
00239         eval(r,a.a,b_);
00240       };
00241     };
00242   
00243     inline void  eval ( E & r, const true_t&, const false_t& ) const 
00244     { R _b; b._eval_(_b); eval(r,a.a,_b); };
00245     
00246   
00247     inline void  eval ( E & r, const true_t& , const true_t& ) const { eval(r,a.a,b.a); };
00248     inline void _eval_( E & r, const true_t& , const true_t& ) const { eval(r,a.a,b.a); };
00249   
00250     
00251     // evaluation on T which is not the result type F of the operator O(A::E,B::E)
00252     template<class T> inline
00253     void eval( T & r ) const
00254     { 
00255       using namespace let;
00256       E tmp; 
00257       _eval_(tmp, typename A::terminal_t(), typename B::terminal_t());
00258       let::assign(r,tmp);
00259     };
00260     // same thing on temporary object
00261     template<class U> inline
00262     void _eval_( U & r ) const 
00263     {
00264       using namespace let;
00265       E tmp;
00266       _eval_(tmp,typename A::terminal_t(), typename B::terminal_t());
00267       let::assign(r,tmp);
00268     };
00269     
00270     inline void eval( E& r ) const { eval( r, typename A::terminal_t(), typename B::terminal_t() ); };
00271     inline void _eval_( E& r ) const { _eval_( r, typename A::terminal_t(), typename B::terminal_t() ); };
00272     //template<class X> operator X() { X tmp; eval(tmp,*this); return tmp; };
00273     /*    operator E() { 
00274           E tmp; 
00275           _eval_(tmp); 
00276           return tmp; 
00277           };
00278     */
00279   };
00280 
00281   
00282   template< class A > inline
00283   std::ostream& operator<<( std::ostream& o, const template_expression<A>& e )
00284   { 
00285     o << (e.a);
00286     return o;
00287   };
00288 
00289   template< class O, class A > inline
00290   std::ostream& operator<<( std::ostream& o, const template_expression< unary_operator< O, A > > & a )
00291   {
00292     return (o << O::name() << "(" << a.a << ")");
00293   };
00294 
00295   template< class O, class A, class B > inline
00296   std::ostream& operator<<( std::ostream& o, const template_expression< binary_operator< O, A, B > >& a )
00297   {
00298     o << O::name() << "(";
00299     o << a.a << "," << a.b << ")";
00300     return o;
00301   };
00302 }
00303 
00304   //using namespace arithm;
00305 
00306 }// end namespace mmx
00307 
00308 #include "texp_operators.hpp"
00309 #include "texp_operators_prototypes.hpp"
00310 
00311 #endif