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 
49 #if( BOOST_VERSION / 100 % 1000 >= 36 )
50 #include <boost/spirit/include/classic_core.hpp>
51 #include <boost/spirit/include/classic_ast.hpp>
52 #include <boost/spirit/include/classic_symbols.hpp>
53 #include <boost/spirit/include/classic_assign_actor.hpp>
54 #include <boost/spirit/include/classic_push_back_actor.hpp>
55 
56 namespace boost_spirit = boost::spirit::classic;
57 #else
58 #include <boost/spirit/core.hpp>
59 #include <boost/spirit/tree/ast.hpp>
60 #include <boost/spirit/symbols/symbols.hpp>
61 #include <boost/spirit/actor/assign_actor.hpp>
62 #include <boost/spirit/actor/push_back_actor.hpp>
63 
64 namespace boost_spirit = boost::spirit;
65 #endif
66 
67 #include <string>
68 #include <vector>
69 #include <map>
70 #if defined(__INTEL_COMPILER)
71 #include <mathimf.h>
72 #else
73 #include <cmath>
74 #endif
75 
76 namespace Nektar
77 {
78  namespace LibUtilities
79  {
80 
81 
82  /// This class defines evaluator of analytic (symbolic)
83  /// mathematical expressions. Expressions are allowed to
84  /// depend on a number of spatial-time variables and
85  /// parameters. Pre-processing and evaluation stages are
86  /// split. At evaluation stage one specifies values for
87  /// each variable, resulting expression value is returned.
88  /// Vectorized evaluator (evaluate expression at a set of
89  /// points) is available.
90  ///
91  /// Internally this class uses boost::spirit to parse analytic
92  /// expressions and unrolls their recursive bracketing structure
93  /// into a sequence of evaluation steps (aka execution stack)
94  /// with resolved data dependencies. Once an expression is
95  /// pre-processed, its execution stack is stored internally
96  /// in order to be re-used.
97 
99  {
100 
101  private:
102 
104 
105  public:
106 
107 
108  typedef std::map<std::string, int> VariableMap;
109  typedef std::map<std::string, int> ConstantMap;
110  typedef std::map<std::string, int> ParameterMap;
111  typedef std::map<std::string, int> ExpressionMap;
112  typedef std::map<std::string, int> FunctionNameMap;
113  typedef std::vector<EvaluationStep*> ExecutionStack;
114  typedef std::pair<bool, NekDouble> PrecomputedValue;
116 
117  typedef boost_spirit::tree_parse_info<
118  std::string::const_iterator,
119  boost_spirit::node_val_data_factory<NekDouble>
121  typedef boost_spirit::tree_match<
122  std::string::const_iterator,
123  boost_spirit::node_val_data_factory<NekDouble>
124  >::tree_iterator ParsedTreeIterator;
125 
126  typedef std::vector<const Array<OneD, const NekDouble>* > VariableArray;
127 
128  typedef boost::mt19937 RandomGeneratorType;
129 
130 
131  // ======================================
132  // Methods
133  // ======================================
134 
135 
136  /// Initializes the evaluator to a state where it is ready to accept input
137  /// from the #DefineFunction function.
139 
140  /// Destroys the execution stack.
142 
143 
144  // ======================================
145  // Setting up methods
146  // ======================================
147 
148 
149  LIB_UTILITIES_EXPORT void SetRandomSeed(unsigned int seed = 123u);
150 
151  /// Constants are evaluated and inserted into the function at the time it is parsed
152  /// when calling the #DefineFunction function. After parsing, if a constant is
153  /// changed, it will not be reflected in the function when Evaluate is called. This
154  /// also means that if a function with an unknown constant is added, and then the
155  /// constant is added, the function will not see the added constant and through an
156  /// exception. This function will add all of the constants in the map argument to
157  /// the global internal constants. If a constant was already loaded previously, it will
158  /// throw an exception stating which constants in the map had this issue. It will add
159  /// all of the constants it can and output the constants it couldn't add in the string
160  /// exception.
161  LIB_UTILITIES_EXPORT void AddConstants(std::map<std::string, NekDouble> const& constants);
162 
163  /// This function behaves in the same way as #AddConstants, but it only adds one
164  /// constant at a time. If the constant existed previously, an exception will be thrown
165  /// stating the fact. If it did not exist previously, it will be added to the global
166  /// constants and will be used the next time #DefineFunction is called.
167  LIB_UTILITIES_EXPORT int AddConstant(std::string const& name, NekDouble value);
168 
169  /// If a constant with the specified name exists, it returns the NekDouble value that the
170  /// constant stores. If the constant doesn't exist, it throws an exception.
171  LIB_UTILITIES_EXPORT NekDouble GetConstant(std::string const& name);
172 
173  /// Parameters are like constants, but they are inserted into the function at the time
174  /// #Evaluate is called instead of when the function is parsed. This function can
175  /// be called at any time, and it will take effect in the next call to #Evaluate.
176  /// This function will delete all of the parameters, and replace all of them with only
177  /// the ones in the map argument.
178  LIB_UTILITIES_EXPORT void SetParameters(std::map<std::string, NekDouble> const& params);
179 
180  /// This function behaves in the same way as #SetParameters, but it only adds one
181  /// parameter and it does not delete the others. If the parameter existed previously,
182  /// it will be overridden and replaced with the new value. If it did not exist previously,
183  /// it will be added to the current parameters.
184  LIB_UTILITIES_EXPORT void SetParameter(std::string const& name, NekDouble value);
185 
186  /// If a parameter with the specified name exists, it returns the NekDouble value that the
187  /// parameter stores. If the parameter doesn't exist, it throws an exception.
188  LIB_UTILITIES_EXPORT NekDouble GetParameter(std::string const& name);
189 
190  /// Returns the total time spent in evaluation procedures, seconds.
192 
193 
194  // ======================================================
195  // Parsing and evaluation methods
196  // ======================================================
197 
198 
199  /// This function allows one to define a function to evaluate. The first argument (vlist)
200  /// is a list of variables (separated by spaces) that the second argument (function)
201  /// depends on. For example, if function = "x + y", then vlist should most likely be
202  /// "x y", unless you are defining x or y as parameters with #SetParameters.
203  /// \output parsed expression ID. You will need this expression id to call evaluation
204  /// methods below.
205  LIB_UTILITIES_EXPORT int DefineFunction(const std::string& vlist, const std::string& function);
206 
207 
208  /// Evaluation method for expressions depending on parameters only.
209  LIB_UTILITIES_EXPORT NekDouble Evaluate(const int AnalyticExpression_id);
210 
211  /// Evaluation method for expressions depending on 4 variables (+parameters).
213  const int AnalyticExpression_id,
214  const NekDouble,
215  const NekDouble,
216  const NekDouble,
217  const NekDouble);
218 
219  /// Evaluation method for expressions depending on unspecified number of variables.
220  /// This suitable for expressions depending on more than 4 variables or for the dynamic
221  /// setting some variables as parameters (there is currently no interface method
222  /// for removing a variable from parameter map though).
224  const int AnalyticExpression_id,
225  std::vector<NekDouble> point);
226 
227  /// Vectorized evaluation method for expressions depending on 4 variables.
229  const int expression_id,
230  const Array<OneD, const NekDouble>&,
231  const Array<OneD, const NekDouble>&,
232  const Array<OneD, const NekDouble>&,
233  const Array<OneD, const NekDouble>&,
234  Array<OneD, NekDouble>& result);
235 
236  /// Vectorized evaluation method for expressions depending on unspecified
237  /// number of variables.
239  const int expression_id,
240  const std::vector<Array<OneD, const NekDouble> > points,
241  Array<OneD, NekDouble>& result);
242 
243  private:
244 
245  // ======================================================
246  // Private parsing and partial evaluation method
247  // ======================================================
248 
249  /// This method prepares the execution stack (an ordered sequence of
250  /// operators that perform the evaluation) for the parsed evaluation tree.
251  ///
252  /// In order to do this, it unrolls binary tree representing
253  /// the recursive evaluation into an ordered sequence of commands.
254  /// That ordered sequence of commands is equivalent to bottom-up
255  /// walk up the evaluation tree, but this allows not to form tree explicitly.
256  ///
257  /// This approach requires to introduce explicitly an execution state
258  /// (memory) shared by commands in the evaluation sequence: recursively
259  /// dependent commands need to pass data between each other. Such state
260  /// for the recursive evaluation is passed via return values of a recursive
261  /// evaluation function --- which is bad if one wants to implement vectorized
262  /// evaluator.
263  ///
264  /// On the other hand, to run through a sequential container of
265  /// functors is faster than to walk the tree and at each node to check
266  /// the node type.
267  ///
268  /// \input root - iterator generated by boost::spirit;
269  /// stack - initially empty sequential container of evaluation steps;
270  /// varMap - maps variable names to their ids;
271  /// stateIndex - an index in state[] array where an evaluation
272  /// step corresponding to the current tree node
273  /// is allowed to write.
274  /// \output an std::pair<bool, NekDouble> which encodes fully pre-evaluated
275  /// NekDouble value as pair <true, value> if all sub-tree down the
276  /// current node evaluates to constant, or flags the opposite
277  /// via pair <false,0>.
279  const ParsedTreeIterator& root,
280  ExecutionStack& stack,
281  VariableMap &varMap,
282  int stateIndex);
283 
284 
285  // ======================================================
286  // Boost::spirit related data structures
287  // ======================================================
288 
289 
290  /** This is a parser for spirit that parses the CONSTANT values. The default
291  constants are those that are in math.h without the M_ prefix and they are
292  initialized in the AnalyticExpressionEvaluator constructor. **/
293 
294  boost_spirit::symbols<NekDouble> m_constantsParser;
295 
296 
297  /** This is the class that is used as the grammar parser for the spirit engine. **/
298  class AnalyticExpression : public boost_spirit::grammar<AnalyticExpression>
299  {
300  private:
301  const boost_spirit::symbols<NekDouble>* constants_p;
302 
303  /** Variables is a customized parser that will match the variables that the function
304  depends on (the first argument of #DefineFunction). **/
305  struct variables : boost_spirit::symbols<NekDouble*>
306  {
307  variables(std::vector<std::string> const& vars)
308  {
309  for (std::vector<std::string>::const_iterator it = vars.begin(); it != vars.end(); it++)
310  add(it->c_str(), 0);
311  }
312  } variables_p;
313 
314  public:
315  /** These constants are used to determine what parser was used to parse what value,
316  which allows for type identification when analyzing the parsed AST. **/
317  static const int constantID = 1;
318  static const int numberID = 2;
319  static const int variableID = 3;
320  static const int parameterID = 4;
321  static const int functionID = 5;
322  static const int factorID = 6;
323  static const int operatorID = 7;
324 
325  AnalyticExpression(const boost_spirit::symbols<NekDouble>* constants, const std::vector<std::string>& variables) :
326  boost_spirit::grammar<AnalyticExpression>(), constants_p(constants), variables_p(variables) {}
327 
328  // Trivial constructor to avoid compiler warning with
329  // constants_p.
331  {
332  constants_p = NULL;
333  }
334 
335  template <typename ScannerT>
336  struct definition
337  {
338  /** This function specifies the grammar of the MathAnalyticExpression parser. **/
339  definition(AnalyticExpression const& self);
340 
341  /** This holds the NekDouble value that is parsed by spirit so it can be stored in the AST. **/
343 
344  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<constantID> > constant;
345  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<numberID> > number;
346  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<variableID> > variable;
347  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<parameterID> > parameter;
348  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<functionID> > function;
349  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<factorID> > factor;
350  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > exponential;
351  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > mult_div;
352  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > add_sub;
353  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > lt_gt;
354  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > equality;
355  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > logical_and;
356  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > logical_or;
357  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > expression;
358  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > op;
359 
360  boost_spirit::rule<ScannerT, boost_spirit::parser_context<>, boost_spirit::parser_tag<operatorID> > const&
361  start() const { return expression; }
362  };
363  }; // class AnalyticExpression
364 
365 
366 
367  // ======================================================
368  // Pre-processed expressions
369  // ======================================================
370 
371  /// These vector and map store pre-processed evaluation sequences
372  /// for the analytic expressions. Each ExecutionStack is an ordered
373  /// container of steps of sequential execution process which
374  /// evaluates an analytic expression.
375 
377  std::vector<ExecutionStack> m_executionStack;
378 
379  /// Keeping map of variables individually per each analytic expression
380  /// allows correctly handling expressions which depend on different
381  /// number of variables.
382 
383  std::vector<VariableMap> m_stackVariableMap;
384 
385  // ======================================================
386  // Execution state and data
387  // ======================================================
388 
389  /// The following data structures hold input data to be used on evaluation
390  /// stage. There are three types of input data:
391  /// - constants (never change their value)
392  /// - parameters are allowed to change their values between evaluations
393  /// (compared to constants)
394  /// - variables always change their values at every evaluation call.
395  /// First map looks like <parameter_name, parameter_id> while the second is
396  /// <parameter_id, parameter_value>. The map is used at a preparation
397  /// stage when the analytic expression is parsed. This associates an integer
398  /// id with a parameter name in its string form. On evaluation stage the id
399  /// and a std::vector constant lookup time make evaluation faster compared
400  /// to permanent std::map<std::string, NekDouble> lookup.
401 
405 
406  std::vector<NekDouble> m_parameter;
407  std::vector<NekDouble> m_constant;
408  std::vector<NekDouble> m_variable;
409 
410 
411  /// This vector stores the execution state (memory) used by the
412  /// sequential execution process.
413  std::vector<NekDouble> m_state;
414 
415  /// Vector of state sizes per each
416  std::vector<int> m_state_sizes;
417 
418  /// This counter is used by PrepareExecutionAsYouParse for finding
419  /// the minimal state size necessary for evaluation of function parsed.
421 
422 
423  /// Timer and sum of evaluation times
426 
427 
429  // boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
430  // m_normal;
431 
432 
433 
434  // ======================================================
435  // A map of (external) mathematical functions
436  // ======================================================
437 
438 
440  std::map<int, OneArgFunc> m_function;
441 
442 
443  // ======================================================
444  // Internal representation of evaluation step
445  // ======================================================
446 
447  /// Short names to minimise the infractructural code mess in defining functors below.
448  typedef std::vector<NekDouble>& vr;
449  typedef const std::vector<NekDouble>& cvr;
450  typedef const int ci;
452 
453  /// Factory method which makes code little less messy
454  template<typename StepType>
455  EvaluationStep* makeStep(ci dest, ci src_left = 0, ci src_right = 0)
456  {
457  return ( new StepType ( m_generator,m_state,m_constant,m_parameter,m_variable,dest,src_left,src_right ) );
458  }
459 
461  {
467  };
468 
469 
470 
471  /// Function objects (functors)
473  {
474  /// reference to random number generator
476 
477  /// references to arrays holding the common state
482 
483  /// indices in the above arrays uniquely defining actual command arguments
487 
488  EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v):
489  rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i), argIdx1(l), argIdx2(r) {};
490 
491  virtual ~EvaluationStep() {}
492 
493  /// declaring this guy pure virtual shortens virtual table. It saves some execution time.
494  virtual void run_many(ci n) = 0;
495  virtual void run_once() = 0;
496  };
497  struct CopyState: public EvaluationStep
498  {
499  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) {}
500  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = state[argIdx1]; }
501  virtual void run_once() { state[storeIdx] = state[argIdx1]; }
502  };
503  struct StoreConst: public EvaluationStep
504  {
505  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) {}
506  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = consts[argIdx1]; }
507  virtual void run_once() { state[storeIdx] = consts[argIdx1]; }
508  };
509  struct StoreVar: public EvaluationStep
510  {
511  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) {}
512  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = vars[argIdx1*n+i]; }
513  virtual void run_once() { state[storeIdx] = vars[argIdx1]; }
514  };
515  struct StorePrm: public EvaluationStep
516  {
517  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) {}
518  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = params[argIdx1]; }
519  virtual void run_once() { state[storeIdx] = params[argIdx1]; }
520  };
521  struct EvalSum: public EvaluationStep
522  {
523  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) {}
524  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]; }
525  virtual void run_once() { state[storeIdx] = state[argIdx1] + state[argIdx2]; }
526  };
527  struct EvalSub: public EvaluationStep
528  {
529  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) {}
530  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]; }
531  virtual void run_once() { state[storeIdx] = state[argIdx1] - state[argIdx2]; }
532  };
533  struct EvalMul: public EvaluationStep
534  {
535  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) {}
536  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]; }
537  virtual void run_once() { state[storeIdx] = state[argIdx1] * state[argIdx2]; }
538  };
539  struct EvalDiv: public EvaluationStep
540  {
541  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) {}
542  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]; }
543  virtual void run_once() { state[storeIdx] = state[argIdx1] / state[argIdx2]; }
544  };
545  struct EvalPow: public EvaluationStep
546  {
547  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) {}
548  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] ); }
549  virtual void run_once() { state[storeIdx] = std::pow( state[argIdx1], state[argIdx2] ); }
550  };
551  struct EvalNeg: public EvaluationStep
552  {
553  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) {}
554  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = - state[argIdx1*n+i]; }
555  virtual void run_once() { state[storeIdx] = - state[argIdx1]; }
556  };
558  {
559  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) {}
560  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] ); }
561  virtual void run_once() { state[storeIdx] = ( state[argIdx1] == state[argIdx2] ); }
562  };
564  {
565  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) {}
566  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] ); }
567  virtual void run_once() { state[storeIdx] = ( state[argIdx1] <= state[argIdx2] ); }
568  };
570  {
571  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) {}
572  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] ); }
573  virtual void run_once() { state[storeIdx] = ( state[argIdx1] < state[argIdx2] ); }
574  };
576  {
577  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) {}
578  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] ); }
579  virtual void run_once() { state[storeIdx] = ( state[argIdx1] >= state[argIdx2] ); }
580  };
582  {
583  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) {}
584  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] ); }
585  virtual void run_once() { state[storeIdx] = ( state[argIdx1] > state[argIdx2] ); }
586  };
587  struct EvalAbs: public EvaluationStep
588  {
589  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) {}
590  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::abs( state[argIdx1*n+i] ); }
591  virtual void run_once() { state[storeIdx] = std::abs( state[argIdx1] ); }
592  };
593  struct EvalSign: public EvaluationStep
594  {
595  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) {}
596  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)); }
597  virtual void run_once() { state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0)); }
598  };
599  struct EvalAsin: public EvaluationStep
600  {
601  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) {}
602  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::asin( state[argIdx1*n+i] ); }
603  virtual void run_once() { state[storeIdx] = std::asin( state[argIdx1] ); }
604  };
605  struct EvalAcos: public EvaluationStep
606  {
607  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) {}
608  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::acos( state[argIdx1*n+i] ); }
609  virtual void run_once() { state[storeIdx] = std::acos( state[argIdx1] ); }
610  };
611  struct EvalAtan: public EvaluationStep
612  {
613  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) {}
614  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::atan( state[argIdx1*n+i] ); }
615  virtual void run_once() { state[storeIdx] = std::atan( state[argIdx1] ); }
616  };
617  struct EvalCeil: public EvaluationStep
618  {
619  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) {}
620  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::ceil( state[argIdx1*n+i] ); }
621  virtual void run_once() { state[storeIdx] = std::ceil( state[argIdx1] ); }
622  };
623  struct EvalCos: public EvaluationStep
624  {
625  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) {}
626  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::cos( state[argIdx1*n+i] ); }
627  virtual void run_once() { state[storeIdx] = std::cos( state[argIdx1] ); }
628  };
629  struct EvalCosh: public EvaluationStep
630  {
631  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) {}
632  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::cosh( state[argIdx1*n+i] ); }
633  virtual void run_once() { state[storeIdx] = std::cosh( state[argIdx1] ); }
634  };
635  struct EvalExp: public EvaluationStep
636  {
637  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) {}
638  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::exp( state[argIdx1*n+i] ); }
639  virtual void run_once() { state[storeIdx] = std::exp( state[argIdx1] ); }
640  };
641  struct EvalFabs: public EvaluationStep
642  {
643  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) {}
644  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::fabs( state[argIdx1*n+i] ); }
645  virtual void run_once() { state[storeIdx] = std::fabs( state[argIdx1] ); }
646  };
647  struct EvalFloor: public EvaluationStep
648  {
649  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) {}
650  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::floor( state[argIdx1*n+i] ); }
651  virtual void run_once() { state[storeIdx] = std::floor( state[argIdx1] ); }
652  };
653  struct EvalLog: public EvaluationStep
654  {
655  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) {}
656  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::log( state[argIdx1*n+i] ); }
657  virtual void run_once() { state[storeIdx] = std::log( state[argIdx1] ); }
658  };
659  struct EvalLog10: public EvaluationStep
660  {
661  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) {}
662  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::log10( state[argIdx1*n+i] ); }
663  virtual void run_once() { state[storeIdx] = std::log10( state[argIdx1] ); }
664  };
665  struct EvalSin: public EvaluationStep
666  {
667  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) {}
668  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sin( state[argIdx1*n+i] ); }
669  virtual void run_once() { state[storeIdx] = std::sin( state[argIdx1] ); }
670  };
671  struct EvalSinh: public EvaluationStep
672  {
673  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) {}
674  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sinh( state[argIdx1*n+i] ); }
675  virtual void run_once() { state[storeIdx] = std::sinh( state[argIdx1] ); }
676  };
677  struct EvalSqrt: public EvaluationStep
678  {
679  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) {}
680  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::sqrt( state[argIdx1*n+i] ); }
681  virtual void run_once() { state[storeIdx] = std::sqrt( state[argIdx1] ); }
682  };
683  struct EvalTan: public EvaluationStep
684  {
685  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) {}
686  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::tan( state[argIdx1*n+i] ); }
687  virtual void run_once() { state[storeIdx] = std::tan( state[argIdx1] ); }
688  };
689  struct EvalTanh: public EvaluationStep
690  {
691  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) {}
692  virtual void run_many(ci n) { for(int i=0;i<n;i++) state[storeIdx*n+i] = std::tanh( state[argIdx1*n+i] ); }
693  virtual void run_once() { state[storeIdx] = std::tanh( state[argIdx1] ); }
694  };
695  struct EvalAWGN: public EvaluationStep
696  {
697  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) {}
698  virtual void run_many(ci n)
699  {
700  // assuming the argument to AWGN does not depend on spatial variables =>
701  boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
702  _normal(rng, boost::normal_distribution<>(0, state[storeIdx*n]) );
703  for(int i=0;i<n;i++) { state[storeIdx*n+i] = _normal(); }
704  }
705  virtual void run_once()
706  {
707  boost::variate_generator<RandomGeneratorType&, boost::normal_distribution<> >
708  _normal(rng, boost::normal_distribution<>(0, state[storeIdx]) );
709  state[storeIdx] = _normal();
710  }
711  };
712 
713  };
714  };
715 };
716 
717 #endif // _ANALYTIC_EXPRESSION_EVALUATOR_HPP