Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AnalyticExpressionEvaluator.cpp
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 
38 #include <stdexcept>
39 #include <algorithm>
40 #include <iostream>
41 #include <boost/lexical_cast.hpp>
42 #include <boost/algorithm/string/trim.hpp>
43 #include <boost/random/detail/seed.hpp>
44 
45 #ifdef _MSC_VER
46 #include <boost/preprocessor/cat.hpp>
47 #endif //MSC_VER
48 
49 #ifdef _MSC_VER
50 #define NEKTAR_MATH_NAME(x) BOOST_PP_CAT(_, x)
51 #else
52 #define NEKTAR_MATH_NAME(x) x
53 #endif
54 
55 #if( BOOST_VERSION / 100 % 1000 >= 36 )
56 using namespace boost::spirit::classic;
57 #else
58 using namespace boost::spirit;
59 #endif
60 
61 // trying to avoid incompatibility between standart <algorithm> header and
62 // windows.h header which defines max and min macros.
63 using std::min;
64 
65 namespace Nektar
66 {
67  namespace LibUtilities
68  {
69 
70  // =========================================================================
71  // AnalyticExpression definitions for Spirit Parser
72  // =========================================================================
73 
74  typedef NekDouble (*PFD)();
75  typedef NekDouble (*PFD1)(NekDouble);
79  struct func
80  {
81  func(PFD1 p) : func1(p), size(1) {};
82  func(PFD2 p) : func2(p), size(2) {};
83  func(PFD3 p) : func3(p), size(3) {};
84  func(PFD4 p) : func4(p), size(4) {};
85 
86  union // Pointer to a function
87  {
92  };
93  size_t size;
94  };
95 
96  // signum function
98  {
99  return (arg > 0.0) - (arg < 0.0);
100  }
101 
102  // Additive white Gaussian noise function.
103  // Arg: sigma of the zero-mean gaussian distribution
104  // Attention: this function is not actually used for
105  // evaluation purposes.
107  {
109  boost::variate_generator<
111  boost::normal_distribution<>
112  > _normal(rng, boost::normal_distribution<>(0, sigma) );
113  return _normal();
114  }
115 
116 
117  /** This struct creates a parser that matches the function
118  definitions from math.h. All of the functions accept one
119  of more NekDoubles as arguments and returns a NekDouble. **/
120  static struct functions : symbols<func>
121  {
123  {
124  // Add all of the functions from math.h
125  add
126  ("abs", std::abs)
127  ("asin", asin)
128  ("acos", acos)
129  ("atan", atan)
130  ("ceil", ceil)
131  ("cos", cos)
132  ("cosh", cosh)
133  ("exp", exp)
134  ("fabs", fabs) // same as abs
135  ("floor", floor)
136  ("log", log)
137  ("log10", log10)
138  ("sin", sin)
139  ("sinh", sinh)
140  ("sqrt", sqrt)
141  ("tan", tan)
142  ("tanh", tanh)
143  // and few more custom functions
144  ("sign", sign)
145  ("awgn", awgn)
146  ;
147  }
148  } functions_p;
149 
150 
151  /** This function specifies the grammar of the MathAnalyticExpression parser. **/
152  template <typename ScannerT>
154  {
155  expression = logical_or;
156 
157  logical_or = logical_and >> *( (root_node_d[str_p("||")] >> logical_and) );
158 
159  logical_and = equality >> *( (root_node_d[str_p("&&")] >> equality) );
160 
161  equality = lt_gt >> *( (root_node_d[str_p("==")] >> lt_gt) );
162 
163  lt_gt = add_sub >>
164  *( (root_node_d[str_p("<=")] >> add_sub)
165  | (root_node_d[str_p(">=")] >> add_sub)
166  | (root_node_d[ch_p('<')] >> add_sub)
167  | (root_node_d[ch_p('>')] >> add_sub)
168  );
169 
170  add_sub = mult_div >>
171  *( (root_node_d[ch_p('+')] >> mult_div)
172  | (root_node_d[ch_p('-')] >> mult_div)
173  );
174 
175  mult_div = exponential >>
176  *( (root_node_d[ch_p('*')] >> exponential)
177  | (root_node_d[ch_p('/')] >> exponential)
178  );
179 
180  exponential = factor >>
181  *( (root_node_d[ch_p('^')] >> factor) );
182 
183  factor = number
184  | function
185  | variable
186  | constant
187  | parameter
188  | inner_node_d[ch_p('(') >> expression >> ch_p(')')]
189  | (root_node_d[ch_p('-')] >> factor);
190 
191  parameter = leaf_node_d[ lexeme_d[
192  (alpha_p | '_' | '$') >> *(alnum_p | '_' | '$')
193  ] ] >> op;
194 
195  function = root_node_d[functions_p] >>
196  infix_node_d[inner_node_d[ch_p('(') >> expression >> *(',' >> expression) >> ch_p(')')]];
197 
198  variable = leaf_node_d[ lexeme_d[
199  self.variables_p
200  ] ] >> op;
201 
202  number = leaf_node_d[ lexeme_d[
203  real_p
204  ] ] >> op;
205 
206  constant = leaf_node_d[ lexeme_d[
207  *self.constants_p
208  ] ] >> op;
209 
210  op = eps_p( end_p | "||" | "&&" | "==" | "<=" | ">=" | '<' | '>' | '+' | '-' | '*' | '/' | '^' | ')' );
211  }
212 
213  // =========================================================================
214  // AnalyticExpressionEvaluator constructor and setting up methods
215  // =========================================================================
216 
217  // \brief Initializes the evaluator. Call DefineFunction(...) next.
218  AnalyticExpressionEvaluator::AnalyticExpressionEvaluator():
219  m_timer(),
220  m_total_eval_time(0)
221  {
222  m_state_size = 1;
223 
224  AddConstant("MEANINGLESS", 0.0);
225  AddConstant("E", 2.71828182845904523536); // Natural logarithm
226  AddConstant("LOG2E", 1.4426950408889634074); // log_2 e
227  AddConstant("LOG10E", 0.43429448190325182765); // log_10 e
228  AddConstant("LN2", 0.69314718055994530942); // log_e 2
229  AddConstant("LN10", 2.30258509299404568402); // log_e 10
230  AddConstant("PI", 3.14159265358979323846); // pi
231  AddConstant("PI_2", 1.57079632679489661923); // pi/2
232  AddConstant("PI_4", 0.78539816339744830962); // pi/4
233  AddConstant("1_PI", 0.31830988618379067154); // 1/pi
234  AddConstant("2_PI", 0.63661977236758134308); // 2/pi
235  AddConstant("2_SQRTPI", 1.12837916709551257390); // 2/sqrt(pi)
236  AddConstant("SQRT2", 1.41421356237309504880); // sqrt(2)
237  AddConstant("SQRT1_2", 0.70710678118654752440); // 1/sqrt(2)
238  AddConstant("GAMMA", 0.57721566490153286060); // Euler
239  AddConstant("DEG", 57.2957795130823208768); // deg/radian
240  AddConstant("PHI", 1.61803398874989484820); // golden ratio
241 
261 
262  m_function[ E_ABS ] = std::abs;
263  m_function[ E_ASIN ] = asin;
264  m_function[ E_ACOS ] = acos;
265  m_function[ E_ATAN ] = atan;
266  m_function[ E_CEIL ] = ceil;
267  m_function[ E_COS ] = cos;
268  m_function[ E_COSH ] = cosh;
269  m_function[ E_EXP ] = exp;
270  m_function[ E_FABS ] = fabs;
271  m_function[ E_FLOOR] = floor;
272  m_function[ E_LOG ] = log;
273  m_function[ E_LOG10] = log10;
274  m_function[ E_SIN ] = sin;
275  m_function[ E_SINH ] = sinh;
276  m_function[ E_SQRT ] = sqrt;
277  m_function[ E_TAN ] = tan;
278  m_function[ E_TANH ] = tanh;
279  m_function[ E_SIGN ] = sign;
280  // there is no entry to m_function that correspond to awgn function.
281  // this is made in purpose. This function need not be pre-evaluated once!
282  }
283 
284 
286  {
287  for (std::vector<ExecutionStack>::iterator it_es = m_executionStack.begin(); it_es != m_executionStack.end(); ++it_es)
288  {
289  for (std::vector<EvaluationStep*>::iterator it = (*it_es).begin(); it != (*it_es).end(); ++it)
290  {
291  delete *it;
292  }
293  (*it_es).clear();
294  }
295  m_executionStack.clear();
296  }
297 
298 
300  {
301  m_generator.seed(seed);
302  }
303 
304 
305  void AnalyticExpressionEvaluator::AddConstants(std::map<std::string, NekDouble> const& constants)
306  {
307  for (std::map<std::string, NekDouble>::const_iterator it = constants.begin(); it != constants.end(); ++it)
308  {
309  AddConstant(it->first, it->second);
310  }
311  }
312 
313  int AnalyticExpressionEvaluator::AddConstant(std::string const& name, NekDouble value)
314  {
315  ConstantMap::const_iterator it = m_constantMapNameToId.find(name);
316  if (it == m_constantMapNameToId.end())
317  {
318  // we are trying to avoid duplicating entries in m_constantParser and m_constants
319  m_constantsParser.add(name.c_str(), value);
320  int index = m_constant.size();
321  m_constantMapNameToId[name] = index;
322  m_constant.push_back(value);
323  return index;
324  }
325  else
326  {
327  if(m_constant[it->second] != value)
328  {
329  std::string errormsg("Attempt to add numerically different constants under the same name: ");
330  errormsg += name;
331  std::cout << errormsg << std::endl;
332  }
333  //ASSERTL1(m_constant[it->second] == value, "Attempt to add numerically different constants under the same name: " + name);
334  }
335  return it->second;
336  }
337 
339  {
340  NekDouble* value = find(m_constantsParser, name.c_str());
341 
342  ASSERTL1(value != NULL, "Constant variable not found: " + name);
343 
344  return *value;
345  }
346 
347  void AnalyticExpressionEvaluator::SetParameters(std::map<std::string, NekDouble> const& params)
348  {
349  for (std::map<std::string, NekDouble>::const_iterator it = params.begin(); it != params.end(); it++)
350  {
351  SetParameter(it->first, it->second);
352  }
353  }
354 
355  void AnalyticExpressionEvaluator::SetParameter(std::string const& name, NekDouble value)
356  {
357  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
358  if (it == m_parameterMapNameToId.end())
359  {
360  m_parameterMapNameToId[name] = m_parameter.size();
361  m_parameter.push_back(value);
362  }
363  else
364  {
365  // if parameter is known, change its value
366  m_parameter[ it->second ] = value;
367  }
368  }
369 
370 
372  {
373  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
374 
375  ASSERTL1(it != m_parameterMapNameToId.end(), "Parameter not found: " + name);
376 
377  return m_parameter[ it->second ];
378  }
379 
380 
382  {
383  return m_total_eval_time;
384  }
385 
386 
387  // ======================================================
388  // Public evaluate methods
389  // ======================================================
390 
391  int AnalyticExpressionEvaluator::DefineFunction(const std::string& vlist, const std::string& expr)
392  {
393  // Find the previous parsing.
394  ExpressionMap::const_iterator it = m_parsedMapExprToExecStackId.find(expr);
395  if (it != m_parsedMapExprToExecStackId.end())
396  {
397  // if this function is already defined, don't do anything but
398  // return its ID.
399  return it->second;
400  }
401 
402  // ----------------------------------------------
403  // Prepare an iterator that allows to walk along
404  // the string representing an analytic expression in the order
405  // that respects its recursive structure (thanks to boost::spirit).
406  // ----------------------------------------------
407 
408  // Parse the vlist input and separate the variables into ordered entries
409  // in a vector<string> object. These need to be ordered because this is
410  // the order the variables will get assigned to in the Map when Evaluate(...)
411  // is called.
412  std::vector<std::string> variableNames;
413  parse((char*) vlist.c_str(), ( *space_p >>
414  *(
415  +(+graph_p)[push_back_a(variableNames)]
416  >> +space_p
417  )
418  )
419  );
420  // Set up our grammar
421  AnalyticExpression myGrammar(&m_constantsParser, variableNames);
422 
423  // Do the actual parsing with boost::spirit and alert the user if there was an error with an exception.
424  ParsedTreeInfo parseInfo = ast_parse<
425  node_val_data_factory<NekDouble>,
426  std::string::const_iterator,
428  space_parser
429  >
430  (expr.begin(), expr.end(), myGrammar, space_p);
431 
432  ASSERTL1(parseInfo.full != false, "Unable to fully parse function. Stopped just before: "
433  + std::string(parseInfo.stop, parseInfo.stop + 15));
434 
435  // ----------------------------------------------
436  // Data parsed, start setting up internal data structures.
437  // ----------------------------------------------
438 
439  ExecutionStack stack;
440  VariableMap variableMap;
441 
442  int stackId = m_executionStack.size();
443  m_state_size = 1;
444 
445  // register all variables declared in the expression
446  for (int i = 0; i < variableNames.size(); i++)
447  {
448  variableMap[variableNames[i]] = i;
449  }
450 
451  // then prepare an execution stack.
452  // this method also calculates a length of internal
453  // state storage (m_state_size) for this function.
454  PrecomputedValue v = PrepareExecutionAsYouParse(parseInfo.trees.begin(), stack, variableMap, 0);
455 
456  // constant expression, fully evaluated
457  if (true == v.first)
458  {
459  ASSERTL1(stack.size() == 0, "Constant expression yeilds non-empty execution stack. Bug in PrepareExecutionAsYouParse()");
460 
461  int const_index = AddConstant(std::string("EXPRESSION_") + boost::lexical_cast<std::string>(stackId), v.second);
462  stack.push_back ( makeStep<StoreConst>( 0, const_index ) );
463  }
464 
465  m_parsedMapExprToExecStackId[expr] = stackId;
466 
467  // the execution stack and its corresponding variable index map are
468  // two parallel std::vectors that share their ids. This split helps
469  // to achieve some performance improvement.
470  m_executionStack.push_back(stack);
471  m_stackVariableMap.push_back(variableMap);
472  m_state_sizes.push_back(m_state_size);
473  return stackId;
474  }
475 
476 
478  {
479  m_timer.Start();
480 
481  ASSERTL1(m_executionStack.size() > expression_id, "unknown analytic expression, it must first be defined with DefineFunction(...)");
482 
483  ExecutionStack &stack = m_executionStack[expression_id];
484 
485  m_state.resize(m_state_sizes[expression_id]);
486  for (int i = 0; i < stack.size(); i++)
487  {
488  (*stack[i]).run_once();
489  }
490 
491  m_timer.Stop();
493 
494  return m_state[0];
495  }
496 
498  const int expression_id,
499  const NekDouble x,
500  const NekDouble y,
501  const NekDouble z,
502  const NekDouble t)
503  {
504  m_timer.Start();
505 
506  ASSERTL1(m_executionStack.size() > expression_id, "unknown analytic expression, it must first be defined with DefineFunction(...)");
507 
508  ExecutionStack &stack = m_executionStack[expression_id];
509 
510  // initialise internal vector of variable values
511  m_state.resize(m_state_sizes[expression_id]);
512 
513  if (m_variable.size() < 4)
514  {
515  m_variable.resize(4);
516  }
517 
518  // no flexibility, no change of variable ordering in m_variable
519  // container depending on their names ordering in the input vlist
520  // argument of DefineFunction. Ordering convention (x,y,z,t) is assumed.
521  m_variable[0] = x;
522  m_variable[1] = y;
523  m_variable[2] = z;
524  m_variable[3] = t;
525 
526  // main execution cycle is hidden here
527  for (int i = 0; i < stack.size(); i++)
528  {
529  (*stack[i]).run_once();
530  }
531 
532  m_timer.Stop();
534 
535  return m_state[0];
536  }
537 
538  NekDouble AnalyticExpressionEvaluator::EvaluateAtPoint(const int expression_id, const std::vector<NekDouble> point)
539  {
540  m_timer.Start();
541 
542  ASSERTL1(m_executionStack.size() > expression_id, "unknown analytic expression, it must first be defined with DefineFunction(...)");
543 
544  ExecutionStack& stack = m_executionStack[expression_id];
545  VariableMap& variableMap = m_stackVariableMap[expression_id];
546 
547  ASSERTL1(point.size() == variableMap.size(), "The number of variables used to define this expression should match the point dimensionality.");
548 
549  // initialise internal vector of variable values
550  m_state.resize(m_state_sizes[expression_id]);
551  m_variable.resize(point.size());
552  VariableMap::const_iterator it;
553  for (it = variableMap.begin(); it != variableMap.end(); ++it)
554  {
555  m_variable[it->second] = point[it->second];
556  }
557  // main execution cycle is hidden here
558  for (int i = 0; i < stack.size(); i++)
559  {
560  (*stack[i]).run_once();
561  }
562 
563  m_timer.Stop();
565 
566  return m_state[0];
567  }
568 
569 
571  const int expression_id,
572  const Array<OneD, const NekDouble>& x,
573  const Array<OneD, const NekDouble>& y,
574  const Array<OneD, const NekDouble>& z,
575  const Array<OneD, const NekDouble>& t,
576  Array<OneD, NekDouble>& result)
577  {
578  m_timer.Start();
579 
580  const int num_points = x.num_elements();
581  ASSERTL1(m_executionStack.size() > expression_id, "unknown analytic expression, it must first be defined with DefineFunction(...)");
582  ASSERTL1(result.num_elements() >= num_points, "destination array must have enough capacity to store expression values at each given point");
583 
584  ExecutionStack &stack = m_executionStack[expression_id];
585 
586  /// If number of points tends to 10^6, one may end up
587  /// with up to ~0.5Gb data allocated for m_state only.
588  /// Lets split the work into cache-sized chunks.
589  /// Ahtung, magic constant!
590  const int max_chunk_size = 1024;
591 
592  /// please don't remove brackets around std::min, it screws up windows compilation
593  const int chunk_size = (std::min)(max_chunk_size, num_points);
594  if (m_state.size() < chunk_size * m_state_sizes[expression_id] )
595  {
596  m_state.resize( m_state_sizes[expression_id] * chunk_size, 0.0 );
597  }
598  if (m_variable.size() < 4 * chunk_size )
599  {
600  m_variable.resize( 4 * chunk_size, 0.0);
601  }
602  if (result.num_elements() < num_points)
603  {
604  result = Array<OneD, NekDouble>(num_points, 0.0);
605  }
606 
607  int offset = 0;
608  int work_left = num_points;
609  while(work_left > 0)
610  {
611  const int this_chunk_size = (std::min)(work_left, 1024);
612  for (int i = 0; i < this_chunk_size; i++)
613  {
614  m_variable[i+this_chunk_size*0] = x[offset + i];
615  m_variable[i+this_chunk_size*1] = y[offset + i];
616  m_variable[i+this_chunk_size*2] = z[offset + i];
617  m_variable[i+this_chunk_size*3] = t[offset + i];
618  }
619  for (int i = 0; i < stack.size(); i++)
620  {
621  (*stack[i]).run_many(this_chunk_size);
622  }
623  for (int i = 0; i < this_chunk_size; i++)
624  {
625  result[offset + i] = m_state[i];
626  }
627  work_left -= this_chunk_size;
628  offset += this_chunk_size;
629  }
630  m_timer.Stop();
632  }
633 
634 
636  const int expression_id,
637  const std::vector<Array<OneD, const NekDouble> > points,
638  Array<OneD, NekDouble>& result)
639  {
640  m_timer.Start();
641 
642  /// \todo test this function properly/update as the method above
643 
644  ASSERTL1(m_executionStack.size() > expression_id, "unknown analytic expression, it must first be defined with DefineFunction(...)");
645 
646  ExecutionStack& stack = m_executionStack[expression_id];
647  VariableMap& variableMap = m_stackVariableMap[expression_id];
648 
649  const int num = points[0].num_elements();
650  m_state.resize(m_state_sizes[expression_id]*num);
651 
652  // assuming all points have same # of coordinates
653  m_variable.resize(4*num,0.0);
654 
655  for (int i = 0; i < points.size(); i++)
656  {
657  for (VariableMap::const_iterator it = variableMap.begin(); it != variableMap.end(); ++it)
658  {
659  m_variable[it->second] = points[i][it->second];
660  }
661  }
662  for (int j = 0; j < stack.size(); j++)
663  {
664  (*stack[j]).run_many(num);
665  }
666  for (int i = 0; i < num; ++i)
667  {
668  result[i] = m_state[i];
669  }
670 
671  m_timer.Stop();
673  }
674 
675 
676 
678  const ParsedTreeIterator& location,
679  ExecutionStack& stack,
680  VariableMap& variableMap,
681  int stateIndex)
682  {
683  std::string valueStr(location->value.begin(), location->value.end());
684  boost::algorithm::trim(valueStr);
685 
686  const parser_id parserID = location->value.id();
687 #if defined(NEKTAR_DEBUG) || defined(NEKTAR_FULLDEBUG)
688  const int num_children = location->children.size();
689 #endif
690 
691  if (parserID == AnalyticExpression::constantID)
692  {
693  ASSERTL1(num_children == 0, "Illegal children under constant node: " + valueStr);
694 
695  ConstantMap::const_iterator it = m_constantMapNameToId.find(valueStr);
696  ASSERTL1(it != m_constantMapNameToId.end(), "Cannot find the value for the specified constant: " + valueStr);
697 
698  return std::make_pair(true, m_constant[it->second]);
699  }
700  else if (parserID == AnalyticExpression::numberID)
701  {
702  ASSERTL1(num_children == 0, "Illegal children under number node: " + valueStr);
703  return std::make_pair(true, boost::lexical_cast<NekDouble>(valueStr.c_str()) );
704  }
705  else if (parserID == AnalyticExpression::variableID)
706  {
707  ASSERTL1(num_children == 0, "Illegal children under variable node: " + valueStr);
708 
709  VariableMap::const_iterator it = variableMap.find(valueStr);
710  ASSERTL1(it != variableMap.end(), "Unknown variable parsed: " + valueStr);
711 
712  // Variables are not defined at the time of this parse.
713  stack.push_back ( makeStep<StoreVar>( stateIndex, it->second ) );
714  return std::make_pair(false, 0);
715  }
716  else if (parserID == AnalyticExpression::parameterID)
717  {
718  ASSERTL1(num_children == 0, "Illegal children under parameter node: " + valueStr);
719 
720  ParameterMap::const_iterator it = m_parameterMapNameToId.find(valueStr);
721  ASSERTL1(it != m_parameterMapNameToId.end(), "Unknown parameter parsed: " + valueStr);
722 
723  // Parameters may change in between of evalutions.
724  stack.push_back ( makeStep<StorePrm>( stateIndex, it->second ) );
725  return std::make_pair(false, 0);
726  }
727  else if (parserID == AnalyticExpression::functionID)
728  {
729  FunctionNameMap::const_iterator it = m_functionMapNameToInstanceType.find(valueStr);
730  ASSERTL1(it != m_functionMapNameToInstanceType.end(), "Invalid function specified: " + valueStr);
731  ASSERTL1(num_children == 1, "Function " + valueStr + " would like to have too few or too many arguments. This is not implemented yet");
732 
733  PrecomputedValue v = PrepareExecutionAsYouParse(location->children.begin(), stack, variableMap, stateIndex);
734 
735  // additive white gaussian noise function
736  if (it->second == E_AWGN)
737  {
738  int const_index = AddConstant(std::string("SUB_EXPR_") + boost::lexical_cast<std::string>(m_constant.size()), v.second);
739  stack.push_back ( makeStep<StoreConst>( stateIndex, const_index ) );
740  stack.push_back ( makeStep<EvalAWGN>( stateIndex, stateIndex ) );
741  return std::make_pair(false,0);
742  }
743 
744  // if precomputed value is valid, return function(value).
745  if (true == v.first)
746  {
747  return std::make_pair( true, m_function[it->second](v.second) );
748  }
749 
750 
751  // if somewhere down the parse tree there is a variable or parameter, set up an
752  // evaluation sequence.
753  switch (it->second)
754  {
755  case E_ABS:
756  stack.push_back ( makeStep<EvalAbs>( stateIndex, stateIndex) );
757  return std::make_pair(false,0);
758  case E_ASIN:
759  stack.push_back ( makeStep<EvalAsin>( stateIndex, stateIndex) );
760  return std::make_pair(false,0);
761  case E_ACOS:
762  stack.push_back ( makeStep<EvalAcos>( stateIndex, stateIndex ) );
763  return std::make_pair(false,0);
764  case E_ATAN:
765  stack.push_back ( makeStep<EvalAtan>( stateIndex, stateIndex ) );
766  return std::make_pair(false,0);
767  case E_CEIL:
768  stack.push_back ( makeStep<EvalCeil>( stateIndex, stateIndex ) );
769  return std::make_pair(false,0);
770  case E_COS:
771  stack.push_back ( makeStep<EvalCos>( stateIndex, stateIndex ) );
772  return std::make_pair(false,0);
773  case E_COSH:
774  stack.push_back ( makeStep<EvalCosh>( stateIndex, stateIndex ) );
775  return std::make_pair(false,0);
776  case E_EXP:
777  stack.push_back ( makeStep<EvalExp>( stateIndex, stateIndex ) );
778  return std::make_pair(false,0);
779  case E_FABS:
780  stack.push_back ( makeStep<EvalFabs>( stateIndex, stateIndex ) );
781  return std::make_pair(false,0);
782  case E_FLOOR:
783  stack.push_back ( makeStep<EvalFloor>( stateIndex, stateIndex ) );
784  return std::make_pair(false,0);
785  case E_LOG:
786  stack.push_back ( makeStep<EvalLog>( stateIndex, stateIndex ) );
787  return std::make_pair(false,0);
788  case E_LOG10:
789  stack.push_back ( makeStep<EvalLog10>( stateIndex, stateIndex ) );
790  return std::make_pair(false,0);
791  case E_SIN:
792  stack.push_back ( makeStep<EvalSin>( stateIndex, stateIndex ) );
793  return std::make_pair(false,0);
794  case E_SINH:
795  stack.push_back ( makeStep<EvalSinh>( stateIndex, stateIndex ) );
796  return std::make_pair(false,0);
797  case E_SQRT:
798  stack.push_back ( makeStep<EvalSqrt>( stateIndex, stateIndex ) );
799  return std::make_pair(false,0);
800  case E_TAN:
801  stack.push_back ( makeStep<EvalTan>( stateIndex, stateIndex ) );
802  return std::make_pair(false,0);
803  case E_TANH:
804  stack.push_back ( makeStep<EvalTanh>( stateIndex, stateIndex ) );
805  return std::make_pair(false,0);
806  case E_SIGN:
807  stack.push_back ( makeStep<EvalSign>( stateIndex, stateIndex ) );
808  return std::make_pair(false,0);
809  default:
810  ASSERTL0(false, "Evaluation of " + valueStr + " is not implemented yet");
811  }
812  return std::make_pair(false,0);
813  }
814  else if (parserID == AnalyticExpression::factorID)
815  {
816  ASSERTL1(*valueStr.begin() == '-', "Illegal factor - it can only be '-' and it was: " + valueStr);
817  ASSERTL1(num_children == 1, "Illegal number of children under factor node: " + valueStr);
818 
819  PrecomputedValue v = PrepareExecutionAsYouParse(location->children.begin(), stack, variableMap, stateIndex);
820 
821  // if precomputed value is valid, process it further.
822  if (true == v.first)
823  {
824  return std::make_pair( true, - v.second );
825  }
826  stack.push_back (makeStep<EvalNeg>( stateIndex, stateIndex) );
827  return std::make_pair(false,0);
828  }
829  else if (parserID == AnalyticExpression::operatorID)
830  {
831  ASSERTL1(num_children == 2, "Too few or too many arguments for mathematical operator: " + valueStr);
832  PrecomputedValue left = PrepareExecutionAsYouParse(location->children.begin()+0, stack, variableMap, stateIndex);
833  PrecomputedValue right = PrepareExecutionAsYouParse(location->children.begin()+1, stack, variableMap, stateIndex+1);
834  m_state_size++;
835 
836  // if both precomputed values are valid, process them further.
837  if ((true == left.first) && (true == right.first))
838  {
839  switch(*valueStr.begin())
840  {
841  case '+':
842  return std::make_pair( true, left.second + right.second );
843  case '-':
844  return std::make_pair( true, left.second - right.second );
845  case '*':
846  return std::make_pair( true, left.second * right.second );
847  case '/':
848  return std::make_pair( true, left.second / right.second );
849  case '^':
850  return std::make_pair( true, std::pow(left.second, right.second) );
851  case '=':
852  return std::make_pair( true, left.second == right.second );
853  case '<':
854  if (*(valueStr.end()-1) == '=')
855  {
856  return std::make_pair( true, left.second <= right.second );
857  }
858  else
859  {
860  return std::make_pair( true, left.second < right.second );
861  }
862  return std::make_pair(false,0);
863  case '>':
864  if (*(valueStr.end()-1) == '=')
865  {
866  return std::make_pair( true, left.second >= right.second );
867  }
868  else
869  {
870  return std::make_pair( true, left.second > right.second );
871  }
872  return std::make_pair(false,0);
873  default:
874  ASSERTL0(false, "Invalid operator encountered: " + valueStr);
875  }
876  return std::make_pair(false,0);
877  }
878 
879  // either operator argument is not fully evaluated
880  // add pre-evaluated value to the contaner of constants
881  if (true == left.first)
882  {
883  int const_index = AddConstant(std::string("SUB_EXPR_") + boost::lexical_cast<std::string>(m_constant.size()), left.second);
884  stack.push_back ( makeStep<StoreConst>( stateIndex, const_index ) );
885  }
886  if (true == right.first)
887  {
888  int const_index = AddConstant(std::string("SUB_EXPR_") + boost::lexical_cast<std::string>(m_constant.size()), right.second);
889  stack.push_back ( makeStep<StoreConst>( stateIndex+1, const_index ) );
890  }
891 
892 
893  switch(*valueStr.begin())
894  {
895  case '+':
896  stack.push_back (makeStep<EvalSum>( stateIndex, stateIndex, stateIndex+1 ) );
897  return std::make_pair(false,0);
898  case '-':
899  stack.push_back (makeStep<EvalSub> (stateIndex, stateIndex, stateIndex+1 ) );
900  return std::make_pair(false,0);
901  case '*':
902  stack.push_back (makeStep<EvalMul>( stateIndex, stateIndex, stateIndex+1 ) );
903  return std::make_pair(false,0);
904  case '/':
905  stack.push_back (makeStep<EvalDiv>( stateIndex, stateIndex, stateIndex+1 ) );
906  return std::make_pair(false,0);
907  case '^':
908  stack.push_back (makeStep<EvalPow>( stateIndex, stateIndex, stateIndex+1 ) );
909  return std::make_pair(false,0);
910  case '=':
911  stack.push_back (makeStep<EvalLogicalEqual>( stateIndex, stateIndex, stateIndex+1 ) );
912  return std::make_pair(false,0);
913  case '<':
914  if (*(valueStr.end()-1) == '=')
915  {
916  stack.push_back (makeStep<EvalLogicalLeq>( stateIndex, stateIndex, stateIndex+1 ) );
917  }
918  else
919  {
920  stack.push_back (makeStep<EvalLogicalLess>( stateIndex, stateIndex, stateIndex+1 ) );
921  }
922  return std::make_pair(false,0);
923 
924  case '>':
925  if (*(valueStr.end()-1) == '=')
926  {
927  stack.push_back (makeStep<EvalLogicalGeq>( stateIndex, stateIndex, stateIndex+1 ) );
928  }
929  else
930  {
931  stack.push_back (makeStep<EvalLogicalGreater>( stateIndex, stateIndex, stateIndex+1 ) );
932  }
933  return std::make_pair(false,0);
934 
935  default:
936  ASSERTL0(false, "Invalid operator encountered: " + valueStr);
937  }
938  return std::make_pair(false,0);
939  }
940  ASSERTL0(false, "Illegal expression encountered: " + valueStr);
941  return std::make_pair(false,0);
942  }
943 
944  };
945 };