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