Nektar++
Interpreter/Interpreter.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Interpreter.cpp
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 
38 
39 #define BOOST_SPIRIT_THREADSAFE
40 #include <boost/spirit/include/classic_assign_actor.hpp>
41 #include <boost/spirit/include/classic_ast.hpp>
42 #include <boost/spirit/include/classic_core.hpp>
43 #include <boost/spirit/include/classic_push_back_actor.hpp>
44 #include <boost/spirit/include/classic_symbols.hpp>
45 
46 #include <boost/random/mersenne_twister.hpp>
47 #include <boost/random/normal_distribution.hpp>
48 #include <boost/random/variate_generator.hpp>
49 
50 #include <boost/algorithm/string/trim.hpp>
51 #include <boost/math/special_functions/bessel.hpp>
52 
53 namespace bsp = boost::spirit::classic;
54 
55 #include <map>
56 #include <string>
57 #include <vector>
58 #if defined(__INTEL_COMPILER)
59 #include <mathimf.h>
60 #else
61 #include <cmath>
62 #endif
63 
64 namespace Nektar
65 {
66 namespace LibUtilities
67 {
68 
69 // signum function
71 {
72  return (arg > 0.0) - (arg < 0.0);
73 }
74 
75 // Additive white Gaussian noise function. Arg: sigma of the zero-mean gaussian
76 // distribution Attention: this function is not actually used for evaluation
77 // purposes.
79 {
80  boost::mt19937 rng;
81  boost::variate_generator<boost::mt19937 &, boost::normal_distribution<>>
82  _normal(rng, boost::normal_distribution<>(0, sigma));
83  return _normal();
84 }
85 
87 {
88  return (x != 0.0 || y != 0.0) ? sqrt(x * x + y * y) : 0.0;
89 }
90 
92 {
93  return (x != 0.0 || y != 0.0) ? atan2(y, x) : 0.0;
94 }
95 
96 // =========================================================================
97 // AnalyticExpression definitions for Spirit Parser
98 // =========================================================================
99 
100 typedef NekDouble (*PFD)();
105 struct func
106 {
107  func(PFD1 p) : func1(p), size(1){};
108  func(PFD2 p) : func2(p), size(2){};
109  func(PFD3 p) : func3(p), size(3){};
110  func(PFD4 p) : func4(p), size(4){};
111 
112  union // Pointer to a function
113  {
118  };
119  size_t size;
120 };
121 
122 /** This struct creates a parser that matches the function definitions from
123  math.h. All of the functions accept one or more NekDoubles as arguments and
124  returns a NekDouble. **/
125 static struct functions : bsp::symbols<func>
126 {
128  {
129  // Add all of the functions from math.h
130  add("abs", std::abs) // absolute value
131  ("asin", asin) // arcsin
132  ("acos", acos) // arccos
133  ("atan", atan) // arctan
134  ("atan2", atan2) // arctan2
135  ("ang", ang) // angle calculation
136  ("ceil", ceil) // ceiling
137  ("cos", cos) // cosine
138  ("cosh", cosh) // hyperbolic cosine
139  ("exp", exp) // exponential
140  ("fabs", fabs) // absolute value
141  ("floor", floor) // floor
142  ("fmod", static_cast<double (*)(double, double)>(
143  &fmod)) // floating-point remainder
144  ("log", log) // natural log
145  ("log10", log10) // log base 10
146  ("rad", rad) // radians
147  ("sin", sin) // sine
148  ("sinh", sinh) // hyperbolic sine
149  ("sqrt", sqrt) // square root
150  ("tan", tan) // tangent
151  ("tanh", tanh) // hyperbolic tangent
152  // and few more custom functions
153  ("sign", sign) // sign
154  ("awgn", awgn) // white noise
155  ;
156  }
158 
159 /**
160  * @brief Concrete implementation of the interface defined in Interpreter.
161  */
163 {
164 private:
165  struct EvaluationStep;
166 
167 public:
168  typedef std::map<std::string, int> VariableMap;
169  typedef std::map<std::string, int> ConstantMap;
170  typedef std::map<std::string, int> ParameterMap;
171  typedef std::map<std::string, int> ExpressionMap;
172  typedef std::map<std::string, int> FunctionNameMap;
173  typedef std::vector<EvaluationStep *> ExecutionStack;
174  typedef std::pair<bool, NekDouble> PrecomputedValue;
177 
178  typedef bsp::tree_parse_info<std::string::const_iterator,
179  bsp::node_val_data_factory<NekDouble>>
181  typedef bsp::tree_match<std::string::const_iterator,
182  bsp::node_val_data_factory<NekDouble>>::
183  tree_iterator ParsedTreeIterator;
184 
185  typedef std::vector<const Array<OneD, const NekDouble> *> VariableArray;
186 
187  /**
188  * @brief Initializes the evaluator.
189  *
190  * This routine will initialize the evaluator with some basic default
191  * constants,
192  */
194  {
195  m_state_size = 1;
196 
197  // Constant definitions.
198  AddConstant("MEANINGLESS", 0.0);
199  AddConstant("E", M_E); // Natural logarithm
200  AddConstant("LOG2E", M_LOG2E); // log_2 e
201  AddConstant("LOG10E", M_LOG10E); // log_10 e
202  AddConstant("LN2", M_LN2); // log_e 2
203  AddConstant("LN10", M_LN10); // log_e 10
204  AddConstant("PI", M_PI); // pi
205  AddConstant("PI_2", M_PI_2); // pi/2
206  AddConstant("PI_4", M_PI_4); // pi/4
207  AddConstant("1_PI", M_1_PI); // 1/pi
208  AddConstant("2_PI", M_2_PI); // 2/pi
209  AddConstant("2_SQRTPI", M_2_SQRTPI); // 2/sqrt(pi)
210  AddConstant("SQRT2", M_SQRT2); // sqrt(2)
211  AddConstant("SQRT1_2", M_SQRT1_2); // 1/sqrt(2)
212  AddConstant("GAMMA", 0.57721566490153286060); // Euler
213  AddConstant("DEG", 57.2957795130823208768); // deg/radian
214  AddConstant("PHI", 1.61803398874989484820); // golden ratio
215 
216  // Function definitions.
241 
243  m_function[E_ASIN] = asin;
244  m_function[E_ACOS] = acos;
245  m_function[E_ATAN] = atan;
246  m_function[E_CEIL] = ceil;
247  m_function[E_COS] = cos;
248  m_function[E_COSH] = cosh;
249  m_function[E_EXP] = exp;
250  m_function[E_FABS] = fabs;
251  m_function[E_FLOOR] = floor;
252  m_function[E_LOG] = log;
253  m_function[E_LOG10] = log10;
254  m_function[E_SIN] = sin;
255  m_function[E_SINH] = sinh;
257  m_function[E_TAN] = tan;
258  m_function[E_TANH] = tanh;
260  m_function2[E_ATAN2] = atan2;
261  m_function2[E_ANG] = ang;
262  m_function2[E_RAD] = rad;
263  m_function2[E_BESSEL] = boost::math::cyl_bessel_j;
264  m_function2[E_FMOD] = static_cast<double (*)(double, double)>(&fmod);
265 
266  // Note that there is no entry in m_function that corresponds to the
267  // awgn function. This is intentional as this function need not be
268  // pre-evaluated once!
269  }
270 
271  /**
272  * @brief Destructor that removes all entries from the execution stack.
273  */
275  {
276  for (auto &it_es : m_executionStack)
277  {
278  for (auto &it : it_es)
279  {
280  delete it;
281  }
282  it_es.clear();
283  }
284  m_executionStack.clear();
285  }
286 
287  /**
288  * @copydoc Interpreter::SetRandomSeed
289  */
290  void SetRandomSeed(unsigned int seed)
291  {
292  m_generator.seed(seed);
293  }
294 
295  /**
296  * @copydoc Interpreter::AddConstants
297  */
298  void AddConstants(std::map<std::string, NekDouble> const &constants)
299  {
300  for (auto const &it : constants)
301  {
302  AddConstant(it.first, it.second);
303  }
304  }
305 
306  /**
307  * @copydoc Interpreter::AddConstant
308  */
309  int AddConstant(std::string const &name, NekDouble value)
310  {
311  ConstantMap::const_iterator it = m_constantMapNameToId.find(name);
312  if (it == m_constantMapNameToId.end())
313  {
314  // We are trying to avoid duplicating entries in m_constantParser
315  // and m_constants.
316  m_constantsParser.add(name.c_str(), value);
317  int index = m_constant.size();
318  m_constantMapNameToId[name] = index;
319  m_constant.push_back(value);
320  return index;
321  }
322  else
323  {
324  if (m_constant[it->second] != value)
325  {
326  std::string errormsg =
327  "Attempt to add numerically different constants under the "
328  "same name: " +
329  name;
330  std::cout << errormsg << std::endl;
331  }
332  }
333  return it->second;
334  }
335 
336  /**
337  * @copydoc Interpreter::GetConstant
338  */
339  NekDouble GetConstant(std::string const &name)
340  {
341  NekDouble *value = find(m_constantsParser, name.c_str());
342  ASSERTL1(value != NULL, "Constant variable not found: " + name);
343  return *value;
344  }
345 
346  /**
347  * @copydoc Interpreter::SetParameters
348  */
349  void SetParameters(std::map<std::string, NekDouble> const &params)
350  {
351  for (auto const &it : params)
352  {
353  SetParameter(it.first, it.second);
354  }
355  }
356 
357  /**
358  * @copydoc Interpreter::SetParameter
359  */
360  void SetParameter(std::string const &name, NekDouble value)
361  {
362  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
363  if (it == m_parameterMapNameToId.end())
364  {
366  m_parameter.push_back(value);
367  }
368  else
369  {
370  // If parameter is known, change its value.
371  m_parameter[it->second] = value;
372  }
373  }
374 
375  /**
376  * @copydoc Interpreter::GetParameter
377  */
378  NekDouble GetParameter(std::string const &name)
379  {
380  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
381  ASSERTL1(it != m_parameterMapNameToId.end(),
382  "Parameter not found: " + name);
383  return m_parameter[it->second];
384  }
385 
386  /**
387  * @copydoc Interpreter::GetTime
388  */
390  {
391  return m_total_eval_time;
392  }
393 
394  /**
395  * @copydoc Interpreter::DefineFunction
396  */
397  int DefineFunction(const std::string &vlist, const std::string &expr)
398  {
399  // If we have previously parsed an identical expression, return its ID.
400  auto it = m_parsedMapExprToExecStackId.find(expr);
401  if (it != m_parsedMapExprToExecStackId.end())
402  {
403  // If this function is already defined, don't do anything but return
404  // its ID.
405  return it->second;
406  }
407 
408  // Otherwise, prepare an iterator that allows to walk along the string
409  // representing an analytic expression in the order that respects its
410  // recursive structure (thanks to boost::spirit).
411 
412  // Parse the vlist input and separate the variables into ordered entries
413  // in a vector<string> object. These need to be ordered because this is
414  // the order the variables will get assigned to in the Map when
415  // Evaluate(...) is called.
416  std::vector<std::string> variableNames;
417  bsp::parse((char *)vlist.c_str(),
418  (*bsp::space_p >>
419  *(+(+bsp::graph_p)[bsp::push_back_a(variableNames)] >>
420  +bsp::space_p)));
421 
422  // Set up our grammar.
423  AnalyticExpression myGrammar(&m_constantsParser, variableNames);
424 
425  // Do the actual parsing with boost::spirit and alert the user if there
426  // was an error with an exception.
427  ParsedTreeInfo parseInfo =
428  bsp::ast_parse<bsp::node_val_data_factory<NekDouble>,
429  std::string::const_iterator, AnalyticExpression,
430  bsp::space_parser>(expr.begin(), expr.end(),
431  myGrammar, bsp::space_p);
432 
433  ASSERTL1(parseInfo.full != false,
434  "Unable to fully parse function. Stopped just before: " +
435  std::string(parseInfo.stop, parseInfo.stop + 15));
436 
437  if (!parseInfo.full)
438  {
439  throw std::runtime_error(
440  "Unable to fully parse function at: " +
441  std::string(parseInfo.stop, parseInfo.stop + 15));
442  }
443 
444  // ----------------------------------------------
445  // Data parsed, start setting up internal data structures.
446  // ----------------------------------------------
447 
448  ExecutionStack stack;
449  VariableMap variableMap;
450 
451  int stackId = m_executionStack.size();
452  m_state_size = 1;
453 
454  // Register all variables declared in the expression
455  for (int i = 0; i < variableNames.size(); i++)
456  {
457  variableMap[variableNames[i]] = i;
458  }
459 
460  // Then prepare an execution stack. This method also calculates a
461  // length of internal state storage (m_state_size) for this function.
462  PrecomputedValue v = PrepareExecutionAsYouParse(parseInfo.trees.begin(),
463  stack, variableMap, 0);
464 
465  // Constant expression, fully evaluated already.
466  if (true == v.first)
467  {
468  ASSERTL1(stack.size() == 0,
469  "Constant expression yeilds non-empty execution stack. "
470  "Bug in PrepareExecutionAsYouParse()");
471 
472  int const_index = AddConstant(
473  std::string("EXPRESSION_") + std::to_string(stackId), v.second);
474  stack.push_back(makeStep<StoreConst>(0, const_index));
475  }
476 
477  m_parsedMapExprToExecStackId[expr] = stackId;
478 
479  // The execution stack and its corresponding variable index map are two
480  // parallel std::vectors that share their ids. This split helps to
481  // achieve some performance improvement.
482  m_executionStack.push_back(stack);
483  m_stackVariableMap.push_back(variableMap);
484  m_state_sizes.push_back(m_state_size);
485 
486  return stackId;
487  }
488 
489  /**
490  * @copydoc Interpreter::Evaluate
491  */
492  NekDouble Evaluate(const int id)
493  {
494  m_timer.Start();
495 
496  ASSERTL1(m_executionStack.size() > id,
497  "unknown analytic expression, it must first be defined "
498  "with DefineFunction(...)");
499 
500  ExecutionStack &stack = m_executionStack[id];
501 
502  m_state.resize(m_state_sizes[id]);
503  for (int i = 0; i < stack.size(); i++)
504  {
505  (*stack[i]).run_once();
506  }
507 
508  m_timer.Stop();
510 
511  return m_state[0];
512  }
513 
514  /**
515  * @copydoc Interpreter::Evaluate
516  */
517  NekDouble Evaluate(const int id, const NekDouble x, const NekDouble y,
518  const NekDouble z, const NekDouble t)
519  {
520  m_timer.Start();
521 
522  ASSERTL1(m_executionStack.size() > id,
523  "unknown analytic expression, it must first be defined with "
524  "DefineFunction(...)");
525 
526  ExecutionStack &stack = m_executionStack[id];
527 
528  // initialise internal vector of variable values
529  m_state.resize(m_state_sizes[id]);
530 
531  if (m_variable.size() < 4)
532  {
533  m_variable.resize(4);
534  }
535 
536  // no flexibility, no change of variable ordering in m_variable
537  // container depending on their names ordering in the input vlist
538  // argument of DefineFunction. Ordering convention (x,y,z,t) is assumed.
539  m_variable[0] = x;
540  m_variable[1] = y;
541  m_variable[2] = z;
542  m_variable[3] = t;
543 
544  // main execution cycle is hidden here
545  for (int i = 0; i < stack.size(); i++)
546  {
547  (*stack[i]).run_once();
548  }
549 
550  m_timer.Stop();
552 
553  return m_state[0];
554  }
555 
556  /**
557  * @copydoc Interpreter::EvaluateAtPoint
558  */
559  NekDouble EvaluateAtPoint(const int id, const std::vector<NekDouble> point)
560  {
561  m_timer.Start();
562 
563  ASSERTL1(m_executionStack.size() > id,
564  "unknown analytic expression, it must first be defined with "
565  "DefineFunction(...)");
566 
567  ExecutionStack &stack = m_executionStack[id];
568  VariableMap &variableMap = m_stackVariableMap[id];
569 
570  ASSERTL1(point.size() == variableMap.size(),
571  "The number of variables used to define this expression should"
572  " match the point dimensionality.");
573 
574  // initialise internal vector of variable values
575  m_state.resize(m_state_sizes[id]);
576  m_variable.resize(point.size());
577  VariableMap::const_iterator it;
578 
579  for (it = variableMap.begin(); it != variableMap.end(); ++it)
580  {
581  m_variable[it->second] = point[it->second];
582  }
583 
584  // main execution cycle is hidden here
585  for (int i = 0; i < stack.size(); i++)
586  {
587  (*stack[i]).run_once();
588  }
589 
590  m_timer.Stop();
592 
593  return m_state[0];
594  }
595 
596  /**
597  * @copydoc Interpreter::Evaluate
598  */
599  void Evaluate(const int id, const Array<OneD, const NekDouble> &x,
603  Array<OneD, NekDouble> &result)
604  {
605  std::vector<Array<OneD, const NekDouble>> points = {x, y, z, t};
606  Evaluate(id, points, result);
607  }
608 
609  /**
610  * @copydoc Interpreter::Evaluate
611  */
612  void Evaluate(const int id,
613  const std::vector<Array<OneD, const NekDouble>> &points,
614  Array<OneD, NekDouble> &result)
615  {
616  m_timer.Start();
617 
618  const int num_points = points[0].size();
619  ASSERTL1(m_executionStack.size() > id,
620  "unknown analytic expression, it must first be defined "
621  "with DefineFunction(...)");
622  ASSERTL1(result.size() >= num_points,
623  "destination array must have enough capacity to store "
624  "expression values at each given point");
625 
626  ExecutionStack &stack = m_executionStack[id];
627 
628  /// If number of points tends to 10^6, one may end up with up to ~0.5Gb
629  /// data allocated for m_state only. Lets split the work into
630  /// cache-sized chunks. Ahtung, magic constant!
631  const int max_chunk_size = 1024;
632  const int nvals = points.size();
633  const int chunk_size = (std::min)(max_chunk_size, num_points);
634 
635  if (m_state.size() < chunk_size * m_state_sizes[id])
636  {
637  m_state.resize(m_state_sizes[id] * chunk_size, 0.0);
638  }
639  if (m_variable.size() < nvals * chunk_size)
640  {
641  m_variable.resize(nvals * chunk_size, 0.0);
642  }
643  if (result.size() < num_points)
644  {
645  result = Array<OneD, NekDouble>(num_points, 0.0);
646  }
647 
648  int offset = 0;
649  int work_left = num_points;
650  while (work_left > 0)
651  {
652  const int this_chunk_size = (std::min)(work_left, 1024);
653  for (int i = 0; i < this_chunk_size; i++)
654  {
655  for (int j = 0; j < nvals; ++j)
656  {
657  m_variable[i + this_chunk_size * j] = points[j][offset + i];
658  }
659  }
660  for (int i = 0; i < stack.size(); i++)
661  {
662  (*stack[i]).run_many(this_chunk_size);
663  }
664  for (int i = 0; i < this_chunk_size; i++)
665  {
666  result[offset + i] = m_state[i];
667  }
668  work_left -= this_chunk_size;
669  offset += this_chunk_size;
670  }
671  m_timer.Stop();
673  }
674 
675  // ======================================================
676  // Private parsing and partial evaluation method
677  // ======================================================
678 
679  /**
680  * @brief Prepares an execution stack for the evaluation of a function.
681  *
682  * This method prepares the execution stack (an ordered sequence of
683  * operators that perform the evaluation) for the parsed evaluation tree.
684  * In order to do this, it unrolls the binary tree representing the
685  * recursive evaluation into an ordered sequence of commands. That ordered
686  * sequence of commands is equivalent to a bottom-up walk up the evaluation
687  * tree, but this allows not to form tree explicitly.
688  *
689  * This approach requires to introduce explicitly an execution state
690  * (memory) shared by commands in the evaluation sequence: recursively
691  * dependent commands need to pass data between each other. Such state for
692  * the recursive evaluation is passed via return values of a recursive
693  * evaluation function --- which is bad if one wants to implement vectorized
694  * evaluator.
695  *
696  * On the other hand, to run through a sequential container of functors is
697  * faster than to walk the tree and at each node to check the node type.
698  *
699  * @param root Iterator generated by boost::spirit.
700  * @param stack Initially empty sequential container of evaluation
701  * steps.
702  * @param varMap Maps variable names to their ids.
703  * @param stateIndex An index in the state[] array where an evaluation
704  * step corresponding to the current tree node
705  * is allowed to write.
706  *
707  * @return A std::pair<bool, NekDouble> which encodes fully pre-evaluated
708  * NekDouble values as `(true, value)` if all sub-tree down the
709  * current node evaluates to constant, or flags the opposite
710  * via `(false, 0)`.
711  */
713  const ParsedTreeIterator &location, ExecutionStack &stack,
714  VariableMap &variableMap, int stateIndex)
715  {
716  std::string valueStr(location->value.begin(), location->value.end());
717  boost::algorithm::trim(valueStr);
718 
719  const bsp::parser_id parserID = location->value.id();
720 #if defined(NEKTAR_DEBUG) || defined(NEKTAR_FULLDEBUG)
721  const int num_children = location->children.size();
722 #endif
723 
724  if (parserID == AnalyticExpression::constantID)
725  {
726  ASSERTL1(num_children == 0,
727  "Illegal children under constant node: " + valueStr);
728 
729  auto it = m_constantMapNameToId.find(valueStr);
730  ASSERTL1(it != m_constantMapNameToId.end(),
731  "Cannot find the value for the specified constant: " +
732  valueStr);
733 
734  return std::make_pair(true, m_constant[it->second]);
735  }
736  else if (parserID == AnalyticExpression::numberID)
737  {
738  ASSERTL1(num_children == 0,
739  "Illegal children under number node: " + valueStr);
740  return std::make_pair(
741  true, boost::lexical_cast<NekDouble>(valueStr.c_str()));
742  }
743  else if (parserID == AnalyticExpression::variableID)
744  {
745  ASSERTL1(num_children == 0,
746  "Illegal children under variable node: " + valueStr);
747 
748  VariableMap::const_iterator it = variableMap.find(valueStr);
749  ASSERTL1(it != variableMap.end(),
750  "Unknown variable parsed: " + valueStr);
751 
752  // Variables are not defined at the time of this parse.
753  stack.push_back(makeStep<StoreVar>(stateIndex, it->second));
754  return std::make_pair(false, 0);
755  }
756  else if (parserID == AnalyticExpression::parameterID)
757  {
758  ASSERTL1(num_children == 0,
759  "Illegal children under parameter node: " + valueStr);
760 
761  auto it = m_parameterMapNameToId.find(valueStr);
762  ASSERTL1(it != m_parameterMapNameToId.end(),
763  "Unknown parameter parsed: " + valueStr);
764 
765  // Parameters may change in between of evalutions.
766  stack.push_back(makeStep<StorePrm>(stateIndex, it->second));
767  return std::make_pair(false, 0);
768  }
769  else if (parserID == AnalyticExpression::functionID)
770  {
771  auto it = m_functionMapNameToInstanceType.find(valueStr);
773  "Invalid function specified: " + valueStr);
774  ASSERTL1(num_children == 1 || num_children == 2,
775  "Function " + valueStr +
776  " has neither one or two "
777  "arguments: this is not implemented yet.");
778 
779  if (location->children.size() == 1)
780  {
782  location->children.begin(), stack, variableMap, stateIndex);
783 
784  // additive white gaussian noise function
785  if (it->second == E_AWGN)
786  {
787  int const_index =
788  AddConstant(std::string("SUB_EXPR_") +
789  std::to_string(m_constant.size()),
790  v.second);
791  stack.push_back(
792  makeStep<StoreConst>(stateIndex, const_index));
793  stack.push_back(makeStep<EvalAWGN>(stateIndex, stateIndex));
794  return std::make_pair(false, 0);
795  }
796 
797  if (true == v.first)
798  {
799  return std::make_pair(true,
800  m_function[it->second](v.second));
801  }
802  }
803  else
804  {
805  PrecomputedValue v1 =
806  PrepareExecutionAsYouParse(location->children.begin() + 0,
807  stack, variableMap, stateIndex);
809  location->children.begin() + 1, stack, variableMap,
810  stateIndex + 1);
811  m_state_size++;
812 
813  if (true == v1.first && true == v2.first)
814  {
815  return std::make_pair(
816  true, m_function2[it->second](v1.second, v2.second));
817  }
818  }
819 
820  // if somewhere down the parse tree there is a variable or
821  // parameter, set up an evaluation sequence.
822  switch (it->second)
823  {
824  case E_ABS:
825  stack.push_back(makeStep<EvalAbs>(stateIndex, stateIndex));
826  return std::make_pair(false, 0);
827  case E_ASIN:
828  stack.push_back(makeStep<EvalAsin>(stateIndex, stateIndex));
829  return std::make_pair(false, 0);
830  case E_ACOS:
831  stack.push_back(makeStep<EvalAcos>(stateIndex, stateIndex));
832  return std::make_pair(false, 0);
833  case E_ATAN:
834  stack.push_back(makeStep<EvalAtan>(stateIndex, stateIndex));
835  return std::make_pair(false, 0);
836  case E_ATAN2:
837  stack.push_back(makeStep<EvalAtan2>(stateIndex, stateIndex,
838  stateIndex + 1));
839  return std::make_pair(false, 0);
840  case E_ANG:
841  stack.push_back(makeStep<EvalAng>(stateIndex, stateIndex,
842  stateIndex + 1));
843  return std::make_pair(false, 0);
844  case E_BESSEL:
845  stack.push_back(makeStep<EvalBessel>(stateIndex, stateIndex,
846  stateIndex + 1));
847  return std::make_pair(false, 0);
848  case E_CEIL:
849  stack.push_back(makeStep<EvalCeil>(stateIndex, stateIndex));
850  return std::make_pair(false, 0);
851  case E_COS:
852  stack.push_back(makeStep<EvalCos>(stateIndex, stateIndex));
853  return std::make_pair(false, 0);
854  case E_COSH:
855  stack.push_back(makeStep<EvalCosh>(stateIndex, stateIndex));
856  return std::make_pair(false, 0);
857  case E_EXP:
858  stack.push_back(makeStep<EvalExp>(stateIndex, stateIndex));
859  return std::make_pair(false, 0);
860  case E_FABS:
861  stack.push_back(makeStep<EvalFabs>(stateIndex, stateIndex));
862  return std::make_pair(false, 0);
863  case E_FLOOR:
864  stack.push_back(
865  makeStep<EvalFloor>(stateIndex, stateIndex));
866  return std::make_pair(false, 0);
867  case E_FMOD:
868  stack.push_back(makeStep<EvalFmod>(stateIndex, stateIndex,
869  stateIndex + 1));
870  return std::make_pair(false, 0);
871  case E_LOG:
872  stack.push_back(makeStep<EvalLog>(stateIndex, stateIndex));
873  return std::make_pair(false, 0);
874  case E_LOG10:
875  stack.push_back(
876  makeStep<EvalLog10>(stateIndex, stateIndex));
877  return std::make_pair(false, 0);
878  case E_RAD:
879  stack.push_back(makeStep<EvalRad>(stateIndex, stateIndex,
880  stateIndex + 1));
881  return std::make_pair(false, 0);
882  case E_SIN:
883  stack.push_back(makeStep<EvalSin>(stateIndex, stateIndex));
884  return std::make_pair(false, 0);
885  case E_SINH:
886  stack.push_back(makeStep<EvalSinh>(stateIndex, stateIndex));
887  return std::make_pair(false, 0);
888  case E_SQRT:
889  stack.push_back(makeStep<EvalSqrt>(stateIndex, stateIndex));
890  return std::make_pair(false, 0);
891  case E_TAN:
892  stack.push_back(makeStep<EvalTan>(stateIndex, stateIndex));
893  return std::make_pair(false, 0);
894  case E_TANH:
895  stack.push_back(makeStep<EvalTanh>(stateIndex, stateIndex));
896  return std::make_pair(false, 0);
897  case E_SIGN:
898  stack.push_back(makeStep<EvalSign>(stateIndex, stateIndex));
899  return std::make_pair(false, 0);
900  default:
901  ASSERTL0(false, "Evaluation of " + valueStr +
902  " is not implemented yet");
903  }
904  return std::make_pair(false, 0);
905  }
906  else if (parserID == AnalyticExpression::unaryID)
907  {
908  ASSERTL1(*valueStr.begin() == '-',
909  "Illegal factor - it can only be '-' and it was: " +
910  valueStr);
911  ASSERTL1(num_children == 1,
912  "Illegal number of children under factor node: " +
913  valueStr);
915  location->children.begin(), stack, variableMap, stateIndex);
916 
917  // if precomputed value is valid, process it further.
918  if (true == v.first)
919  {
920  return std::make_pair(true, -v.second);
921  }
922  stack.push_back(makeStep<EvalNeg>(stateIndex, stateIndex));
923  return std::make_pair(false, 0);
924  }
925  else if (parserID == AnalyticExpression::operatorID)
926  {
927  ASSERTL1(
928  num_children == 2,
929  "Too few or too many arguments for mathematical operator: " +
930  valueStr);
932  location->children.begin() + 0, stack, variableMap, stateIndex);
933  PrecomputedValue right =
934  PrepareExecutionAsYouParse(location->children.begin() + 1,
935  stack, variableMap, stateIndex + 1);
936  m_state_size++;
937 
938  // if both precomputed values are valid, process them further.
939  if ((left.first == true) && (right.first == true))
940  {
941  switch (*valueStr.begin())
942  {
943  case '+':
944  return std::make_pair(true, left.second + right.second);
945  case '-':
946  return std::make_pair(true, left.second - right.second);
947  case '*':
948  return std::make_pair(true, left.second * right.second);
949  case '/':
950  return std::make_pair(true, left.second / right.second);
951  case '%':
952  return std::make_pair(
953  true, std::fmod(left.second, right.second));
954  case '^':
955  return std::make_pair(
956  true, std::pow(left.second, right.second));
957  case '=':
958  return std::make_pair(true,
959  left.second == right.second);
960  case '<':
961  if (*(valueStr.end() - 1) == '=')
962  {
963  return std::make_pair(true,
964  left.second <= right.second);
965  }
966  else
967  {
968  return std::make_pair(true,
969  left.second < right.second);
970  }
971  return std::make_pair(false, 0);
972  case '>':
973  if (*(valueStr.end() - 1) == '=')
974  {
975  return std::make_pair(true,
976  left.second >= right.second);
977  }
978  else
979  {
980  return std::make_pair(true,
981  left.second > right.second);
982  }
983  return std::make_pair(false, 0);
984  default:
985  ASSERTL0(false,
986  "Invalid operator encountered: " + valueStr);
987  }
988  return std::make_pair(false, 0);
989  }
990 
991  // either operator argument is not fully evaluated
992  // add pre-evaluated value to the contaner of constants
993  if (true == left.first)
994  {
995  int const_index =
996  AddConstant(std::string("SUB_EXPR_") +
997  std::to_string(m_constant.size()),
998  left.second);
999  stack.push_back(makeStep<StoreConst>(stateIndex, const_index));
1000  }
1001  if (true == right.first)
1002  {
1003  int const_index =
1004  AddConstant(std::string("SUB_EXPR_") +
1005  std::to_string(m_constant.size()),
1006  right.second);
1007  stack.push_back(
1008  makeStep<StoreConst>(stateIndex + 1, const_index));
1009  }
1010 
1011  switch (*valueStr.begin())
1012  {
1013  case '+':
1014  stack.push_back(makeStep<EvalSum>(stateIndex, stateIndex,
1015  stateIndex + 1));
1016  return std::make_pair(false, 0);
1017  case '-':
1018  stack.push_back(makeStep<EvalSub>(stateIndex, stateIndex,
1019  stateIndex + 1));
1020  return std::make_pair(false, 0);
1021  case '*':
1022  stack.push_back(makeStep<EvalMul>(stateIndex, stateIndex,
1023  stateIndex + 1));
1024  return std::make_pair(false, 0);
1025  case '/':
1026  stack.push_back(makeStep<EvalDiv>(stateIndex, stateIndex,
1027  stateIndex + 1));
1028  return std::make_pair(false, 0);
1029  case '%':
1030  stack.push_back(makeStep<EvalMod>(stateIndex, stateIndex,
1031  stateIndex + 1));
1032  return std::make_pair(false, 0);
1033  case '^':
1034  stack.push_back(makeStep<EvalPow>(stateIndex, stateIndex,
1035  stateIndex + 1));
1036  return std::make_pair(false, 0);
1037  case '=':
1038  stack.push_back(makeStep<EvalLogicalEqual>(
1039  stateIndex, stateIndex, stateIndex + 1));
1040  return std::make_pair(false, 0);
1041  case '<':
1042  if (*(valueStr.end() - 1) == '=')
1043  {
1044  stack.push_back(makeStep<EvalLogicalLeq>(
1045  stateIndex, stateIndex, stateIndex + 1));
1046  }
1047  else
1048  {
1049  stack.push_back(makeStep<EvalLogicalLess>(
1050  stateIndex, stateIndex, stateIndex + 1));
1051  }
1052  return std::make_pair(false, 0);
1053 
1054  case '>':
1055  if (*(valueStr.end() - 1) == '=')
1056  {
1057  stack.push_back(makeStep<EvalLogicalGeq>(
1058  stateIndex, stateIndex, stateIndex + 1));
1059  }
1060  else
1061  {
1062  stack.push_back(makeStep<EvalLogicalGreater>(
1063  stateIndex, stateIndex, stateIndex + 1));
1064  }
1065  return std::make_pair(false, 0);
1066 
1067  default:
1068  ASSERTL0(false,
1069  "Invalid operator encountered: " + valueStr);
1070  }
1071  return std::make_pair(false, 0);
1072  }
1073  else if (parserID == AnalyticExpression::operatorID)
1074  {
1075  ASSERTL1(
1076  false,
1077  "Too few or too many arguments for mathematical operator: " +
1078  valueStr);
1079  }
1080  ASSERTL0(false, "Illegal expression encountered: " + valueStr);
1081  return std::make_pair(false, 0);
1082  }
1083 
1084  // ======================================================
1085  // Boost::spirit related data structures
1086  // ======================================================
1087 
1088  /** This is a parser for spirit that parses the CONSTANT values. The default
1089  constants are those that are in math.h without the M_ prefix and they
1090  are initialized in the AnalyticExpressionEvaluator constructor. **/
1091 
1092  bsp::symbols<NekDouble> m_constantsParser;
1093 
1094  /** This is the class that is used as the grammar parser for the spirit
1095  * engine. **/
1096  class AnalyticExpression : public bsp::grammar<AnalyticExpression>
1097  {
1098  private:
1099  const bsp::symbols<NekDouble> *constants_p;
1100 
1101  /** Variables is a customized parser that will match the variables that
1102  the function depends on (the first argument of #DefineFunction). **/
1103  struct variables : bsp::symbols<NekDouble *>
1104  {
1105  variables(std::vector<std::string> const &vars)
1106  {
1107  for (auto const &it : vars)
1108  {
1109  add(it.c_str(), 0);
1110  }
1111  }
1113 
1114  public:
1115  /** These constants are used to determine what parser was used to parse
1116  what value, which allows for type identification when analyzing the
1117  parsed AST. **/
1118  static const int constantID = 1;
1119  static const int numberID = 2;
1120  static const int variableID = 3;
1121  static const int parameterID = 4;
1122  static const int functionID = 5;
1123  static const int unaryID = 6;
1124  static const int operatorID = 7;
1125 
1126  AnalyticExpression(const bsp::symbols<NekDouble> *constants,
1127  const std::vector<std::string> &variables)
1128  : bsp::grammar<AnalyticExpression>(), constants_p(constants),
1130  {
1131  }
1132 
1133  // Trivial constructor to avoid compiler warning with
1134  // constants_p.
1136  {
1137  constants_p = NULL;
1138  }
1139 
1140  template <typename ScannerT> struct definition
1141  {
1142  /** This function specifies the grammar of the
1143  * MathAnalyticExpression parser. **/
1145  {
1147 
1148  logical_or =
1149  logical_and >>
1150  *((bsp::root_node_d[bsp::str_p("||")] >> logical_and));
1151 
1152  logical_and =
1153  equality >>
1154  *((bsp::root_node_d[bsp::str_p("&&")] >> equality));
1155 
1156  equality =
1157  lt_gt >> *((bsp::root_node_d[bsp::str_p("==")] >> lt_gt));
1158 
1159  lt_gt = add_sub >>
1160  *((bsp::root_node_d[bsp::str_p("<=")] >> add_sub) |
1161  (bsp::root_node_d[bsp::str_p(">=")] >> add_sub) |
1162  (bsp::root_node_d[bsp::ch_p('<')] >> add_sub) |
1163  (bsp::root_node_d[bsp::ch_p('>')] >> add_sub));
1164 
1165  add_sub =
1166  negate >> *((bsp::root_node_d[bsp::ch_p('+')] >> negate) |
1167  (bsp::root_node_d[bsp::ch_p('-')] >> negate));
1168 
1169  negate = !(bsp::root_node_d[bsp::ch_p('-')]) >> mult_div_mod;
1170 
1171  mult_div_mod =
1172  exponential >>
1173  *((bsp::root_node_d[bsp::ch_p('*')] >> exponential) |
1174  (bsp::root_node_d[bsp::ch_p('/')] >> exponential) |
1175  (bsp::root_node_d[bsp::ch_p('%')] >> exponential));
1176 
1177  exponential =
1178  base >> !(bsp::root_node_d[bsp::ch_p('^')] >> exponential);
1179 
1180  base = number | function | variable | constant | parameter |
1181  bsp::inner_node_d[bsp::ch_p('(') >> expression >>
1182  bsp::ch_p(')')];
1183  parameter =
1184  bsp::leaf_node_d[bsp::lexeme_d[(bsp::alpha_p | '_' | '$') >>
1185  *(bsp::alnum_p | '_' |
1186  '$')]] >>
1187  op;
1188 
1189  function =
1190  bsp::root_node_d[functions_p] >>
1191  bsp::infix_node_d[bsp::inner_node_d[bsp::ch_p('(') >>
1192  expression >>
1193  *(',' >> expression) >>
1194  bsp::ch_p(')')]];
1195 
1196  variable =
1197  bsp::leaf_node_d[bsp::lexeme_d[self.variables_p]] >> op;
1198 
1199  number = bsp::leaf_node_d[bsp::lexeme_d[bsp::real_p]] >> op;
1200 
1201  constant =
1202  bsp::leaf_node_d[bsp::lexeme_d[*self.constants_p]] >> op;
1203 
1204  op = bsp::eps_p(bsp::end_p | "||" | "&&" | "==" | "<=" | ">=" |
1205  '<' | '>' | '+' | '-' | '*' | '/' | '%' | '^' |
1206  ')' | ',');
1207  }
1208 
1209  /** This holds the NekDouble value that is parsed by spirit so it
1210  * can be stored in the AST. **/
1212 
1213  template <int N>
1214  using bsp_rule =
1215  bsp::rule<ScannerT, bsp::parser_context<>, bsp::parser_tag<N>>;
1216 
1234 
1236  {
1237  return expression;
1238  }
1239  };
1240  }; // class AnalyticExpression
1241 
1242 private:
1243  // ======================================================
1244  // Pre-processed expressions
1245  // ======================================================
1246 
1247  /// These vector and map store pre-processed evaluation sequences
1248  /// for the analytic expressions. Each ExecutionStack is an ordered
1249  /// container of steps of sequential execution process which
1250  /// evaluates an analytic expression.
1251 
1253  std::vector<ExecutionStack> m_executionStack;
1254 
1255  /// Keeping map of variables individually per each analytic expression
1256  /// allows correctly handling expressions which depend on different
1257  /// number of variables.
1258 
1259  std::vector<VariableMap> m_stackVariableMap;
1260 
1261  // ======================================================
1262  // Execution state and data
1263  // ======================================================
1264 
1265  /// The following data structures hold input data to be used on evaluation
1266  /// stage. There are three types of input data:
1267  /// - constants (never change their value)
1268  /// - parameters are allowed to change their values between evaluations
1269  /// (compared to constants)
1270  /// - variables always change their values at every evaluation call.
1271  /// First map looks like <parameter_name, parameter_id> while the second is
1272  /// <parameter_id, parameter_value>. The map is used at a preparation
1273  /// stage when the analytic expression is parsed. This associates an
1274  /// integer id with a parameter name in its string form. On evaluation
1275  /// stage the id and a std::vector constant lookup time make evaluation
1276  /// faster compared to permanent std::map<std::string, NekDouble> lookup.
1277 
1281 
1282  std::vector<NekDouble> m_parameter;
1283  std::vector<NekDouble> m_constant;
1284  std::vector<NekDouble> m_variable;
1285 
1286  /// This vector stores the execution state (memory) used by the
1287  /// sequential execution process.
1288  std::vector<NekDouble> m_state;
1289 
1290  /// Vector of state sizes per each
1291  std::vector<int> m_state_sizes;
1292 
1293  /// This counter is used by PrepareExecutionAsYouParse for finding
1294  /// the minimal state size necessary for evaluation of function parsed.
1296 
1297  /// Timer and sum of evaluation times
1300 
1301  boost::mt19937 m_generator;
1302 
1303  // ======================================================
1304  // A map of (external) mathematical functions
1305  // ======================================================
1306 
1308  std::map<int, OneArgFunc> m_function;
1309  std::map<int, TwoArgFunc> m_function2;
1310 
1311  // ======================================================
1312  // Internal representation of evaluation step
1313  // ======================================================
1314 
1315  /// Short names to minimise the infractructural code mess in defining
1316  /// functors below.
1317  typedef std::vector<NekDouble> &vr;
1318  typedef const std::vector<NekDouble> &cvr;
1319  typedef const int ci;
1320  typedef boost::mt19937 &rgt;
1321 
1322  /// Factory method which makes code little less messy
1323  template <typename StepType>
1324  EvaluationStep *makeStep(ci dest, ci src_left = 0, ci src_right = 0)
1325  {
1326  return (new StepType(m_generator, m_state, m_constant, m_parameter,
1327  m_variable, dest, src_left, src_right));
1328  }
1329 
1331  {
1356  E_BESSEL
1357  };
1358 
1359  /// Function objects (functors)
1361  {
1362  /// reference to random number generator
1364 
1365  /// references to arrays holding the common state
1370 
1371  /// indices in the above arrays uniquely defining actual command
1372  /// arguments
1376 
1377  EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
1378  : rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i),
1379  argIdx1(l), argIdx2(r){};
1380 
1382  {
1383  }
1384 
1385  /// declaring this guy pure virtual shortens virtual table. It saves
1386  /// some execution time.
1387  virtual void run_many(ci n) = 0;
1388  virtual void run_once() = 0;
1389  };
1390  struct CopyState : public EvaluationStep
1391  {
1392  CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1393  : EvaluationStep(rn, i, l, r, s, c, p, v)
1394  {
1395  }
1396  virtual void run_many(ci n)
1397  {
1398  for (int i = 0; i < n; i++)
1399  state[storeIdx * n + i] = state[argIdx1];
1400  }
1401  virtual void run_once()
1402  {
1404  }
1405  };
1406  struct StoreConst : public EvaluationStep
1407  {
1408  StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1409  : EvaluationStep(rn, i, l, r, s, c, p, v)
1410  {
1411  }
1412  virtual void run_many(ci n)
1413  {
1414  for (int i = 0; i < n; i++)
1415  state[storeIdx * n + i] = consts[argIdx1];
1416  }
1417  virtual void run_once()
1418  {
1420  }
1421  };
1422  struct StoreVar : public EvaluationStep
1423  {
1424  StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1425  : EvaluationStep(rn, i, l, r, s, c, p, v)
1426  {
1427  }
1428  virtual void run_many(ci n)
1429  {
1430  for (int i = 0; i < n; i++)
1431  state[storeIdx * n + i] = vars[argIdx1 * n + i];
1432  }
1433  virtual void run_once()
1434  {
1435  state[storeIdx] = vars[argIdx1];
1436  }
1437  };
1438  struct StorePrm : public EvaluationStep
1439  {
1440  StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1441  : EvaluationStep(rn, i, l, r, s, c, p, v)
1442  {
1443  }
1444  virtual void run_many(ci n)
1445  {
1446  for (int i = 0; i < n; i++)
1447  state[storeIdx * n + i] = params[argIdx1];
1448  }
1449  virtual void run_once()
1450  {
1452  }
1453  };
1454  struct EvalSum : public EvaluationStep
1455  {
1456  EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1457  : EvaluationStep(rn, i, l, r, s, c, p, v)
1458  {
1459  }
1460  virtual void run_many(ci n)
1461  {
1462  for (int i = 0; i < n; i++)
1463  state[storeIdx * n + i] =
1464  state[argIdx1 * n + i] + state[argIdx2 * n + i];
1465  }
1466  virtual void run_once()
1467  {
1469  }
1470  };
1471  struct EvalSub : public EvaluationStep
1472  {
1473  EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1474  : EvaluationStep(rn, i, l, r, s, c, p, v)
1475  {
1476  }
1477  virtual void run_many(ci n)
1478  {
1479  for (int i = 0; i < n; i++)
1480  state[storeIdx * n + i] =
1481  state[argIdx1 * n + i] - state[argIdx2 * n + i];
1482  }
1483  virtual void run_once()
1484  {
1486  }
1487  };
1488  struct EvalMul : public EvaluationStep
1489  {
1490  EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1491  : EvaluationStep(rn, i, l, r, s, c, p, v)
1492  {
1493  }
1494  virtual void run_many(ci n)
1495  {
1496  for (int i = 0; i < n; i++)
1497  state[storeIdx * n + i] =
1498  state[argIdx1 * n + i] * state[argIdx2 * n + i];
1499  }
1500  virtual void run_once()
1501  {
1503  }
1504  };
1505  struct EvalDiv : public EvaluationStep
1506  {
1507  EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1508  : EvaluationStep(rn, i, l, r, s, c, p, v)
1509  {
1510  }
1511  virtual void run_many(ci n)
1512  {
1513  for (int i = 0; i < n; i++)
1514  state[storeIdx * n + i] =
1515  state[argIdx1 * n + i] / state[argIdx2 * n + i];
1516  }
1517  virtual void run_once()
1518  {
1520  }
1521  };
1522  struct EvalPow : public EvaluationStep
1523  {
1524  EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1525  : EvaluationStep(rn, i, l, r, s, c, p, v)
1526  {
1527  }
1528  virtual void run_many(ci n)
1529  {
1530  for (int i = 0; i < n; i++)
1531  state[storeIdx * n + i] =
1532  std::pow(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1533  }
1534  virtual void run_once()
1535  {
1536  state[storeIdx] = std::pow(state[argIdx1], state[argIdx2]);
1537  }
1538  };
1539  struct EvalNeg : public EvaluationStep
1540  {
1541  EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1542  : EvaluationStep(rn, i, l, r, s, c, p, v)
1543  {
1544  }
1545  virtual void run_many(ci n)
1546  {
1547  for (int i = 0; i < n; i++)
1548  state[storeIdx * n + i] = -state[argIdx1 * n + i];
1549  }
1550  virtual void run_once()
1551  {
1552  state[storeIdx] = -state[argIdx1];
1553  }
1554  };
1556  {
1557  EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1558  : EvaluationStep(rn, i, l, r, s, c, p, v)
1559  {
1560  }
1561  virtual void run_many(ci n)
1562  {
1563  for (int i = 0; i < n; i++)
1564  state[storeIdx * n + i] =
1565  (state[argIdx1 * n + i] == state[argIdx2 * n + i]);
1566  }
1567  virtual void run_once()
1568  {
1570  }
1571  };
1573  {
1574  EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1575  : EvaluationStep(rn, i, l, r, s, c, p, v)
1576  {
1577  }
1578  virtual void run_many(ci n)
1579  {
1580  for (int i = 0; i < n; i++)
1581  state[storeIdx * n + i] =
1582  (state[argIdx1 * n + i] <= state[argIdx2 * n + i]);
1583  }
1584  virtual void run_once()
1585  {
1587  }
1588  };
1590  {
1591  EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1592  : EvaluationStep(rn, i, l, r, s, c, p, v)
1593  {
1594  }
1595  virtual void run_many(ci n)
1596  {
1597  for (int i = 0; i < n; i++)
1598  state[storeIdx * n + i] =
1599  (state[argIdx1 * n + i] < state[argIdx2 * n + i]);
1600  }
1601  virtual void run_once()
1602  {
1604  }
1605  };
1607  {
1608  EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1609  : EvaluationStep(rn, i, l, r, s, c, p, v)
1610  {
1611  }
1612  virtual void run_many(ci n)
1613  {
1614  for (int i = 0; i < n; i++)
1615  state[storeIdx * n + i] =
1616  (state[argIdx1 * n + i] >= state[argIdx2 * n + i]);
1617  }
1618  virtual void run_once()
1619  {
1621  }
1622  };
1624  {
1625  EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1626  : EvaluationStep(rn, i, l, r, s, c, p, v)
1627  {
1628  }
1629  virtual void run_many(ci n)
1630  {
1631  for (int i = 0; i < n; i++)
1632  state[storeIdx * n + i] =
1633  (state[argIdx1 * n + i] > state[argIdx2 * n + i]);
1634  }
1635  virtual void run_once()
1636  {
1638  }
1639  };
1640  struct EvalMod : public EvaluationStep
1641  {
1642  EvalMod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1643  : EvaluationStep(rn, i, l, r, s, c, p, v)
1644  {
1645  }
1646  virtual void run_many(ci n)
1647  {
1648  for (int i = 0; i < n; i++)
1649  state[storeIdx * n + i] =
1650  std::fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1651  }
1652  virtual void run_once()
1653  {
1654  state[storeIdx] = std::fmod(state[argIdx1], state[argIdx2]);
1655  }
1656  };
1657  struct EvalAbs : public EvaluationStep
1658  {
1659  EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1660  : EvaluationStep(rn, i, l, r, s, c, p, v)
1661  {
1662  }
1663  virtual void run_many(ci n)
1664  {
1665  for (int i = 0; i < n; i++)
1666  state[storeIdx * n + i] = std::abs(state[argIdx1 * n + i]);
1667  }
1668  virtual void run_once()
1669  {
1671  }
1672  };
1673  struct EvalSign : public EvaluationStep
1674  {
1675  EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1676  : EvaluationStep(rn, i, l, r, s, c, p, v)
1677  {
1678  }
1679  virtual void run_many(ci n)
1680  {
1681  for (int i = 0; i < n; i++)
1682  state[storeIdx * n + i] = ((state[argIdx1 * n + i] > 0.0) -
1683  (state[argIdx1 * n + i] < 0.0));
1684  }
1685  virtual void run_once()
1686  {
1687  state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0));
1688  }
1689  };
1690  struct EvalAsin : public EvaluationStep
1691  {
1692  EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1693  : EvaluationStep(rn, i, l, r, s, c, p, v)
1694  {
1695  }
1696  virtual void run_many(ci n)
1697  {
1698  for (int i = 0; i < n; i++)
1699  state[storeIdx * n + i] = std::asin(state[argIdx1 * n + i]);
1700  }
1701  virtual void run_once()
1702  {
1703  state[storeIdx] = std::asin(state[argIdx1]);
1704  }
1705  };
1706  struct EvalAcos : public EvaluationStep
1707  {
1708  EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1709  : EvaluationStep(rn, i, l, r, s, c, p, v)
1710  {
1711  }
1712  virtual void run_many(ci n)
1713  {
1714  for (int i = 0; i < n; i++)
1715  state[storeIdx * n + i] = std::acos(state[argIdx1 * n + i]);
1716  }
1717  virtual void run_once()
1718  {
1719  state[storeIdx] = std::acos(state[argIdx1]);
1720  }
1721  };
1722  struct EvalAtan : public EvaluationStep
1723  {
1724  EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1725  : EvaluationStep(rn, i, l, r, s, c, p, v)
1726  {
1727  }
1728  virtual void run_many(ci n)
1729  {
1730  for (int i = 0; i < n; i++)
1731  state[storeIdx * n + i] = std::atan(state[argIdx1 * n + i]);
1732  }
1733  virtual void run_once()
1734  {
1735  state[storeIdx] = std::atan(state[argIdx1]);
1736  }
1737  };
1738  struct EvalAtan2 : public EvaluationStep
1739  {
1740  EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1741  : EvaluationStep(rn, i, l, r, s, c, p, v)
1742  {
1743  }
1744  virtual void run_many(ci n)
1745  {
1746  for (int i = 0; i < n; i++)
1747  state[storeIdx * n + i] =
1748  std::atan2(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1749  }
1750  virtual void run_once()
1751  {
1752  state[storeIdx] = std::atan2(state[argIdx1], state[argIdx2]);
1753  }
1754  };
1755  struct EvalAng : public EvaluationStep
1756  {
1757  EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1758  : EvaluationStep(rn, i, l, r, s, c, p, v)
1759  {
1760  }
1761  virtual void run_many(ci n)
1762  {
1763  for (int i = 0; i < n; i++)
1764  state[storeIdx * n + i] =
1765  ang(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1766  }
1767  virtual void run_once()
1768  {
1770  }
1771  };
1772  struct EvalBessel : public EvaluationStep
1773  {
1774  EvalBessel(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1775  : EvaluationStep(rn, i, l, r, s, c, p, v)
1776  {
1777  }
1778  virtual void run_many(ci n)
1779  {
1780  for (int i = 0; i < n; i++)
1781  state[storeIdx * n + i] = boost::math::cyl_bessel_j(
1782  state[argIdx1 * n + i], state[argIdx2 * n + i]);
1783  }
1784  virtual void run_once()
1785  {
1786  state[storeIdx] =
1787  boost::math::cyl_bessel_j(state[argIdx1], state[argIdx2]);
1788  }
1789  };
1790  struct EvalCeil : public EvaluationStep
1791  {
1792  EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1793  : EvaluationStep(rn, i, l, r, s, c, p, v)
1794  {
1795  }
1796  virtual void run_many(ci n)
1797  {
1798  for (int i = 0; i < n; i++)
1799  state[storeIdx * n + i] = std::ceil(state[argIdx1 * n + i]);
1800  }
1801  virtual void run_once()
1802  {
1803  state[storeIdx] = std::ceil(state[argIdx1]);
1804  }
1805  };
1806  struct EvalCos : public EvaluationStep
1807  {
1808  EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1809  : EvaluationStep(rn, i, l, r, s, c, p, v)
1810  {
1811  }
1812  virtual void run_many(ci n)
1813  {
1814  for (int i = 0; i < n; i++)
1815  state[storeIdx * n + i] = std::cos(state[argIdx1 * n + i]);
1816  }
1817  virtual void run_once()
1818  {
1819  state[storeIdx] = std::cos(state[argIdx1]);
1820  }
1821  };
1822  struct EvalCosh : public EvaluationStep
1823  {
1824  EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1825  : EvaluationStep(rn, i, l, r, s, c, p, v)
1826  {
1827  }
1828  virtual void run_many(ci n)
1829  {
1830  for (int i = 0; i < n; i++)
1831  state[storeIdx * n + i] = std::cosh(state[argIdx1 * n + i]);
1832  }
1833  virtual void run_once()
1834  {
1835  state[storeIdx] = std::cosh(state[argIdx1]);
1836  }
1837  };
1838  struct EvalExp : public EvaluationStep
1839  {
1840  EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1841  : EvaluationStep(rn, i, l, r, s, c, p, v)
1842  {
1843  }
1844  virtual void run_many(ci n)
1845  {
1846  for (int i = 0; i < n; i++)
1847  state[storeIdx * n + i] = std::exp(state[argIdx1 * n + i]);
1848  }
1849  virtual void run_once()
1850  {
1851  state[storeIdx] = std::exp(state[argIdx1]);
1852  }
1853  };
1854  struct EvalFabs : public EvaluationStep
1855  {
1856  EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1857  : EvaluationStep(rn, i, l, r, s, c, p, v)
1858  {
1859  }
1860  virtual void run_many(ci n)
1861  {
1862  for (int i = 0; i < n; i++)
1863  state[storeIdx * n + i] = std::fabs(state[argIdx1 * n + i]);
1864  }
1865  virtual void run_once()
1866  {
1867  state[storeIdx] = std::fabs(state[argIdx1]);
1868  }
1869  };
1870  struct EvalFloor : public EvaluationStep
1871  {
1872  EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1873  : EvaluationStep(rn, i, l, r, s, c, p, v)
1874  {
1875  }
1876  virtual void run_many(ci n)
1877  {
1878  for (int i = 0; i < n; i++)
1879  state[storeIdx * n + i] = std::floor(state[argIdx1 * n + i]);
1880  }
1881  virtual void run_once()
1882  {
1883  state[storeIdx] = std::floor(state[argIdx1]);
1884  }
1885  };
1886  struct EvalFmod : public EvaluationStep
1887  {
1888  EvalFmod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1889  : EvaluationStep(rn, i, l, r, s, c, p, v)
1890  {
1891  }
1892  virtual void run_many(ci n)
1893  {
1894  for (int i = 0; i < n; i++)
1895  state[storeIdx * n + i] =
1896  fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1897  }
1898  virtual void run_once()
1899  {
1900  state[storeIdx] = fmod(state[argIdx1], state[argIdx2]);
1901  }
1902  };
1903  struct EvalLog : public EvaluationStep
1904  {
1905  EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1906  : EvaluationStep(rn, i, l, r, s, c, p, v)
1907  {
1908  }
1909  virtual void run_many(ci n)
1910  {
1911  for (int i = 0; i < n; i++)
1912  state[storeIdx * n + i] = std::log(state[argIdx1 * n + i]);
1913  }
1914  virtual void run_once()
1915  {
1917  }
1918  };
1919  struct EvalLog10 : public EvaluationStep
1920  {
1921  EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1922  : EvaluationStep(rn, i, l, r, s, c, p, v)
1923  {
1924  }
1925  virtual void run_many(ci n)
1926  {
1927  for (int i = 0; i < n; i++)
1928  state[storeIdx * n + i] = std::log10(state[argIdx1 * n + i]);
1929  }
1930  virtual void run_once()
1931  {
1932  state[storeIdx] = std::log10(state[argIdx1]);
1933  }
1934  };
1935  struct EvalRad : public EvaluationStep
1936  {
1937  EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1938  : EvaluationStep(rn, i, l, r, s, c, p, v)
1939  {
1940  }
1941  virtual void run_many(ci n)
1942  {
1943  for (int i = 0; i < n; i++)
1944  state[storeIdx * n + i] =
1945  rad(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1946  }
1947  virtual void run_once()
1948  {
1950  }
1951  };
1952  struct EvalSin : public EvaluationStep
1953  {
1954  EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1955  : EvaluationStep(rn, i, l, r, s, c, p, v)
1956  {
1957  }
1958  virtual void run_many(ci n)
1959  {
1960  for (int i = 0; i < n; i++)
1961  state[storeIdx * n + i] = std::sin(state[argIdx1 * n + i]);
1962  }
1963  virtual void run_once()
1964  {
1965  state[storeIdx] = std::sin(state[argIdx1]);
1966  }
1967  };
1968  struct EvalSinh : public EvaluationStep
1969  {
1970  EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1971  : EvaluationStep(rn, i, l, r, s, c, p, v)
1972  {
1973  }
1974  virtual void run_many(ci n)
1975  {
1976  for (int i = 0; i < n; i++)
1977  state[storeIdx * n + i] = std::sinh(state[argIdx1 * n + i]);
1978  }
1979  virtual void run_once()
1980  {
1981  state[storeIdx] = std::sinh(state[argIdx1]);
1982  }
1983  };
1984  struct EvalSqrt : public EvaluationStep
1985  {
1986  EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1987  : EvaluationStep(rn, i, l, r, s, c, p, v)
1988  {
1989  }
1990  virtual void run_many(ci n)
1991  {
1992  for (int i = 0; i < n; i++)
1993  state[storeIdx * n + i] = std::sqrt(state[argIdx1 * n + i]);
1994  }
1995  virtual void run_once()
1996  {
1998  }
1999  };
2000  struct EvalTan : public EvaluationStep
2001  {
2002  EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2003  : EvaluationStep(rn, i, l, r, s, c, p, v)
2004  {
2005  }
2006  virtual void run_many(ci n)
2007  {
2008  for (int i = 0; i < n; i++)
2009  state[storeIdx * n + i] = std::tan(state[argIdx1 * n + i]);
2010  }
2011  virtual void run_once()
2012  {
2013  state[storeIdx] = std::tan(state[argIdx1]);
2014  }
2015  };
2016  struct EvalTanh : public EvaluationStep
2017  {
2018  EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2019  : EvaluationStep(rn, i, l, r, s, c, p, v)
2020  {
2021  }
2022  virtual void run_many(ci n)
2023  {
2024  for (int i = 0; i < n; i++)
2025  state[storeIdx * n + i] = std::tanh(state[argIdx1 * n + i]);
2026  }
2027  virtual void run_once()
2028  {
2029  state[storeIdx] = std::tanh(state[argIdx1]);
2030  }
2031  };
2032  struct EvalAWGN : public EvaluationStep
2033  {
2034  EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2035  : EvaluationStep(rn, i, l, r, s, c, p, v)
2036  {
2037  }
2038  virtual void run_many(ci n)
2039  {
2040  // assuming the argument to AWGN does not depend on spatial
2041  // variables =>
2042  boost::variate_generator<boost::mt19937 &,
2043  boost::normal_distribution<>>
2044  _normal(rng,
2045  boost::normal_distribution<>(0, state[storeIdx * n]));
2046  for (int i = 0; i < n; i++)
2047  {
2048  state[storeIdx * n + i] = _normal();
2049  }
2050  }
2051  virtual void run_once()
2052  {
2053  boost::variate_generator<boost::mt19937 &,
2054  boost::normal_distribution<>>
2055  _normal(rng, boost::normal_distribution<>(0, state[storeIdx]));
2056  state[storeIdx] = _normal();
2057  }
2058  };
2059 };
2060 
2062 {
2063  m_impl = std::unique_ptr<ExpressionEvaluator>(new ExpressionEvaluator());
2064 }
2065 
2067 {
2068 }
2069 
2070 Interpreter::Interpreter(Interpreter &&r) : m_impl(std::move(r.m_impl))
2071 {
2072 }
2073 
2075 {
2076  m_impl = std::move(r.m_impl);
2077  return *this;
2078 }
2079 
2080 void Interpreter::SetRandomSeed(unsigned int seed)
2081 {
2082  m_impl->SetRandomSeed(seed);
2083 }
2084 
2086  std::map<std::string, NekDouble> const &constants)
2087 {
2088  m_impl->AddConstants(constants);
2089 }
2090 
2091 int Interpreter::AddConstant(std::string const &name, NekDouble value)
2092 {
2093  return m_impl->AddConstant(name, value);
2094 }
2095 
2097 {
2098  return m_impl->GetConstant(name);
2099 }
2100 
2101 void Interpreter::SetParameters(std::map<std::string, NekDouble> const &params)
2102 {
2103  m_impl->SetParameters(params);
2104 }
2105 
2106 void Interpreter::SetParameter(std::string const &name, NekDouble value)
2107 {
2108  m_impl->SetParameter(name, value);
2109 }
2110 
2112 {
2113  return m_impl->GetParameter(name);
2114 }
2115 
2117 {
2118  return m_impl->GetTime();
2119 }
2120 
2121 int Interpreter::DefineFunction(const std::string &vlist,
2122  const std::string &function)
2123 {
2124  return m_impl->DefineFunction(vlist, function);
2125 }
2126 
2127 NekDouble Interpreter::Evaluate(const int AnalyticExpression_id)
2128 {
2129  return m_impl->Evaluate(AnalyticExpression_id);
2130 }
2131 
2132 NekDouble Interpreter::Evaluate(const int AnalyticExpression_id,
2133  const NekDouble x, const NekDouble y,
2134  const NekDouble z, const NekDouble t)
2135 {
2136  return m_impl->Evaluate(AnalyticExpression_id, x, y, z, t);
2137 }
2138 
2139 NekDouble Interpreter::EvaluateAtPoint(const int AnalyticExpression_id,
2140  std::vector<NekDouble> point)
2141 {
2142  return m_impl->EvaluateAtPoint(AnalyticExpression_id, point);
2143 }
2144 
2145 void Interpreter::Evaluate(const int expression_id,
2150  Array<OneD, NekDouble> &result)
2151 {
2152  m_impl->Evaluate(expression_id, x, y, z, t, result);
2153 }
2154 
2156  const int expression_id,
2157  const std::vector<Array<OneD, const NekDouble>> &points,
2158  Array<OneD, NekDouble> &result)
2159 {
2160  m_impl->Evaluate(expression_id, points, result);
2161 }
2162 
2163 } // namespace LibUtilities
2164 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
#define LIB_UTILITIES_EXPORT
AnalyticExpression(const bsp::symbols< NekDouble > *constants, const std::vector< std::string > &variables)
Nektar::LibUtilities::Interpreter::ExpressionEvaluator::AnalyticExpression::variables variables_p
Concrete implementation of the interface defined in Interpreter.
void Evaluate(const int id, const Array< OneD, const NekDouble > &x, const Array< OneD, const NekDouble > &y, const Array< OneD, const NekDouble > &z, const Array< OneD, const NekDouble > &t, Array< OneD, NekDouble > &result)
Evaluate a function which depends only on constants and/or parameters.
int AddConstant(std::string const &name, NekDouble value)
Set constants to be evaluated.
void SetParameters(std::map< std::string, NekDouble > const &params)
Set parameter values.
EvaluationStep * makeStep(ci dest, ci src_left=0, ci src_right=0)
Factory method which makes code little less messy.
std::vector< int > m_state_sizes
Vector of state sizes per each.
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
NekDouble GetConstant(std::string const &name)
Return the value of a constant.
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
std::vector< const Array< OneD, const NekDouble > * > VariableArray
std::vector< VariableMap > m_stackVariableMap
Keeping map of variables individually per each analytic expression allows correctly handling expressi...
bsp::tree_match< std::string::const_iterator, bsp::node_val_data_factory< NekDouble > >::tree_iterator ParsedTreeIterator
NekDouble EvaluateAtPoint(const int id, const std::vector< NekDouble > point)
Evaluate a function which depends on zero or more variables.
NekDouble Evaluate(const int id, const NekDouble x, const NekDouble y, const NekDouble z, const NekDouble t)
Evaluate a function which depends only on constants and/or parameters.
void SetParameter(std::string const &name, NekDouble value)
Set parameter values.
ParameterMap m_parameterMapNameToId
The following data structures hold input data to be used on evaluation stage. There are three types o...
int m_state_size
This counter is used by PrepareExecutionAsYouParse for finding the minimal state size necessary for e...
NekDouble GetTime() const
Returns the total walltime spent in evaluation procedures in seconds.
NekDouble GetParameter(std::string const &name)
Get the value of a parameter.
bsp::tree_parse_info< std::string::const_iterator, bsp::node_val_data_factory< NekDouble > > ParsedTreeInfo
std::vector< NekDouble > & vr
Short names to minimise the infractructural code mess in defining functors below.
void SetRandomSeed(unsigned int seed)
Sets the random seed for the pseudorandom number generator.
std::vector< NekDouble > m_state
This vector stores the execution state (memory) used by the sequential execution process.
PrecomputedValue PrepareExecutionAsYouParse(const ParsedTreeIterator &location, ExecutionStack &stack, VariableMap &variableMap, int stateIndex)
Prepares an execution stack for the evaluation of a function.
void AddConstants(std::map< std::string, NekDouble > const &constants)
Set constants to be evaluated.
~ExpressionEvaluator(void)
Destructor that removes all entries from the execution stack.
void Evaluate(const int id, const std::vector< Array< OneD, const NekDouble >> &points, Array< OneD, NekDouble > &result)
Evaluate a function which depends only on constants and/or parameters.
ExpressionMap m_parsedMapExprToExecStackId
These vector and map store pre-processed evaluation sequences for the analytic expressions....
Interpreter class for the evaluation of mathematical expressions.
Definition: Interpreter.h:78
NekDouble GetTime() const
Returns the total walltime spent in evaluation procedures in seconds.
void AddConstants(std::map< std::string, NekDouble > const &constants)
Set constants to be evaluated.
std::unique_ptr< ExpressionEvaluator > m_impl
Concrete implementation of the above API calls.
Definition: Interpreter.h:319
Interpreter & operator=(Interpreter &&)
Default assignment operator.
NekDouble GetConstant(std::string const &name)
Return the value of a constant.
int AddConstant(std::string const &name, NekDouble value)
Set constants to be evaluated.
NekDouble EvaluateAtPoint(const int id, std::vector< NekDouble > point)
Evaluate a function which depends on zero or more variables.
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
void SetParameters(std::map< std::string, NekDouble > const &params)
Set parameter values.
void SetParameter(std::string const &name, NekDouble value)
Set parameter values.
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
NekDouble GetParameter(std::string const &name)
Get the value of a parameter.
void SetRandomSeed(unsigned int seed=123u)
Sets the random seed for the pseudorandom number generator.
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:68
NekDouble(* PFD1)(NekDouble)
NekDouble(* PFD2)(NekDouble, NekDouble)
static NekDouble rad(NekDouble x, NekDouble y)
NekDouble awgn(NekDouble sigma)
static NekDouble ang(NekDouble x, NekDouble y)
NekDouble(* PFD4)(NekDouble, NekDouble, NekDouble, NekDouble)
NekDouble(* PFD3)(NekDouble, NekDouble, NekDouble)
NekDouble sign(NekDouble arg)
Nektar::LibUtilities::functions functions_p
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:444
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
bsp::rule< ScannerT, bsp::parser_context<>, bsp::parser_tag< N > > bsp_rule
CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalBessel(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalFmod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalMod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)=0
declaring this guy pure virtual shortens virtual table. It saves some execution time.
ci storeIdx
indices in the above arrays uniquely defining actual command arguments
EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.