Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AnalyticExpressionEvaluator.hpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File AnalyticExpressionEvaluator.hpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Parser and evaluator of analytic expressions.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #ifndef _ANALYTIC_EXPRESSION_EVALUATOR_HPP
37 #define _ANALYTIC_EXPRESSION_EVALUATOR_HPP
38 
42 
43 #include <boost/version.hpp>
44 #include <boost/random/mersenne_twister.hpp> // for mt19937
45 #include <boost/random/variate_generator.hpp> // for variate_generator
46 #include <boost/random/normal_distribution.hpp>
47 
48 #if( BOOST_VERSION / 100 % 1000 >= 36 )
49 #include <boost/spirit/include/classic_core.hpp>
50 #include <boost/spirit/include/classic_ast.hpp>
51 #include <boost/spirit/include/classic_symbols.hpp>
52 #include <boost/spirit/include/classic_assign_actor.hpp>
53 #include <boost/spirit/include/classic_push_back_actor.hpp>
54 
55 namespace boost_spirit = boost::spirit::classic;
56 #else
57 #include <boost/spirit/core.hpp>
58 #include <boost/spirit/tree/ast.hpp>
59 #include <boost/spirit/symbols/symbols.hpp>
60 #include <boost/spirit/actor/assign_actor.hpp>
61 #include <boost/spirit/actor/push_back_actor.hpp>
62 
63 namespace boost_spirit = boost::spirit;
64 #endif
65 
66 #include <string>
67 #include <vector>
68 #include <map>
69 #if defined(__INTEL_COMPILER)
70 #include <mathimf.h>
71 #else
72 #include <cmath>
73 #endif
74 
75 namespace Nektar
76 {
77  namespace LibUtilities
78  {
80  {
81  if (x != 0. || y != 0.)
82  return sqrt (x*x + y*y);
83  else
84  return 0.;
85  }
86 
88  {
89  NekDouble theta = 0.;
90  if ((x != 0.) || (y != 0.))
91  theta = atan2 (y,x);
92  return theta;
93  }
94 
95  /// This class defines evaluator of analytic (symbolic)
96  /// mathematical expressions. Expressions are allowed to
97  /// depend on a number of spatial-time variables and
98  /// parameters. Pre-processing and evaluation stages are
99  /// split. At evaluation stage one specifies values for
100  /// each variable, resulting expression value is returned.
101  /// Vectorized evaluator (evaluate expression at a set of
102  /// points) is available.
103  ///
104  /// Internally this class uses boost::spirit to parse analytic
105  /// expressions and unrolls their recursive bracketing structure
106  /// into a sequence of evaluation steps (aka execution stack)
107  /// with resolved data dependencies. Once an expression is
108  /// pre-processed, its execution stack is stored internally
109  /// in order to be re-used.
110 
112  {
113 
114  private:
115 
117 
118  public:
119 
120 
121  typedef std::map<std::string, int> VariableMap;
122  typedef std::map<std::string, int> ConstantMap;
123  typedef std::map<std::string, int> ParameterMap;
124  typedef std::map<std::string, int> ExpressionMap;
125  typedef std::map<std::string, int> FunctionNameMap;
126  typedef std::vector<EvaluationStep*> ExecutionStack;
127  typedef std::pair<bool, NekDouble> PrecomputedValue;
130 
131  typedef boost_spirit::tree_parse_info<
132  std::string::const_iterator,
133  boost_spirit::node_val_data_factory<NekDouble>
135  typedef boost_spirit::tree_match<
136  std::string::const_iterator,
137  boost_spirit::node_val_data_factory<NekDouble>
138  >::tree_iterator ParsedTreeIterator;
139 
140  typedef std::vector<const Array<OneD, const NekDouble>* > VariableArray;
141 
142  typedef boost::mt19937 RandomGeneratorType;
143 
144 
145  // ======================================
146  // Methods
147  // ======================================
148 
149 
150  /// Initializes the evaluator to a state where it is ready to accept input
151  /// from the #DefineFunction function.
153 
154  /// Destroys the execution stack.
156 
157 
158  // ======================================
159  // Setting up methods
160  // ======================================
161 
162 
163  LIB_UTILITIES_EXPORT void SetRandomSeed(unsigned int seed = 123u);
164 
165  /// Constants are evaluated and inserted into the function at the time it is parsed
166  /// when calling the #DefineFunction function. After parsing, if a constant is
167  /// changed, it will not be reflected in the function when Evaluate is called. This
168  /// also means that if a function with an unknown constant is added, and then the
169  /// constant is added, the function will not see the added constant and through an
170  /// exception. This function will add all of the constants in the map argument to
171  /// the global internal constants. If a constant was already loaded previously, it will
172  /// throw an exception stating which constants in the map had this issue. It will add
173  /// all of the constants it can and output the constants it couldn't add in the string
174  /// exception.
175  LIB_UTILITIES_EXPORT void AddConstants(std::map<std::string, NekDouble> const& constants);
176 
177  /// This function behaves in the same way as #AddConstants, but it only adds one
178  /// constant at a time. If the constant existed previously, an exception will be thrown
179  /// stating the fact. If it did not exist previously, it will be added to the global
180  /// constants and will be used the next time #DefineFunction is called.
181  LIB_UTILITIES_EXPORT int AddConstant(std::string const& name, NekDouble value);
182 
183  /// If a constant with the specified name exists, it returns the NekDouble value that the
184  /// constant stores. If the constant doesn't exist, it throws an exception.
185  LIB_UTILITIES_EXPORT NekDouble GetConstant(std::string const& name);
186 
187  /// Parameters are like constants, but they are inserted into the function at the time
188  /// #Evaluate is called instead of when the function is parsed. This function can
189  /// be called at any time, and it will take effect in the next call to #Evaluate.
190  /// This function will delete all of the parameters, and replace all of them with only
191  /// the ones in the map argument.
192  LIB_UTILITIES_EXPORT void SetParameters(std::map<std::string, NekDouble> const& params);
193 
194  /// This function behaves in the same way as #SetParameters, but it only adds one
195  /// parameter and it does not delete the others. If the parameter existed previously,
196  /// it will be overridden and replaced with the new value. If it did not exist previously,
197  /// it will be added to the current parameters.
198  LIB_UTILITIES_EXPORT void SetParameter(std::string const& name, NekDouble value);
199 
200  /// If a parameter with the specified name exists, it returns the NekDouble value that the
201  /// parameter stores. If the parameter doesn't exist, it throws an exception.
202  LIB_UTILITIES_EXPORT NekDouble GetParameter(std::string const& name);
203 
204  /// Returns the total time spent in evaluation procedures, seconds.
206 
207 
208  // ======================================================
209  // Parsing and evaluation methods
210  // ======================================================
211 
212 
213  /// This function allows one to define a function to evaluate. The first argument (vlist)
214  /// is a list of variables (separated by spaces) that the second argument (function)
215  /// depends on. For example, if function = "x + y", then vlist should most likely be
216  /// "x y", unless you are defining x or y as parameters with #SetParameters.
217  /// \output parsed expression ID. You will need this expression id to call evaluation
218  /// methods below.
219  LIB_UTILITIES_EXPORT int DefineFunction(const std::string& vlist, const std::string& function);
220 
221 
222  /// Evaluation method for expressions depending on parameters only.
223  LIB_UTILITIES_EXPORT NekDouble Evaluate(const int AnalyticExpression_id);
224 
225  /// Evaluation method for expressions depending on 4 variables (+parameters).
227  const int AnalyticExpression_id,
228  const NekDouble,
229  const NekDouble,
230  const NekDouble,
231  const NekDouble);
232 
233  /// Evaluation method for expressions depending on unspecified number of variables.
234  /// This suitable for expressions depending on more than 4 variables or for the dynamic
235  /// setting some variables as parameters (there is currently no interface method
236  /// for removing a variable from parameter map though).
238  const int AnalyticExpression_id,
239  std::vector<NekDouble> point);
240 
241  /// Vectorized evaluation method for expressions depending on 4 variables.
243  const int expression_id,
244  const Array<OneD, const NekDouble>&,
245  const Array<OneD, const NekDouble>&,
246  const Array<OneD, const NekDouble>&,
247  const Array<OneD, const NekDouble>&,
248  Array<OneD, NekDouble>& result);
249 
250 
251 
252  /// Vectorized evaluation method for expressions depending on unspecified
253  /// number of variables.
255  const int expression_id,
256  const std::vector<Array<OneD, const NekDouble> > points,
257  Array<OneD, NekDouble>& result);
258 
259  private:
260 
261  // ======================================================
262  // Private parsing and partial evaluation method
263  // ======================================================
264 
265  /// This method prepares the execution stack (an ordered sequence of
266  /// operators that perform the evaluation) for the parsed evaluation tree.
267  ///
268  /// In order to do this, it unrolls binary tree representing
269  /// the recursive evaluation into an ordered sequence of commands.
270  /// That ordered sequence of commands is equivalent to bottom-up
271  /// walk up the evaluation tree, but this allows not to form tree explicitly.
272  ///
273  /// This approach requires to introduce explicitly an execution state
274  /// (memory) shared by commands in the evaluation sequence: recursively
275  /// dependent commands need to pass data between each other. Such state
276  /// for the recursive evaluation is passed via return values of a recursive
277  /// evaluation function --- which is bad if one wants to implement vectorized
278  /// evaluator.
279  ///
280  /// On the other hand, to run through a sequential container of
281  /// functors is faster than to walk the tree and at each node to check
282  /// the node type.
283  ///
284  /// \input root - iterator generated by boost::spirit;
285  /// stack - initially empty sequential container of evaluation steps;
286  /// varMap - maps variable names to their ids;
287  /// stateIndex - an index in state[] array where an evaluation
288  /// step corresponding to the current tree node
289  /// is allowed to write.
290  /// \output an std::pair<bool, NekDouble> which encodes fully pre-evaluated
291  /// NekDouble value as pair <true, value> if all sub-tree down the
292  /// current node evaluates to constant, or flags the opposite
293  /// via pair <false,0>.
295  const ParsedTreeIterator& root,
296  ExecutionStack& stack,
297  VariableMap &varMap,
298  int stateIndex);
299 
300 
301  // ======================================================
302  // Boost::spirit related data structures
303  // ======================================================
304 
305 
306  /** This is a parser for spirit that parses the CONSTANT values. The default
307  constants are those that are in math.h without the M_ prefix and they are
308  initialized in the AnalyticExpressionEvaluator constructor. **/
309 
310  boost_spirit::symbols<NekDouble> m_constantsParser;
311 
312 
313  /** This is the class that is used as the grammar parser for the spirit engine. **/
314  class AnalyticExpression : public boost_spirit::grammar<AnalyticExpression>
315  {
316  private:
317  const boost_spirit::symbols<NekDouble>* constants_p;
318 
319  /** Variables is a customized parser that will match the variables that the function
320  depends on (the first argument of #DefineFunction). **/
321  struct variables : boost_spirit::symbols<NekDouble*>
322  {
323  variables(std::vector<std::string> const& vars)
324  {
325  for (std::vector<std::string>::const_iterator it = vars.begin(); it != vars.end(); it++)
326  add(it->c_str(), 0);
327  }
328  } variables_p;
329 
330  public:
331  /** These constants are used to determine what parser was used to parse what value,
332  which allows for type identification when analyzing the parsed AST. **/
333  static const int constantID = 1;
334  static const int numberID = 2;
335  static const int variableID = 3;
336  static const int parameterID = 4;
337  static const int functionID = 5;
338  static const int factorID = 6;
339  static const int operatorID = 7;
340 
341  AnalyticExpression(const boost_spirit::symbols<NekDouble>* constants, const std::vector<std::string>& variables) :
342  boost_spirit::grammar<AnalyticExpression>(), constants_p(constants), variables_p(variables) {}
343 
344  // Trivial constructor to avoid compiler warning with
345  // constants_p.
347  {
348  constants_p = NULL;
349  }
350 
351  template <typename ScannerT>
352  struct definition
353  {
354  /** This function specifies the grammar of the MathAnalyticExpression parser. **/
355  definition(AnalyticExpression const& self);
356 
357  /** This holds the NekDouble value that is parsed by spirit so it can be stored in the AST. **/
359 
360  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<constantID> > constant;
361  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<numberID> > number;
362  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<variableID> > variable;
363  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<parameterID> > parameter;
364  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<functionID> > function;
365  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<factorID> > factor;
366  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > exponential;
367  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > mult_div;
368  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > add_sub;
369  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > lt_gt;
370  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > equality;
371  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > logical_and;
372  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > logical_or;
373  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > expression;
374  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > op;
375 
376  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > const&
377  start() const { return expression; }
378  };
379  }; // class AnalyticExpression
380 
381 
382 
383  // ======================================================
384  // Pre-processed expressions
385  // ======================================================
386 
387  /// These vector and map store pre-processed evaluation sequences
388  /// for the analytic expressions. Each ExecutionStack is an ordered
389  /// container of steps of sequential execution process which
390  /// evaluates an analytic expression.
391 
393  std::vector<ExecutionStack> m_executionStack;
394 
395  /// Keeping map of variables individually per each analytic expression
396  /// allows correctly handling expressions which depend on different
397  /// number of variables.
398 
399  std::vector<VariableMap> m_stackVariableMap;
400 
401  // ======================================================
402  // Execution state and data
403  // ======================================================
404 
405  /// The following data structures hold input data to be used on evaluation
406  /// stage. There are three types of input data:
407  /// - constants (never change their value)
408  /// - parameters are allowed to change their values between evaluations
409  /// (compared to constants)
410  /// - variables always change their values at every evaluation call.
411  /// First map looks like <parameter_name, parameter_id> while the second is
412  /// <parameter_id, parameter_value>. The map is used at a preparation
413  /// stage when the analytic expression is parsed. This associates an integer
414  /// id with a parameter name in its string form. On evaluation stage the id
415  /// and a std::vector constant lookup time make evaluation faster compared
416  /// to permanent std::map<std::string, NekDouble> lookup.
417 
421 
422  std::vector<NekDouble> m_parameter;
423  std::vector<NekDouble> m_constant;
424  std::vector<NekDouble> m_variable;
425 
426 
427  /// This vector stores the execution state (memory) used by the
428  /// sequential execution process.
429  std::vector<NekDouble> m_state;
430 
431  /// Vector of state sizes per each
432  std::vector<int> m_state_sizes;
433 
434  /// This counter is used by PrepareExecutionAsYouParse for finding
435  /// the minimal state size necessary for evaluation of function parsed.
437 
438 
439  /// Timer and sum of evaluation times
442 
443 
445  // boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
446  // m_normal;
447 
448 
449 
450  // ======================================================
451  // A map of (external) mathematical functions
452  // ======================================================
453 
454 
456  std::map<int, OneArgFunc> m_function;
457  std::map<int, TwoArgFunc> m_function2;
458 
459 
460  // ======================================================
461  // Internal representation of evaluation step
462  // ======================================================
463 
464  /// Short names to minimise the infractructural code mess in defining functors below.
465  typedef std::vector<NekDouble>& vr;
466  typedef const std::vector<NekDouble>& cvr;
467  typedef const int ci;
469 
470  /// Factory method which makes code little less messy
471  template<typename StepType>
472  EvaluationStep* makeStep(ci dest, ci src_left = 0, ci src_right = 0)
473  {
474  return ( new StepType ( m_generator,m_state,m_constant,m_parameter,m_variable,dest,src_left,src_right ) );
475  }
476 
478  {
483  };
484 
485 
486 
487  /// Function objects (functors)
489  {
490  /// reference to random number generator
492 
493  /// references to arrays holding the common state
498 
499  /// indices in the above arrays uniquely defining actual command arguments
503 
504  EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v):
505  rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i), argIdx1(l), argIdx2(r) {};
506 
507  virtual ~EvaluationStep() {}
508 
509  /// declaring this guy pure virtual shortens virtual table. It saves some execution time.
510  virtual void run_many(ci n) = 0;
511  virtual void run_once() = 0;
512  };
513  struct CopyState: public EvaluationStep
514  {
515  CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
516  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1]; }
517  virtual void run_once() { state[storeIdx] = state[argIdx1]; }
518  };
519  struct StoreConst: public EvaluationStep
520  {
521  StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
522  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = consts[argIdx1]; }
523  virtual void run_once() { state[storeIdx] = consts[argIdx1]; }
524  };
525  struct StoreVar: public EvaluationStep
526  {
527  StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
528  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = vars[argIdx1*n+i]; }
529  virtual void run_once() { state[storeIdx] = vars[argIdx1]; }
530  };
531  struct StorePrm: public EvaluationStep
532  {
533  StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
534  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = params[argIdx1]; }
535  virtual void run_once() { state[storeIdx] = params[argIdx1]; }
536  };
537  struct EvalSum: public EvaluationStep
538  {
539  EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
540  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1*n+i] + state[argIdx2*n+i]; }
541  virtual void run_once() { state[storeIdx] = state[argIdx1] + state[argIdx2]; }
542  };
543  struct EvalSub: public EvaluationStep
544  {
545  EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
546  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1*n+i] - state[argIdx2*n+i]; }
547  virtual void run_once() { state[storeIdx] = state[argIdx1] - state[argIdx2]; }
548  };
549  struct EvalMul: public EvaluationStep
550  {
551  EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
552  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1*n+i] * state[argIdx2*n+i]; }
553  virtual void run_once() { state[storeIdx] = state[argIdx1] * state[argIdx2]; }
554  };
555  struct EvalDiv: public EvaluationStep
556  {
557  EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
558  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1*n+i] / state[argIdx2*n+i]; }
559  virtual void run_once() { state[storeIdx] = state[argIdx1] / state[argIdx2]; }
560  };
561  struct EvalPow: public EvaluationStep
562  {
563  EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
564  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::pow( state[argIdx1*n+i], state[argIdx2*n+i] ); }
565  virtual void run_once() { state[storeIdx] = std::pow( state[argIdx1], state[argIdx2] ); }
566  };
567  struct EvalNeg: public EvaluationStep
568  {
569  EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
570  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = - state[argIdx1*n+i]; }
571  virtual void run_once() { state[storeIdx] = - state[argIdx1]; }
572  };
574  {
575  EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
576  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ( state[argIdx1*n+i] == state[argIdx2*n+i] ); }
577  virtual void run_once() { state[storeIdx] = ( state[argIdx1] == state[argIdx2] ); }
578  };
580  {
581  EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
582  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ( state[argIdx1*n+i] <= state[argIdx2*n+i] ); }
583  virtual void run_once() { state[storeIdx] = ( state[argIdx1] <= state[argIdx2] ); }
584  };
586  {
587  EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
588  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ( state[argIdx1*n+i] < state[argIdx2*n+i] ); }
589  virtual void run_once() { state[storeIdx] = ( state[argIdx1] < state[argIdx2] ); }
590  };
592  {
593  EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
594  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ( state[argIdx1*n+i] >= state[argIdx2*n+i] ); }
595  virtual void run_once() { state[storeIdx] = ( state[argIdx1] >= state[argIdx2] ); }
596  };
598  {
599  EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
600  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ( state[argIdx1*n+i] > state[argIdx2*n+i] ); }
601  virtual void run_once() { state[storeIdx] = ( state[argIdx1] > state[argIdx2] ); }
602  };
603  struct EvalAbs: public EvaluationStep
604  {
605  EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
606  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::abs( state[argIdx1*n+i] ); }
607  virtual void run_once() { state[storeIdx] = std::abs( state[argIdx1] ); }
608  };
609  struct EvalSign: public EvaluationStep
610  {
611  EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
612  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ((state[argIdx1*n+i] > 0.0) - (state[argIdx1*n+i] < 0.0)); }
613  virtual void run_once() { state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0)); }
614  };
615  struct EvalAsin: public EvaluationStep
616  {
617  EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
618  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::asin( state[argIdx1*n+i] ); }
619  virtual void run_once() { state[storeIdx] = std::asin( state[argIdx1] ); }
620  };
621  struct EvalAcos: public EvaluationStep
622  {
623  EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
624  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::acos( state[argIdx1*n+i] ); }
625  virtual void run_once() { state[storeIdx] = std::acos( state[argIdx1] ); }
626  };
627  struct EvalAtan: public EvaluationStep
628  {
629  EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
630  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::atan( state[argIdx1*n+i] ); }
631  virtual void run_once() { state[storeIdx] = std::atan( state[argIdx1] ); }
632  };
633  struct EvalAtan2: public EvaluationStep
634  {
635  EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
636  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::atan2( state[argIdx1*n+i], state[argIdx2*n+i] ); }
637  virtual void run_once() { state[storeIdx] = std::atan2( state[argIdx1], state[argIdx2] ); }
638  };
639  struct EvalAng: public EvaluationStep
640  {
641  EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
642  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = ang( state[argIdx1*n+i], state[argIdx2*n+i] ); }
643  virtual void run_once() { state[storeIdx] = ang( state[argIdx1], state[argIdx2] ); }
644  };
645  struct EvalCeil: public EvaluationStep
646  {
647  EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
648  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::ceil( state[argIdx1*n+i] ); }
649  virtual void run_once() { state[storeIdx] = std::ceil( state[argIdx1] ); }
650  };
651  struct EvalCos: public EvaluationStep
652  {
653  EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
654  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::cos( state[argIdx1*n+i] ); }
655  virtual void run_once() { state[storeIdx] = std::cos( state[argIdx1] ); }
656  };
657  struct EvalCosh: public EvaluationStep
658  {
659  EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
660  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::cosh( state[argIdx1*n+i] ); }
661  virtual void run_once() { state[storeIdx] = std::cosh( state[argIdx1] ); }
662  };
663  struct EvalExp: public EvaluationStep
664  {
665  EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
666  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::exp( state[argIdx1*n+i] ); }
667  virtual void run_once() { state[storeIdx] = std::exp( state[argIdx1] ); }
668  };
669  struct EvalFabs: public EvaluationStep
670  {
671  EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
672  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::fabs( state[argIdx1*n+i] ); }
673  virtual void run_once() { state[storeIdx] = std::fabs( state[argIdx1] ); }
674  };
675  struct EvalFloor: public EvaluationStep
676  {
677  EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
678  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::floor( state[argIdx1*n+i] ); }
679  virtual void run_once() { state[storeIdx] = std::floor( state[argIdx1] ); }
680  };
681  struct EvalLog: public EvaluationStep
682  {
683  EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
684  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::log( state[argIdx1*n+i] ); }
685  virtual void run_once() { state[storeIdx] = std::log( state[argIdx1] ); }
686  };
687  struct EvalLog10: public EvaluationStep
688  {
689  EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
690  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::log10( state[argIdx1*n+i] ); }
691  virtual void run_once() { state[storeIdx] = std::log10( state[argIdx1] ); }
692  };
693  struct EvalRad: public EvaluationStep
694  {
695  EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
696  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = rad( state[argIdx1*n+i], state[argIdx2*n+i] ); }
697  virtual void run_once() { state[storeIdx] = rad( state[argIdx1], state[argIdx2] ); }
698  };
699  struct EvalSin: public EvaluationStep
700  {
701  EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
702  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sin( state[argIdx1*n+i] ); }
703  virtual void run_once() { state[storeIdx] = std::sin( state[argIdx1] ); }
704  };
705  struct EvalSinh: public EvaluationStep
706  {
707  EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
708  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sinh( state[argIdx1*n+i] ); }
709  virtual void run_once() { state[storeIdx] = std::sinh( state[argIdx1] ); }
710  };
711  struct EvalSqrt: public EvaluationStep
712  {
713  EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
714  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sqrt( state[argIdx1*n+i] ); }
715  virtual void run_once() { state[storeIdx] = std::sqrt( state[argIdx1] ); }
716  };
717  struct EvalTan: public EvaluationStep
718  {
719  EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
720  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::tan( state[argIdx1*n+i] ); }
721  virtual void run_once() { state[storeIdx] = std::tan( state[argIdx1] ); }
722  };
723  struct EvalTanh: public EvaluationStep
724  {
725  EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
726  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::tanh( state[argIdx1*n+i] ); }
727  virtual void run_once() { state[storeIdx] = std::tanh( state[argIdx1] ); }
728  };
729  struct EvalAWGN: public EvaluationStep
730  {
731  EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r): EvaluationStep(rn,i,l,r,s,c,p,v) {}
732  virtual void run_many(ci n)
733  {
734  // assuming the argument to AWGN does not depend on spatial variables =>
735  boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
736  _normal(rng, boost::normal_distribution<>(0, state[storeIdx*n]) );
737  for(int i=0;i<n;i++) { state[storeIdx*n+i] = _normal(); }
738  }
739  virtual void run_once()
740  {
741  boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
742  _normal(rng, boost::normal_distribution<>(0, state[storeIdx]) );
743  state[storeIdx] = _normal();
744  }
745  };
746 
747  };
748  };
749 };
750 
751 #endif // _ANALYTIC_EXPRESSION_EVALUATOR_HPP