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