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 case '>':
980 if (*(valueStr.end() - 1) == '=')
981 {
982 return std::make_pair(true,
983 left.second >= right.second);
984 }
985 else
986 {
987 return std::make_pair(true,
988 left.second > right.second);
989 }
990 default:
991 ASSERTL0(false,
992 "Invalid operator encountered: " + valueStr);
993 }
994 return std::make_pair(false, 0);
995 }
996
997 // either operator argument is not fully evaluated
998 // add pre-evaluated value to the contaner of constants
999 if (true == left.first)
1000 {
1001 int const_index =
1002 AddConstant(std::string("SUB_EXPR_") +
1003 std::to_string(m_constant.size()),
1004 left.second);
1005 stack.push_back(makeStep<StoreConst>(stateIndex, const_index));
1006 }
1007 if (true == right.first)
1008 {
1009 int const_index =
1010 AddConstant(std::string("SUB_EXPR_") +
1011 std::to_string(m_constant.size()),
1012 right.second);
1013 stack.push_back(
1014 makeStep<StoreConst>(stateIndex + 1, const_index));
1015 }
1016
1017 switch (*valueStr.begin())
1018 {
1019 case '+':
1020 stack.push_back(makeStep<EvalSum>(stateIndex, stateIndex,
1021 stateIndex + 1));
1022 return std::make_pair(false, 0);
1023 case '-':
1024 stack.push_back(makeStep<EvalSub>(stateIndex, stateIndex,
1025 stateIndex + 1));
1026 return std::make_pair(false, 0);
1027 case '*':
1028 stack.push_back(makeStep<EvalMul>(stateIndex, stateIndex,
1029 stateIndex + 1));
1030 return std::make_pair(false, 0);
1031 case '/':
1032 stack.push_back(makeStep<EvalDiv>(stateIndex, stateIndex,
1033 stateIndex + 1));
1034 return std::make_pair(false, 0);
1035 case '%':
1036 stack.push_back(makeStep<EvalMod>(stateIndex, stateIndex,
1037 stateIndex + 1));
1038 return std::make_pair(false, 0);
1039 case '^':
1040 stack.push_back(makeStep<EvalPow>(stateIndex, stateIndex,
1041 stateIndex + 1));
1042 return std::make_pair(false, 0);
1043 case '=':
1044 stack.push_back(makeStep<EvalLogicalEqual>(
1045 stateIndex, stateIndex, stateIndex + 1));
1046 return std::make_pair(false, 0);
1047 case '<':
1048 if (*(valueStr.end() - 1) == '=')
1049 {
1050 stack.push_back(makeStep<EvalLogicalLeq>(
1051 stateIndex, stateIndex, stateIndex + 1));
1052 }
1053 else
1054 {
1055 stack.push_back(makeStep<EvalLogicalLess>(
1056 stateIndex, stateIndex, stateIndex + 1));
1057 }
1058 return std::make_pair(false, 0);
1059
1060 case '>':
1061 if (*(valueStr.end() - 1) == '=')
1062 {
1063 stack.push_back(makeStep<EvalLogicalGeq>(
1064 stateIndex, stateIndex, stateIndex + 1));
1065 }
1066 else
1067 {
1068 stack.push_back(makeStep<EvalLogicalGreater>(
1069 stateIndex, stateIndex, stateIndex + 1));
1070 }
1071 return std::make_pair(false, 0);
1072
1073 default:
1074 ASSERTL0(false,
1075 "Invalid operator encountered: " + valueStr);
1076 }
1077 return std::make_pair(false, 0);
1078 }
1079 else if (parserID == AnalyticExpression::operatorID)
1080 {
1081 ASSERTL1(
1082 false,
1083 "Too few or too many arguments for mathematical operator: " +
1084 valueStr);
1085 }
1086 ASSERTL0(false, "Illegal expression encountered: " + valueStr);
1087 return std::make_pair(false, 0);
1088 }
1089
1090 // ======================================================
1091 // Boost::spirit related data structures
1092 // ======================================================
1093
1094 /** This is a parser for spirit that parses the CONSTANT values. The default
1095 constants are those that are in math.h without the M_ prefix and they
1096 are initialized in the AnalyticExpressionEvaluator constructor. **/
1097
1098 bsp::symbols<NekDouble> m_constantsParser;
1099
1100 /** This is the class that is used as the grammar parser for the spirit
1101 * engine. **/
1102 class AnalyticExpression : public bsp::grammar<AnalyticExpression>
1103 {
1104 private:
1105 const bsp::symbols<NekDouble> *constants_p;
1106
1107 /** Variables is a customized parser that will match the variables that
1108 the function depends on (the first argument of #DefineFunction). **/
1109 struct variables : bsp::symbols<NekDouble *>
1110 {
1111 variables(std::vector<std::string> const &vars)
1112 {
1113 for (auto const &it : vars)
1114 {
1115 add(it.c_str(), 0);
1116 }
1117 }
1119
1120 public:
1121 /** These constants are used to determine what parser was used to parse
1122 what value, which allows for type identification when analyzing the
1123 parsed AST. **/
1124 static const int constantID = 1;
1125 static const int numberID = 2;
1126 static const int variableID = 3;
1127 static const int parameterID = 4;
1128 static const int functionID = 5;
1129 static const int unaryID = 6;
1130 static const int operatorID = 7;
1131
1132 AnalyticExpression(const bsp::symbols<NekDouble> *constants,
1133 const std::vector<std::string> &variables)
1134 : bsp::grammar<AnalyticExpression>(), constants_p(constants),
1136 {
1137 }
1138
1139 // Trivial constructor to avoid compiler warning with
1140 // constants_p.
1142 {
1143 constants_p = nullptr;
1144 }
1145
1146 template <typename ScannerT> struct definition
1147 {
1148 /** This function specifies the grammar of the
1149 * MathAnalyticExpression parser. **/
1151 {
1153
1154 logical_or =
1155 logical_and >>
1156 *((bsp::root_node_d[bsp::str_p("||")] >> logical_and));
1157
1158 logical_and =
1159 equality >>
1160 *((bsp::root_node_d[bsp::str_p("&&")] >> equality));
1161
1162 equality =
1163 lt_gt >> *((bsp::root_node_d[bsp::str_p("==")] >> lt_gt));
1164
1165 lt_gt = add_sub >>
1166 *((bsp::root_node_d[bsp::str_p("<=")] >> add_sub) |
1167 (bsp::root_node_d[bsp::str_p(">=")] >> add_sub) |
1168 (bsp::root_node_d[bsp::ch_p('<')] >> add_sub) |
1169 (bsp::root_node_d[bsp::ch_p('>')] >> add_sub));
1170
1171 add_sub =
1172 negate >> *((bsp::root_node_d[bsp::ch_p('+')] >> negate) |
1173 (bsp::root_node_d[bsp::ch_p('-')] >> negate));
1174
1175 negate = !(bsp::root_node_d[bsp::ch_p('-')]) >> mult_div_mod;
1176
1177 mult_div_mod =
1178 exponential >>
1179 *((bsp::root_node_d[bsp::ch_p('*')] >> exponential) |
1180 (bsp::root_node_d[bsp::ch_p('/')] >> exponential) |
1181 (bsp::root_node_d[bsp::ch_p('%')] >> exponential));
1182
1183 exponential =
1184 base >> !(bsp::root_node_d[bsp::ch_p('^')] >> exponential);
1185
1187 bsp::inner_node_d[bsp::ch_p('(') >> expression >>
1188 bsp::ch_p(')')];
1189 parameter =
1190 bsp::leaf_node_d[bsp::lexeme_d[(bsp::alpha_p | '_' | '$') >>
1191 *(bsp::alnum_p | '_' |
1192 '$')]] >>
1193 op;
1194
1195 function =
1196 bsp::root_node_d[functions_p] >>
1197 bsp::infix_node_d[bsp::inner_node_d[bsp::ch_p('(') >>
1198 expression >>
1199 *(',' >> expression) >>
1200 bsp::ch_p(')')]];
1201
1202 variable =
1203 bsp::leaf_node_d[bsp::lexeme_d[self.variables_p]] >> op;
1204
1205 number = bsp::leaf_node_d[bsp::lexeme_d[bsp::real_p]] >> op;
1206
1207 constant =
1208 bsp::leaf_node_d[bsp::lexeme_d[*self.constants_p]] >> op;
1209
1210 op = bsp::eps_p(bsp::end_p | "||" | "&&" | "==" | "<=" | ">=" |
1211 '<' | '>' | '+' | '-' | '*' | '/' | '%' | '^' |
1212 ')' | ',');
1213 }
1214
1215 /** This holds the NekDouble value that is parsed by spirit so it
1216 * can be stored in the AST. **/
1218
1219 template <int N>
1220 using bsp_rule =
1221 bsp::rule<ScannerT, bsp::parser_context<>, bsp::parser_tag<N>>;
1222
1240
1242 {
1243 return expression;
1244 }
1245 };
1246 }; // class AnalyticExpression
1247
1248private:
1249 // ======================================================
1250 // Pre-processed expressions
1251 // ======================================================
1252
1253 /// These vector and map store pre-processed evaluation sequences
1254 /// for the analytic expressions. Each ExecutionStack is an ordered
1255 /// container of steps of sequential execution process which
1256 /// evaluates an analytic expression.
1257
1259 std::vector<ExecutionStack> m_executionStack;
1260
1261 /// Keeping map of variables individually per each analytic expression
1262 /// allows correctly handling expressions which depend on different
1263 /// number of variables.
1264
1265 std::vector<VariableMap> m_stackVariableMap;
1266
1267 // ======================================================
1268 // Execution state and data
1269 // ======================================================
1270
1271 /// The following data structures hold input data to be used on evaluation
1272 /// stage. There are three types of input data:
1273 /// - constants (never change their value)
1274 /// - parameters are allowed to change their values between evaluations
1275 /// (compared to constants)
1276 /// - variables always change their values at every evaluation call.
1277 /// First map looks like <parameter_name, parameter_id> while the second is
1278 /// <parameter_id, parameter_value>. The map is used at a preparation
1279 /// stage when the analytic expression is parsed. This associates an
1280 /// integer id with a parameter name in its string form. On evaluation
1281 /// stage the id and a std::vector constant lookup time make evaluation
1282 /// faster compared to permanent std::map<std::string, NekDouble> lookup.
1283
1287
1288 std::vector<NekDouble> m_parameter;
1289 std::vector<NekDouble> m_constant;
1290 std::vector<NekDouble> m_variable;
1291
1292 /// This vector stores the execution state (memory) used by the
1293 /// sequential execution process.
1294 std::vector<NekDouble> m_state;
1295
1296 /// Vector of state sizes per each
1297 std::vector<int> m_state_sizes;
1298
1299 /// This counter is used by PrepareExecutionAsYouParse for finding
1300 /// the minimal state size necessary for evaluation of function parsed.
1302
1303 /// Timer and sum of evaluation times
1306
1307 std::mt19937 m_generator;
1308
1309 // ======================================================
1310 // A map of (external) mathematical functions
1311 // ======================================================
1312
1314 std::map<int, OneArgFunc> m_function;
1315 std::map<int, TwoArgFunc> m_function2;
1316
1317 // ======================================================
1318 // Internal representation of evaluation step
1319 // ======================================================
1320
1321 /// Short names to minimise the infractructural code mess in defining
1322 /// functors below.
1323 typedef std::vector<NekDouble> &vr;
1324 typedef const std::vector<NekDouble> &cvr;
1325 typedef const int ci;
1326 typedef std::mt19937 &rgt;
1327
1328 /// Factory method which makes code little less messy
1329 template <typename StepType>
1330 EvaluationStep *makeStep(ci dest, ci src_left = 0, ci src_right = 0)
1331 {
1332 return (new StepType(m_generator, m_state, m_constant, m_parameter,
1333 m_variable, dest, src_left, src_right));
1334 }
1335
1337 {
1364 E_BESSEL
1366
1367 /// Function objects (functors)
1369 {
1370 /// reference to random number generator
1372
1373 /// references to arrays holding the common state
1378
1379 /// indices in the above arrays uniquely defining actual command
1380 /// arguments
1384
1385 EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
1386 : rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i),
1387 argIdx1(l), argIdx2(r){};
1388
1390 {
1391 }
1392
1393 /// declaring this guy pure virtual shortens virtual table. It saves
1394 /// some execution time.
1395 virtual void run_many(ci n) = 0;
1396 virtual void run_once() = 0;
1397 };
1399 {
1400 CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1401 : EvaluationStep(rn, i, l, r, s, c, p, v)
1402 {
1403 }
1404 void run_many(ci n) override
1405 {
1406 for (int i = 0; i < n; i++)
1407 {
1408 state[storeIdx * n + i] = state[argIdx1];
1409 }
1410 }
1411 void run_once() override
1412 {
1414 }
1415 };
1417 {
1418 StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1419 : EvaluationStep(rn, i, l, r, s, c, p, v)
1420 {
1421 }
1422 void run_many(ci n) override
1423 {
1424 for (int i = 0; i < n; i++)
1425 {
1426 state[storeIdx * n + i] = consts[argIdx1];
1427 }
1428 }
1429 void run_once() override
1430 {
1432 }
1433 };
1434 struct StoreVar : public EvaluationStep
1435 {
1436 StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1437 : EvaluationStep(rn, i, l, r, s, c, p, v)
1438 {
1439 }
1440 void run_many(ci n) override
1441 {
1442 for (int i = 0; i < n; i++)
1443 {
1444 state[storeIdx * n + i] = vars[argIdx1 * n + i];
1445 }
1446 }
1447 void run_once() override
1448 {
1450 }
1451 };
1452 struct StorePrm : public EvaluationStep
1453 {
1454 StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1455 : EvaluationStep(rn, i, l, r, s, c, p, v)
1456 {
1457 }
1458 void run_many(ci n) override
1459 {
1460 for (int i = 0; i < n; i++)
1461 {
1462 state[storeIdx * n + i] = params[argIdx1];
1463 }
1464 }
1465 void run_once() override
1466 {
1468 }
1469 };
1470 struct EvalSum : public EvaluationStep
1471 {
1472 EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1473 : EvaluationStep(rn, i, l, r, s, c, p, v)
1474 {
1475 }
1476 void run_many(ci n) override
1477 {
1478 for (int i = 0; i < n; i++)
1479 {
1480 state[storeIdx * n + i] =
1481 state[argIdx1 * n + i] + state[argIdx2 * n + i];
1482 }
1483 }
1484 void run_once() override
1485 {
1487 }
1488 };
1489 struct EvalSub : public EvaluationStep
1490 {
1491 EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1492 : EvaluationStep(rn, i, l, r, s, c, p, v)
1493 {
1494 }
1495 void run_many(ci n) override
1496 {
1497 for (int i = 0; i < n; i++)
1498 {
1499 state[storeIdx * n + i] =
1500 state[argIdx1 * n + i] - state[argIdx2 * n + i];
1501 }
1502 }
1503 void run_once() override
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 void run_many(ci n) override
1515 {
1516 for (int i = 0; i < n; i++)
1517 {
1518 state[storeIdx * n + i] =
1519 state[argIdx1 * n + i] * state[argIdx2 * n + i];
1520 }
1521 }
1522 void run_once() override
1523 {
1525 }
1526 };
1527 struct EvalDiv : public EvaluationStep
1528 {
1529 EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1530 : EvaluationStep(rn, i, l, r, s, c, p, v)
1531 {
1532 }
1533 void run_many(ci n) override
1534 {
1535 for (int i = 0; i < n; i++)
1536 {
1537 state[storeIdx * n + i] =
1538 state[argIdx1 * n + i] / state[argIdx2 * n + i];
1539 }
1540 }
1541 void run_once() override
1542 {
1544 }
1545 };
1546 struct EvalPow : public EvaluationStep
1547 {
1548 EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1549 : EvaluationStep(rn, i, l, r, s, c, p, v)
1550 {
1551 }
1552 void run_many(ci n) override
1553 {
1554 for (int i = 0; i < n; i++)
1555 {
1556 state[storeIdx * n + i] =
1557 std::pow(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1558 }
1559 }
1560 void run_once() override
1561 {
1562 state[storeIdx] = std::pow(state[argIdx1], state[argIdx2]);
1563 }
1564 };
1565 struct EvalNeg : public EvaluationStep
1566 {
1567 EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1568 : EvaluationStep(rn, i, l, r, s, c, p, v)
1569 {
1570 }
1571 void run_many(ci n) override
1572 {
1573 for (int i = 0; i < n; i++)
1574 {
1575 state[storeIdx * n + i] = -state[argIdx1 * n + i];
1576 }
1577 }
1578 void run_once() override
1579 {
1581 }
1582 };
1584 {
1585 EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1586 : EvaluationStep(rn, i, l, r, s, c, p, v)
1587 {
1588 }
1589 void run_many(ci n) override
1590 {
1591 for (int i = 0; i < n; i++)
1592 {
1593 state[storeIdx * n + i] =
1594 (state[argIdx1 * n + i] == state[argIdx2 * n + i]);
1595 }
1596 }
1597 void run_once() override
1598 {
1600 }
1601 };
1603 {
1604 EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1605 : EvaluationStep(rn, i, l, r, s, c, p, v)
1606 {
1607 }
1608 void run_many(ci n) override
1609 {
1610 for (int i = 0; i < n; i++)
1611 {
1612 state[storeIdx * n + i] =
1613 (state[argIdx1 * n + i] <= state[argIdx2 * n + i]);
1614 }
1615 }
1616 void run_once() override
1617 {
1619 }
1620 };
1622 {
1623 EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1624 : EvaluationStep(rn, i, l, r, s, c, p, v)
1625 {
1626 }
1627 void run_many(ci n) override
1628 {
1629 for (int i = 0; i < n; i++)
1630 {
1631 state[storeIdx * n + i] =
1632 (state[argIdx1 * n + i] < state[argIdx2 * n + i]);
1633 }
1634 }
1635 void run_once() override
1636 {
1638 }
1639 };
1641 {
1642 EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1643 : EvaluationStep(rn, i, l, r, s, c, p, v)
1644 {
1645 }
1646 void run_many(ci n) override
1647 {
1648 for (int i = 0; i < n; i++)
1649 {
1650 state[storeIdx * n + i] =
1651 (state[argIdx1 * n + i] >= state[argIdx2 * n + i]);
1652 }
1653 }
1654 void run_once() override
1655 {
1657 }
1658 };
1660 {
1661 EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1662 : EvaluationStep(rn, i, l, r, s, c, p, v)
1663 {
1664 }
1665 void run_many(ci n) override
1666 {
1667 for (int i = 0; i < n; i++)
1668 {
1669 state[storeIdx * n + i] =
1670 (state[argIdx1 * n + i] > state[argIdx2 * n + i]);
1671 }
1672 }
1673 void run_once() override
1674 {
1676 }
1677 };
1678 struct EvalMod : public EvaluationStep
1679 {
1680 EvalMod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1681 : EvaluationStep(rn, i, l, r, s, c, p, v)
1682 {
1683 }
1684 void run_many(ci n) override
1685 {
1686 for (int i = 0; i < n; i++)
1687 {
1688 state[storeIdx * n + i] =
1689 std::fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1690 }
1691 }
1692 void run_once() override
1693 {
1694 state[storeIdx] = std::fmod(state[argIdx1], state[argIdx2]);
1695 }
1696 };
1697 struct EvalAbs : public EvaluationStep
1698 {
1699 EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1700 : EvaluationStep(rn, i, l, r, s, c, p, v)
1701 {
1702 }
1703 void run_many(ci n) override
1704 {
1705 for (int i = 0; i < n; i++)
1706 {
1707 state[storeIdx * n + i] = std::abs(state[argIdx1 * n + i]);
1708 }
1709 }
1710 void run_once() override
1711 {
1713 }
1714 };
1715 struct EvalSign : public EvaluationStep
1716 {
1717 EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1718 : EvaluationStep(rn, i, l, r, s, c, p, v)
1719 {
1720 }
1721 void run_many(ci n) override
1722 {
1723 for (int i = 0; i < n; i++)
1724 {
1725 state[storeIdx * n + i] = ((state[argIdx1 * n + i] > 0.0) -
1726 (state[argIdx1 * n + i] < 0.0));
1727 }
1728 }
1729 void run_once() override
1730 {
1731 state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0));
1732 }
1733 };
1734 struct EvalAsin : public EvaluationStep
1735 {
1736 EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1737 : EvaluationStep(rn, i, l, r, s, c, p, v)
1738 {
1739 }
1740 void run_many(ci n) override
1741 {
1742 for (int i = 0; i < n; i++)
1743 {
1744 state[storeIdx * n + i] = std::asin(state[argIdx1 * n + i]);
1745 }
1746 }
1747 void run_once() override
1748 {
1749 state[storeIdx] = std::asin(state[argIdx1]);
1750 }
1751 };
1752 struct EvalAcos : public EvaluationStep
1753 {
1754 EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1755 : EvaluationStep(rn, i, l, r, s, c, p, v)
1756 {
1757 }
1758 void run_many(ci n) override
1759 {
1760 for (int i = 0; i < n; i++)
1761 {
1762 state[storeIdx * n + i] = std::acos(state[argIdx1 * n + i]);
1763 }
1764 }
1765 void run_once() override
1766 {
1767 state[storeIdx] = std::acos(state[argIdx1]);
1768 }
1769 };
1770 struct EvalAtan : public EvaluationStep
1771 {
1772 EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1773 : EvaluationStep(rn, i, l, r, s, c, p, v)
1774 {
1775 }
1776 void run_many(ci n) override
1777 {
1778 for (int i = 0; i < n; i++)
1779 {
1780 state[storeIdx * n + i] = std::atan(state[argIdx1 * n + i]);
1781 }
1782 }
1783 void run_once() override
1784 {
1785 state[storeIdx] = std::atan(state[argIdx1]);
1786 }
1787 };
1789 {
1790 EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1791 : EvaluationStep(rn, i, l, r, s, c, p, v)
1792 {
1793 }
1794 void run_many(ci n) override
1795 {
1796 for (int i = 0; i < n; i++)
1797 {
1798 state[storeIdx * n + i] =
1799 std::atan2(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1800 }
1801 }
1802 void run_once() override
1803 {
1804 state[storeIdx] = std::atan2(state[argIdx1], state[argIdx2]);
1805 }
1806 };
1807 struct EvalAng : public EvaluationStep
1808 {
1809 EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1810 : EvaluationStep(rn, i, l, r, s, c, p, v)
1811 {
1812 }
1813 void run_many(ci n) override
1814 {
1815 for (int i = 0; i < n; i++)
1816 {
1817 state[storeIdx * n + i] =
1818 ang(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1819 }
1820 }
1821 void run_once() override
1822 {
1824 }
1825 };
1827 {
1828 EvalBessel(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 void run_many(ci n) override
1833 {
1834 for (int i = 0; i < n; i++)
1835 {
1836 state[storeIdx * n + i] = boost::math::cyl_bessel_j(
1837 state[argIdx1 * n + i], state[argIdx2 * n + i]);
1838 }
1839 }
1840 void run_once() override
1841 {
1842 state[storeIdx] =
1843 boost::math::cyl_bessel_j(state[argIdx1], state[argIdx2]);
1844 }
1845 };
1846 struct EvalCeil : public EvaluationStep
1847 {
1848 EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1849 : EvaluationStep(rn, i, l, r, s, c, p, v)
1850 {
1851 }
1852 void run_many(ci n) override
1853 {
1854 for (int i = 0; i < n; i++)
1855 {
1856 state[storeIdx * n + i] = std::ceil(state[argIdx1 * n + i]);
1857 }
1858 }
1859 void run_once() override
1860 {
1861 state[storeIdx] = std::ceil(state[argIdx1]);
1862 }
1863 };
1864 struct EvalCos : public EvaluationStep
1865 {
1866 EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1867 : EvaluationStep(rn, i, l, r, s, c, p, v)
1868 {
1869 }
1870 void run_many(ci n) override
1871 {
1872 for (int i = 0; i < n; i++)
1873 {
1874 state[storeIdx * n + i] = std::cos(state[argIdx1 * n + i]);
1875 }
1876 }
1877 void run_once() override
1878 {
1879 state[storeIdx] = std::cos(state[argIdx1]);
1880 }
1881 };
1882 struct EvalCosh : public EvaluationStep
1883 {
1884 EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1885 : EvaluationStep(rn, i, l, r, s, c, p, v)
1886 {
1887 }
1888 void run_many(ci n) override
1889 {
1890 for (int i = 0; i < n; i++)
1891 {
1892 state[storeIdx * n + i] = std::cosh(state[argIdx1 * n + i]);
1893 }
1894 }
1895 void run_once() override
1896 {
1897 state[storeIdx] = std::cosh(state[argIdx1]);
1898 }
1899 };
1900 struct EvalExp : public EvaluationStep
1901 {
1902 EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1903 : EvaluationStep(rn, i, l, r, s, c, p, v)
1904 {
1905 }
1906 void run_many(ci n) override
1907 {
1908 for (int i = 0; i < n; i++)
1909 {
1910 state[storeIdx * n + i] = std::exp(state[argIdx1 * n + i]);
1911 }
1912 }
1913 void run_once() override
1914 {
1915 state[storeIdx] = std::exp(state[argIdx1]);
1916 }
1917 };
1918 struct EvalFabs : public EvaluationStep
1919 {
1920 EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1921 : EvaluationStep(rn, i, l, r, s, c, p, v)
1922 {
1923 }
1924 void run_many(ci n) override
1925 {
1926 for (int i = 0; i < n; i++)
1927 {
1928 state[storeIdx * n + i] = std::fabs(state[argIdx1 * n + i]);
1929 }
1930 }
1931 void run_once() override
1932 {
1933 state[storeIdx] = std::fabs(state[argIdx1]);
1934 }
1935 };
1937 {
1938 EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1939 : EvaluationStep(rn, i, l, r, s, c, p, v)
1940 {
1941 }
1942 void run_many(ci n) override
1943 {
1944 for (int i = 0; i < n; i++)
1945 {
1946 state[storeIdx * n + i] = std::floor(state[argIdx1 * n + i]);
1947 }
1948 }
1949 void run_once() override
1950 {
1951 state[storeIdx] = std::floor(state[argIdx1]);
1952 }
1953 };
1954 struct EvalFmod : public EvaluationStep
1955 {
1956 EvalFmod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1957 : EvaluationStep(rn, i, l, r, s, c, p, v)
1958 {
1959 }
1960 void run_many(ci n) override
1961 {
1962 for (int i = 0; i < n; i++)
1963 {
1964 state[storeIdx * n + i] =
1965 fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1966 }
1967 }
1968 void run_once() override
1969 {
1971 }
1972 };
1973 struct EvalLog : public EvaluationStep
1974 {
1975 EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1976 : EvaluationStep(rn, i, l, r, s, c, p, v)
1977 {
1978 }
1979 void run_many(ci n) override
1980 {
1981 for (int i = 0; i < n; i++)
1982 {
1983 state[storeIdx * n + i] = std::log(state[argIdx1 * n + i]);
1984 }
1985 }
1986 void run_once() override
1987 {
1989 }
1990 };
1992 {
1993 EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1994 : EvaluationStep(rn, i, l, r, s, c, p, v)
1995 {
1996 }
1997 void run_many(ci n) override
1998 {
1999 for (int i = 0; i < n; i++)
2000 {
2001 state[storeIdx * n + i] = std::log10(state[argIdx1 * n + i]);
2002 }
2003 }
2004 void run_once() override
2005 {
2006 state[storeIdx] = std::log10(state[argIdx1]);
2007 }
2008 };
2009 struct EvalMax : public EvaluationStep
2010 {
2011 EvalMax(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2012 : EvaluationStep(rn, i, l, r, s, c, p, v)
2013 {
2014 }
2015 void run_many(ci n) override
2016 {
2017 for (int i = 0; i < n; i++)
2018 {
2019 state[storeIdx * n + i] =
2020 fmax(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2021 }
2022 }
2023 void run_once() override
2024 {
2026 }
2027 };
2028 struct EvalMin : public EvaluationStep
2029 {
2030 EvalMin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2031 : EvaluationStep(rn, i, l, r, s, c, p, v)
2032 {
2033 }
2034 void run_many(ci n) override
2035 {
2036 for (int i = 0; i < n; i++)
2037 {
2038 state[storeIdx * n + i] =
2039 fmin(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2040 }
2041 }
2042 void run_once() override
2043 {
2045 }
2046 };
2047 struct EvalRad : public EvaluationStep
2048 {
2049 EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2050 : EvaluationStep(rn, i, l, r, s, c, p, v)
2051 {
2052 }
2053 void run_many(ci n) override
2054 {
2055 for (int i = 0; i < n; i++)
2056 {
2057 state[storeIdx * n + i] =
2058 rad(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2059 }
2060 }
2061 void run_once() override
2062 {
2064 }
2065 };
2066 struct EvalSin : public EvaluationStep
2067 {
2068 EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2069 : EvaluationStep(rn, i, l, r, s, c, p, v)
2070 {
2071 }
2072 void run_many(ci n) override
2073 {
2074 for (int i = 0; i < n; i++)
2075 {
2076 state[storeIdx * n + i] = std::sin(state[argIdx1 * n + i]);
2077 }
2078 }
2079 void run_once() override
2080 {
2081 state[storeIdx] = std::sin(state[argIdx1]);
2082 }
2083 };
2084 struct EvalSinh : public EvaluationStep
2085 {
2086 EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2087 : EvaluationStep(rn, i, l, r, s, c, p, v)
2088 {
2089 }
2090 void run_many(ci n) override
2091 {
2092 for (int i = 0; i < n; i++)
2093 {
2094 state[storeIdx * n + i] = std::sinh(state[argIdx1 * n + i]);
2095 }
2096 }
2097 void run_once() override
2098 {
2099 state[storeIdx] = std::sinh(state[argIdx1]);
2100 }
2101 };
2102 struct EvalSqrt : public EvaluationStep
2103 {
2104 EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2105 : EvaluationStep(rn, i, l, r, s, c, p, v)
2106 {
2107 }
2108 void run_many(ci n) override
2109 {
2110 for (int i = 0; i < n; i++)
2111 {
2112 state[storeIdx * n + i] = std::sqrt(state[argIdx1 * n + i]);
2113 }
2114 }
2115 void run_once() override
2116 {
2118 }
2119 };
2120 struct EvalTan : public EvaluationStep
2121 {
2122 EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2123 : EvaluationStep(rn, i, l, r, s, c, p, v)
2124 {
2125 }
2126 void run_many(ci n) override
2127 {
2128 for (int i = 0; i < n; i++)
2129 {
2130 state[storeIdx * n + i] = std::tan(state[argIdx1 * n + i]);
2131 }
2132 }
2133 void run_once() override
2134 {
2135 state[storeIdx] = std::tan(state[argIdx1]);
2136 }
2137 };
2138 struct EvalTanh : public EvaluationStep
2139 {
2140 EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2141 : EvaluationStep(rn, i, l, r, s, c, p, v)
2142 {
2143 }
2144 void run_many(ci n) override
2145 {
2146 for (int i = 0; i < n; i++)
2147 {
2148 state[storeIdx * n + i] = std::tanh(state[argIdx1 * n + i]);
2149 }
2150 }
2151 void run_once() override
2152 {
2153 state[storeIdx] = std::tanh(state[argIdx1]);
2154 }
2155 };
2156 struct EvalAWGN : public EvaluationStep
2157 {
2158 EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2159 : EvaluationStep(rn, i, l, r, s, c, p, v)
2160 {
2161 }
2162 void run_many(ci n) override
2163 {
2164 // assuming the argument to AWGN does not depend on spatial
2165 // variables =>
2166 std::normal_distribution<> _normal(0, state[storeIdx * n]);
2167 for (int i = 0; i < n; i++)
2168 {
2169 state[storeIdx * n + i] = _normal(rng);
2170 }
2171 }
2172 void run_once() override
2173 {
2174 std::normal_distribution<> _normal(0, state[storeIdx]);
2175 state[storeIdx] = _normal(rng);
2176 }
2177 };
2178};
2179
2181{
2182 m_impl = std::unique_ptr<ExpressionEvaluator>(new ExpressionEvaluator());
2183}
2184
2186{
2187}
2188
2189Interpreter::Interpreter(Interpreter &&r) : m_impl(std::move(r.m_impl))
2190{
2191}
2192
2194{
2195 m_impl = std::move(r.m_impl);
2196 return *this;
2197}
2198
2199void Interpreter::SetRandomSeed(unsigned int seed)
2200{
2201 m_impl->SetRandomSeed(seed);
2202}
2203
2205 std::map<std::string, NekDouble> const &constants)
2206{
2207 m_impl->AddConstants(constants);
2208}
2209
2210int Interpreter::AddConstant(std::string const &name, NekDouble value)
2211{
2212 return m_impl->AddConstant(name, value);
2213}
2214
2216{
2217 return m_impl->GetConstant(name);
2218}
2219
2220void Interpreter::SetParameters(std::map<std::string, NekDouble> const &params)
2221{
2222 m_impl->SetParameters(params);
2223}
2224
2225void Interpreter::SetParameter(std::string const &name, NekDouble value)
2226{
2227 m_impl->SetParameter(name, value);
2228}
2229
2231{
2232 return m_impl->GetParameter(name);
2233}
2234
2236{
2237 return m_impl->GetTime();
2238}
2239
2240int Interpreter::DefineFunction(const std::string &vlist,
2241 const std::string &function)
2242{
2243 return m_impl->DefineFunction(vlist, function);
2244}
2245
2246NekDouble Interpreter::Evaluate(const int AnalyticExpression_id)
2247{
2248 return m_impl->Evaluate(AnalyticExpression_id);
2249}
2250
2251NekDouble Interpreter::Evaluate(const int AnalyticExpression_id,
2252 const NekDouble x, const NekDouble y,
2253 const NekDouble z, const NekDouble t)
2254{
2255 return m_impl->Evaluate(AnalyticExpression_id, x, y, z, t);
2256}
2257
2258NekDouble Interpreter::EvaluateAtPoint(const int AnalyticExpression_id,
2259 std::vector<NekDouble> point)
2260{
2261 return m_impl->EvaluateAtPoint(AnalyticExpression_id, point);
2262}
2263
2264void Interpreter::Evaluate(const int expression_id,
2269 Array<OneD, NekDouble> &result)
2270{
2271 m_impl->Evaluate(expression_id, x, y, z, t, result);
2272}
2273
2275 const int expression_id,
2276 const std::vector<Array<OneD, const NekDouble>> &points,
2277 Array<OneD, NekDouble> &result)
2278{
2279 m_impl->Evaluate(expression_id, points, result);
2280}
2281
2282} // 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:475
std::vector< double > z(NPUPPER)
double NekDouble
STL namespace.
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)