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(true, std::stod(valueStr.c_str()));
741 }
742 else if (parserID == AnalyticExpression::variableID)
743 {
744 ASSERTL1(num_children == 0,
745 "Illegal children under variable node: " + valueStr);
746
747 VariableMap::const_iterator it = variableMap.find(valueStr);
748 ASSERTL1(it != variableMap.end(),
749 "Unknown variable parsed: " + valueStr);
750
751 // Variables are not defined at the time of this parse.
752 stack.push_back(makeStep<StoreVar>(stateIndex, it->second));
753 return std::make_pair(false, 0);
754 }
755 else if (parserID == AnalyticExpression::parameterID)
756 {
757 ASSERTL1(num_children == 0,
758 "Illegal children under parameter node: " + valueStr);
759
760 auto it = m_parameterMapNameToId.find(valueStr);
762 "Unknown parameter parsed: " + valueStr);
763
764 // Parameters may change in between of evalutions.
765 stack.push_back(makeStep<StorePrm>(stateIndex, it->second));
766 return std::make_pair(false, 0);
767 }
768 else if (parserID == AnalyticExpression::functionID)
769 {
770 auto it = m_functionMapNameToInstanceType.find(valueStr);
772 "Invalid function specified: " + valueStr);
773 ASSERTL1(num_children == 1 || num_children == 2,
774 "Function " + valueStr +
775 " has neither one or two "
776 "arguments: this is not implemented yet.");
777
778 if (location->children.size() == 1)
779 {
781 location->children.begin(), stack, variableMap, stateIndex);
782
783 // additive white gaussian noise function
784 if (it->second == E_AWGN)
785 {
786 int const_index =
787 AddConstant(std::string("SUB_EXPR_") +
788 std::to_string(m_constant.size()),
789 v.second);
790 stack.push_back(
791 makeStep<StoreConst>(stateIndex, const_index));
792 stack.push_back(makeStep<EvalAWGN>(stateIndex, stateIndex));
793 return std::make_pair(false, 0);
794 }
795
796 if (true == v.first)
797 {
798 return std::make_pair(true,
799 m_function[it->second](v.second));
800 }
801 }
802 else
803 {
805 PrepareExecutionAsYouParse(location->children.begin() + 0,
806 stack, variableMap, stateIndex);
808 location->children.begin() + 1, stack, variableMap,
809 stateIndex + 1);
810 m_state_size++;
811
812 if (true == v1.first && true == v2.first)
813 {
814 return std::make_pair(
815 true, m_function2[it->second](v1.second, v2.second));
816 }
817 }
818
819 // if somewhere down the parse tree there is a variable or
820 // parameter, set up an evaluation sequence.
821 switch (it->second)
822 {
823 case E_ABS:
824 stack.push_back(makeStep<EvalAbs>(stateIndex, stateIndex));
825 return std::make_pair(false, 0);
826 case E_ASIN:
827 stack.push_back(makeStep<EvalAsin>(stateIndex, stateIndex));
828 return std::make_pair(false, 0);
829 case E_ACOS:
830 stack.push_back(makeStep<EvalAcos>(stateIndex, stateIndex));
831 return std::make_pair(false, 0);
832 case E_ATAN:
833 stack.push_back(makeStep<EvalAtan>(stateIndex, stateIndex));
834 return std::make_pair(false, 0);
835 case E_ATAN2:
836 stack.push_back(makeStep<EvalAtan2>(stateIndex, stateIndex,
837 stateIndex + 1));
838 return std::make_pair(false, 0);
839 case E_ANG:
840 stack.push_back(makeStep<EvalAng>(stateIndex, stateIndex,
841 stateIndex + 1));
842 return std::make_pair(false, 0);
843 case E_BESSEL:
844 stack.push_back(makeStep<EvalBessel>(stateIndex, stateIndex,
845 stateIndex + 1));
846 return std::make_pair(false, 0);
847 case E_CEIL:
848 stack.push_back(makeStep<EvalCeil>(stateIndex, stateIndex));
849 return std::make_pair(false, 0);
850 case E_COS:
851 stack.push_back(makeStep<EvalCos>(stateIndex, stateIndex));
852 return std::make_pair(false, 0);
853 case E_COSH:
854 stack.push_back(makeStep<EvalCosh>(stateIndex, stateIndex));
855 return std::make_pair(false, 0);
856 case E_EXP:
857 stack.push_back(makeStep<EvalExp>(stateIndex, stateIndex));
858 return std::make_pair(false, 0);
859 case E_FABS:
860 stack.push_back(makeStep<EvalFabs>(stateIndex, stateIndex));
861 return std::make_pair(false, 0);
862 case E_FLOOR:
863 stack.push_back(
864 makeStep<EvalFloor>(stateIndex, stateIndex));
865 return std::make_pair(false, 0);
866 case E_FMOD:
867 stack.push_back(makeStep<EvalFmod>(stateIndex, stateIndex,
868 stateIndex + 1));
869 return std::make_pair(false, 0);
870 case E_LOG:
871 stack.push_back(makeStep<EvalLog>(stateIndex, stateIndex));
872 return std::make_pair(false, 0);
873 case E_LOG10:
874 stack.push_back(
875 makeStep<EvalLog10>(stateIndex, stateIndex));
876 return std::make_pair(false, 0);
877 case E_MAX:
878 stack.push_back(makeStep<EvalMax>(stateIndex, stateIndex,
879 stateIndex + 1));
880 return std::make_pair(false, 0);
881 case E_MIN:
882 stack.push_back(makeStep<EvalMin>(stateIndex, stateIndex,
883 stateIndex + 1));
884 return std::make_pair(false, 0);
885 case E_RAD:
886 stack.push_back(makeStep<EvalRad>(stateIndex, stateIndex,
887 stateIndex + 1));
888 return std::make_pair(false, 0);
889 case E_SIN:
890 stack.push_back(makeStep<EvalSin>(stateIndex, stateIndex));
891 return std::make_pair(false, 0);
892 case E_SINH:
893 stack.push_back(makeStep<EvalSinh>(stateIndex, stateIndex));
894 return std::make_pair(false, 0);
895 case E_SQRT:
896 stack.push_back(makeStep<EvalSqrt>(stateIndex, stateIndex));
897 return std::make_pair(false, 0);
898 case E_TAN:
899 stack.push_back(makeStep<EvalTan>(stateIndex, stateIndex));
900 return std::make_pair(false, 0);
901 case E_TANH:
902 stack.push_back(makeStep<EvalTanh>(stateIndex, stateIndex));
903 return std::make_pair(false, 0);
904 case E_SIGN:
905 stack.push_back(makeStep<EvalSign>(stateIndex, stateIndex));
906 return std::make_pair(false, 0);
907 default:
908 ASSERTL0(false, "Evaluation of " + valueStr +
909 " is not implemented yet");
910 }
911 return std::make_pair(false, 0);
912 }
913 else if (parserID == AnalyticExpression::unaryID)
914 {
915 ASSERTL1(*valueStr.begin() == '-',
916 "Illegal factor - it can only be '-' and it was: " +
917 valueStr);
918 ASSERTL1(num_children == 1,
919 "Illegal number of children under factor node: " +
920 valueStr);
922 location->children.begin(), stack, variableMap, stateIndex);
923
924 // if precomputed value is valid, process it further.
925 if (true == v.first)
926 {
927 return std::make_pair(true, -v.second);
928 }
929 stack.push_back(makeStep<EvalNeg>(stateIndex, stateIndex));
930 return std::make_pair(false, 0);
931 }
932 else if (parserID == AnalyticExpression::operatorID)
933 {
934 ASSERTL1(
935 num_children == 2,
936 "Too few or too many arguments for mathematical operator: " +
937 valueStr);
939 location->children.begin() + 0, stack, variableMap, stateIndex);
940 PrecomputedValue right =
941 PrepareExecutionAsYouParse(location->children.begin() + 1,
942 stack, variableMap, stateIndex + 1);
943 m_state_size++;
944
945 // if both precomputed values are valid, process them further.
946 if ((left.first == true) && (right.first == true))
947 {
948 switch (*valueStr.begin())
949 {
950 case '+':
951 return std::make_pair(true, left.second + right.second);
952 case '-':
953 return std::make_pair(true, left.second - right.second);
954 case '*':
955 return std::make_pair(true, left.second * right.second);
956 case '/':
957 return std::make_pair(true, left.second / right.second);
958 case '%':
959 return std::make_pair(
960 true, std::fmod(left.second, right.second));
961 case '^':
962 return std::make_pair(
963 true, std::pow(left.second, right.second));
964 case '=':
965 return std::make_pair(true,
966 left.second == right.second);
967 case '<':
968 if (*(valueStr.end() - 1) == '=')
969 {
970 return std::make_pair(true,
971 left.second <= right.second);
972 }
973 else
974 {
975 return std::make_pair(true,
976 left.second < right.second);
977 }
978 case '>':
979 if (*(valueStr.end() - 1) == '=')
980 {
981 return std::make_pair(true,
982 left.second >= right.second);
983 }
984 else
985 {
986 return std::make_pair(true,
987 left.second > right.second);
988 }
989 default:
990 ASSERTL0(false,
991 "Invalid operator encountered: " + valueStr);
992 }
993 return std::make_pair(false, 0);
994 }
995
996 // either operator argument is not fully evaluated
997 // add pre-evaluated value to the contaner of constants
998 if (true == left.first)
999 {
1000 int const_index =
1001 AddConstant(std::string("SUB_EXPR_") +
1002 std::to_string(m_constant.size()),
1003 left.second);
1004 stack.push_back(makeStep<StoreConst>(stateIndex, const_index));
1005 }
1006 if (true == right.first)
1007 {
1008 int const_index =
1009 AddConstant(std::string("SUB_EXPR_") +
1010 std::to_string(m_constant.size()),
1011 right.second);
1012 stack.push_back(
1013 makeStep<StoreConst>(stateIndex + 1, const_index));
1014 }
1015
1016 switch (*valueStr.begin())
1017 {
1018 case '+':
1019 stack.push_back(makeStep<EvalSum>(stateIndex, stateIndex,
1020 stateIndex + 1));
1021 return std::make_pair(false, 0);
1022 case '-':
1023 stack.push_back(makeStep<EvalSub>(stateIndex, stateIndex,
1024 stateIndex + 1));
1025 return std::make_pair(false, 0);
1026 case '*':
1027 stack.push_back(makeStep<EvalMul>(stateIndex, stateIndex,
1028 stateIndex + 1));
1029 return std::make_pair(false, 0);
1030 case '/':
1031 stack.push_back(makeStep<EvalDiv>(stateIndex, stateIndex,
1032 stateIndex + 1));
1033 return std::make_pair(false, 0);
1034 case '%':
1035 stack.push_back(makeStep<EvalMod>(stateIndex, stateIndex,
1036 stateIndex + 1));
1037 return std::make_pair(false, 0);
1038 case '^':
1039 stack.push_back(makeStep<EvalPow>(stateIndex, stateIndex,
1040 stateIndex + 1));
1041 return std::make_pair(false, 0);
1042 case '=':
1043 stack.push_back(makeStep<EvalLogicalEqual>(
1044 stateIndex, stateIndex, stateIndex + 1));
1045 return std::make_pair(false, 0);
1046 case '<':
1047 if (*(valueStr.end() - 1) == '=')
1048 {
1049 stack.push_back(makeStep<EvalLogicalLeq>(
1050 stateIndex, stateIndex, stateIndex + 1));
1051 }
1052 else
1053 {
1054 stack.push_back(makeStep<EvalLogicalLess>(
1055 stateIndex, stateIndex, stateIndex + 1));
1056 }
1057 return std::make_pair(false, 0);
1058
1059 case '>':
1060 if (*(valueStr.end() - 1) == '=')
1061 {
1062 stack.push_back(makeStep<EvalLogicalGeq>(
1063 stateIndex, stateIndex, stateIndex + 1));
1064 }
1065 else
1066 {
1067 stack.push_back(makeStep<EvalLogicalGreater>(
1068 stateIndex, stateIndex, stateIndex + 1));
1069 }
1070 return std::make_pair(false, 0);
1071
1072 default:
1073 ASSERTL0(false,
1074 "Invalid operator encountered: " + valueStr);
1075 }
1076 return std::make_pair(false, 0);
1077 }
1078 else if (parserID == AnalyticExpression::operatorID)
1079 {
1080 ASSERTL1(
1081 false,
1082 "Too few or too many arguments for mathematical operator: " +
1083 valueStr);
1084 }
1085 ASSERTL0(false, "Illegal expression encountered: " + valueStr);
1086 return std::make_pair(false, 0);
1087 }
1088
1089 // ======================================================
1090 // Boost::spirit related data structures
1091 // ======================================================
1092
1093 /** This is a parser for spirit that parses the CONSTANT values. The default
1094 constants are those that are in math.h without the M_ prefix and they
1095 are initialized in the AnalyticExpressionEvaluator constructor. **/
1096
1097 bsp::symbols<NekDouble> m_constantsParser;
1098
1099 /** This is the class that is used as the grammar parser for the spirit
1100 * engine. **/
1101 class AnalyticExpression : public bsp::grammar<AnalyticExpression>
1102 {
1103 private:
1104 const bsp::symbols<NekDouble> *constants_p;
1105
1106 /** Variables is a customized parser that will match the variables that
1107 the function depends on (the first argument of #DefineFunction). **/
1108 struct variables : bsp::symbols<NekDouble *>
1109 {
1110 variables(std::vector<std::string> const &vars)
1111 {
1112 for (auto const &it : vars)
1113 {
1114 add(it.c_str(), 0);
1115 }
1116 }
1118
1119 public:
1120 /** These constants are used to determine what parser was used to parse
1121 what value, which allows for type identification when analyzing the
1122 parsed AST. **/
1123 static const int constantID = 1;
1124 static const int numberID = 2;
1125 static const int variableID = 3;
1126 static const int parameterID = 4;
1127 static const int functionID = 5;
1128 static const int unaryID = 6;
1129 static const int operatorID = 7;
1130
1131 AnalyticExpression(const bsp::symbols<NekDouble> *constants,
1132 const std::vector<std::string> &variables)
1133 : bsp::grammar<AnalyticExpression>(), constants_p(constants),
1135 {
1136 }
1137
1138 // Trivial constructor to avoid compiler warning with
1139 // constants_p.
1141 {
1142 constants_p = nullptr;
1143 }
1144
1145 template <typename ScannerT> struct definition
1146 {
1147 /** This function specifies the grammar of the
1148 * MathAnalyticExpression parser. **/
1150 {
1152
1153 logical_or =
1154 logical_and >>
1155 *((bsp::root_node_d[bsp::str_p("||")] >> logical_and));
1156
1157 logical_and =
1158 equality >>
1159 *((bsp::root_node_d[bsp::str_p("&&")] >> equality));
1160
1161 equality =
1162 lt_gt >> *((bsp::root_node_d[bsp::str_p("==")] >> lt_gt));
1163
1164 lt_gt = add_sub >>
1165 *((bsp::root_node_d[bsp::str_p("<=")] >> add_sub) |
1166 (bsp::root_node_d[bsp::str_p(">=")] >> add_sub) |
1167 (bsp::root_node_d[bsp::ch_p('<')] >> add_sub) |
1168 (bsp::root_node_d[bsp::ch_p('>')] >> add_sub));
1169
1170 add_sub =
1171 negate >> *((bsp::root_node_d[bsp::ch_p('+')] >> negate) |
1172 (bsp::root_node_d[bsp::ch_p('-')] >> negate));
1173
1174 negate = !(bsp::root_node_d[bsp::ch_p('-')]) >> mult_div_mod;
1175
1176 mult_div_mod =
1177 exponential >>
1178 *((bsp::root_node_d[bsp::ch_p('*')] >> exponential) |
1179 (bsp::root_node_d[bsp::ch_p('/')] >> exponential) |
1180 (bsp::root_node_d[bsp::ch_p('%')] >> exponential));
1181
1182 exponential =
1183 base >> !(bsp::root_node_d[bsp::ch_p('^')] >> exponential);
1184
1186 bsp::inner_node_d[bsp::ch_p('(') >> expression >>
1187 bsp::ch_p(')')];
1188 parameter =
1189 bsp::leaf_node_d[bsp::lexeme_d[(bsp::alpha_p | '_' | '$') >>
1190 *(bsp::alnum_p | '_' |
1191 '$')]] >>
1192 op;
1193
1194 function =
1195 bsp::root_node_d[functions_p] >>
1196 bsp::infix_node_d[bsp::inner_node_d[bsp::ch_p('(') >>
1197 expression >>
1198 *(',' >> expression) >>
1199 bsp::ch_p(')')]];
1200
1201 variable =
1202 bsp::leaf_node_d[bsp::lexeme_d[self.variables_p]] >> op;
1203
1204 number = bsp::leaf_node_d[bsp::lexeme_d[bsp::real_p]] >> op;
1205
1206 constant =
1207 bsp::leaf_node_d[bsp::lexeme_d[*self.constants_p]] >> op;
1208
1209 op = bsp::eps_p(bsp::end_p | "||" | "&&" | "==" | "<=" | ">=" |
1210 '<' | '>' | '+' | '-' | '*' | '/' | '%' | '^' |
1211 ')' | ',');
1212 }
1213
1214 /** This holds the NekDouble value that is parsed by spirit so it
1215 * can be stored in the AST. **/
1217
1218 template <int N>
1219 using bsp_rule =
1220 bsp::rule<ScannerT, bsp::parser_context<>, bsp::parser_tag<N>>;
1221
1239
1241 {
1242 return expression;
1243 }
1244 };
1245 }; // class AnalyticExpression
1246
1247private:
1248 // ======================================================
1249 // Pre-processed expressions
1250 // ======================================================
1251
1252 /// These vector and map store pre-processed evaluation sequences
1253 /// for the analytic expressions. Each ExecutionStack is an ordered
1254 /// container of steps of sequential execution process which
1255 /// evaluates an analytic expression.
1256
1258 std::vector<ExecutionStack> m_executionStack;
1259
1260 /// Keeping map of variables individually per each analytic expression
1261 /// allows correctly handling expressions which depend on different
1262 /// number of variables.
1263
1264 std::vector<VariableMap> m_stackVariableMap;
1265
1266 // ======================================================
1267 // Execution state and data
1268 // ======================================================
1269
1270 /// The following data structures hold input data to be used on evaluation
1271 /// stage. There are three types of input data:
1272 /// - constants (never change their value)
1273 /// - parameters are allowed to change their values between evaluations
1274 /// (compared to constants)
1275 /// - variables always change their values at every evaluation call.
1276 /// First map looks like <parameter_name, parameter_id> while the second is
1277 /// <parameter_id, parameter_value>. The map is used at a preparation
1278 /// stage when the analytic expression is parsed. This associates an
1279 /// integer id with a parameter name in its string form. On evaluation
1280 /// stage the id and a std::vector constant lookup time make evaluation
1281 /// faster compared to permanent std::map<std::string, NekDouble> lookup.
1282
1286
1287 std::vector<NekDouble> m_parameter;
1288 std::vector<NekDouble> m_constant;
1289 std::vector<NekDouble> m_variable;
1290
1291 /// This vector stores the execution state (memory) used by the
1292 /// sequential execution process.
1293 std::vector<NekDouble> m_state;
1294
1295 /// Vector of state sizes per each
1296 std::vector<int> m_state_sizes;
1297
1298 /// This counter is used by PrepareExecutionAsYouParse for finding
1299 /// the minimal state size necessary for evaluation of function parsed.
1301
1302 /// Timer and sum of evaluation times
1305
1306 std::mt19937 m_generator;
1307
1308 // ======================================================
1309 // A map of (external) mathematical functions
1310 // ======================================================
1311
1313 std::map<int, OneArgFunc> m_function;
1314 std::map<int, TwoArgFunc> m_function2;
1315
1316 // ======================================================
1317 // Internal representation of evaluation step
1318 // ======================================================
1319
1320 /// Short names to minimise the infractructural code mess in defining
1321 /// functors below.
1322 typedef std::vector<NekDouble> &vr;
1323 typedef const std::vector<NekDouble> &cvr;
1324 typedef const int ci;
1325 typedef std::mt19937 &rgt;
1326
1327 /// Factory method which makes code little less messy
1328 template <typename StepType>
1329 EvaluationStep *makeStep(ci dest, ci src_left = 0, ci src_right = 0)
1330 {
1331 return (new StepType(m_generator, m_state, m_constant, m_parameter,
1332 m_variable, dest, src_left, src_right));
1333 }
1334
1336 {
1363 E_BESSEL
1365
1366 /// Function objects (functors)
1368 {
1369 /// reference to random number generator
1371
1372 /// references to arrays holding the common state
1377
1378 /// indices in the above arrays uniquely defining actual command
1379 /// arguments
1383
1384 EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
1385 : rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i),
1386 argIdx1(l), argIdx2(r){};
1387
1389 {
1390 }
1391
1392 /// declaring this guy pure virtual shortens virtual table. It saves
1393 /// some execution time.
1394 virtual void run_many(ci n) = 0;
1395 virtual void run_once() = 0;
1396 };
1398 {
1399 CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1400 : EvaluationStep(rn, i, l, r, s, c, p, v)
1401 {
1402 }
1403 void run_many(ci n) override
1404 {
1405 for (int i = 0; i < n; i++)
1406 {
1407 state[storeIdx * n + i] = state[argIdx1];
1408 }
1409 }
1410 void run_once() override
1411 {
1413 }
1414 };
1416 {
1417 StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1418 : EvaluationStep(rn, i, l, r, s, c, p, v)
1419 {
1420 }
1421 void run_many(ci n) override
1422 {
1423 for (int i = 0; i < n; i++)
1424 {
1425 state[storeIdx * n + i] = consts[argIdx1];
1426 }
1427 }
1428 void run_once() override
1429 {
1431 }
1432 };
1433 struct StoreVar : public EvaluationStep
1434 {
1435 StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1436 : EvaluationStep(rn, i, l, r, s, c, p, v)
1437 {
1438 }
1439 void run_many(ci n) override
1440 {
1441 for (int i = 0; i < n; i++)
1442 {
1443 state[storeIdx * n + i] = vars[argIdx1 * n + i];
1444 }
1445 }
1446 void run_once() override
1447 {
1449 }
1450 };
1451 struct StorePrm : public EvaluationStep
1452 {
1453 StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1454 : EvaluationStep(rn, i, l, r, s, c, p, v)
1455 {
1456 }
1457 void run_many(ci n) override
1458 {
1459 for (int i = 0; i < n; i++)
1460 {
1461 state[storeIdx * n + i] = params[argIdx1];
1462 }
1463 }
1464 void run_once() override
1465 {
1467 }
1468 };
1469 struct EvalSum : public EvaluationStep
1470 {
1471 EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1472 : EvaluationStep(rn, i, l, r, s, c, p, v)
1473 {
1474 }
1475 void run_many(ci n) override
1476 {
1477 for (int i = 0; i < n; i++)
1478 {
1479 state[storeIdx * n + i] =
1480 state[argIdx1 * n + i] + state[argIdx2 * n + i];
1481 }
1482 }
1483 void run_once() override
1484 {
1486 }
1487 };
1488 struct EvalSub : public EvaluationStep
1489 {
1490 EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1491 : EvaluationStep(rn, i, l, r, s, c, p, v)
1492 {
1493 }
1494 void run_many(ci n) override
1495 {
1496 for (int i = 0; i < n; i++)
1497 {
1498 state[storeIdx * n + i] =
1499 state[argIdx1 * n + i] - state[argIdx2 * n + i];
1500 }
1501 }
1502 void run_once() override
1503 {
1505 }
1506 };
1507 struct EvalMul : public EvaluationStep
1508 {
1509 EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1510 : EvaluationStep(rn, i, l, r, s, c, p, v)
1511 {
1512 }
1513 void run_many(ci n) override
1514 {
1515 for (int i = 0; i < n; i++)
1516 {
1517 state[storeIdx * n + i] =
1518 state[argIdx1 * n + i] * state[argIdx2 * n + i];
1519 }
1520 }
1521 void run_once() override
1522 {
1524 }
1525 };
1526 struct EvalDiv : public EvaluationStep
1527 {
1528 EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1529 : EvaluationStep(rn, i, l, r, s, c, p, v)
1530 {
1531 }
1532 void run_many(ci n) override
1533 {
1534 for (int i = 0; i < n; i++)
1535 {
1536 state[storeIdx * n + i] =
1537 state[argIdx1 * n + i] / state[argIdx2 * n + i];
1538 }
1539 }
1540 void run_once() override
1541 {
1543 }
1544 };
1545 struct EvalPow : public EvaluationStep
1546 {
1547 EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1548 : EvaluationStep(rn, i, l, r, s, c, p, v)
1549 {
1550 }
1551 void run_many(ci n) override
1552 {
1553 for (int i = 0; i < n; i++)
1554 {
1555 state[storeIdx * n + i] =
1556 std::pow(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1557 }
1558 }
1559 void run_once() override
1560 {
1561 state[storeIdx] = std::pow(state[argIdx1], state[argIdx2]);
1562 }
1563 };
1564 struct EvalNeg : public EvaluationStep
1565 {
1566 EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1567 : EvaluationStep(rn, i, l, r, s, c, p, v)
1568 {
1569 }
1570 void run_many(ci n) override
1571 {
1572 for (int i = 0; i < n; i++)
1573 {
1574 state[storeIdx * n + i] = -state[argIdx1 * n + i];
1575 }
1576 }
1577 void run_once() override
1578 {
1580 }
1581 };
1583 {
1584 EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1585 : EvaluationStep(rn, i, l, r, s, c, p, v)
1586 {
1587 }
1588 void run_many(ci n) override
1589 {
1590 for (int i = 0; i < n; i++)
1591 {
1592 state[storeIdx * n + i] =
1593 (state[argIdx1 * n + i] == state[argIdx2 * n + i]);
1594 }
1595 }
1596 void run_once() override
1597 {
1599 }
1600 };
1602 {
1603 EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1604 : EvaluationStep(rn, i, l, r, s, c, p, v)
1605 {
1606 }
1607 void run_many(ci n) override
1608 {
1609 for (int i = 0; i < n; i++)
1610 {
1611 state[storeIdx * n + i] =
1612 (state[argIdx1 * n + i] <= state[argIdx2 * n + i]);
1613 }
1614 }
1615 void run_once() override
1616 {
1618 }
1619 };
1621 {
1622 EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1623 : EvaluationStep(rn, i, l, r, s, c, p, v)
1624 {
1625 }
1626 void run_many(ci n) override
1627 {
1628 for (int i = 0; i < n; i++)
1629 {
1630 state[storeIdx * n + i] =
1631 (state[argIdx1 * n + i] < state[argIdx2 * n + i]);
1632 }
1633 }
1634 void run_once() override
1635 {
1637 }
1638 };
1640 {
1641 EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1642 : EvaluationStep(rn, i, l, r, s, c, p, v)
1643 {
1644 }
1645 void run_many(ci n) override
1646 {
1647 for (int i = 0; i < n; i++)
1648 {
1649 state[storeIdx * n + i] =
1650 (state[argIdx1 * n + i] >= state[argIdx2 * n + i]);
1651 }
1652 }
1653 void run_once() override
1654 {
1656 }
1657 };
1659 {
1660 EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1661 : EvaluationStep(rn, i, l, r, s, c, p, v)
1662 {
1663 }
1664 void run_many(ci n) override
1665 {
1666 for (int i = 0; i < n; i++)
1667 {
1668 state[storeIdx * n + i] =
1669 (state[argIdx1 * n + i] > state[argIdx2 * n + i]);
1670 }
1671 }
1672 void run_once() override
1673 {
1675 }
1676 };
1677 struct EvalMod : public EvaluationStep
1678 {
1679 EvalMod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1680 : EvaluationStep(rn, i, l, r, s, c, p, v)
1681 {
1682 }
1683 void run_many(ci n) override
1684 {
1685 for (int i = 0; i < n; i++)
1686 {
1687 state[storeIdx * n + i] =
1688 std::fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1689 }
1690 }
1691 void run_once() override
1692 {
1693 state[storeIdx] = std::fmod(state[argIdx1], state[argIdx2]);
1694 }
1695 };
1696 struct EvalAbs : public EvaluationStep
1697 {
1698 EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1699 : EvaluationStep(rn, i, l, r, s, c, p, v)
1700 {
1701 }
1702 void run_many(ci n) override
1703 {
1704 for (int i = 0; i < n; i++)
1705 {
1706 state[storeIdx * n + i] = std::abs(state[argIdx1 * n + i]);
1707 }
1708 }
1709 void run_once() override
1710 {
1712 }
1713 };
1714 struct EvalSign : public EvaluationStep
1715 {
1716 EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1717 : EvaluationStep(rn, i, l, r, s, c, p, v)
1718 {
1719 }
1720 void run_many(ci n) override
1721 {
1722 for (int i = 0; i < n; i++)
1723 {
1724 state[storeIdx * n + i] = ((state[argIdx1 * n + i] > 0.0) -
1725 (state[argIdx1 * n + i] < 0.0));
1726 }
1727 }
1728 void run_once() override
1729 {
1730 state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0));
1731 }
1732 };
1733 struct EvalAsin : public EvaluationStep
1734 {
1735 EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1736 : EvaluationStep(rn, i, l, r, s, c, p, v)
1737 {
1738 }
1739 void run_many(ci n) override
1740 {
1741 for (int i = 0; i < n; i++)
1742 {
1743 state[storeIdx * n + i] = std::asin(state[argIdx1 * n + i]);
1744 }
1745 }
1746 void run_once() override
1747 {
1748 state[storeIdx] = std::asin(state[argIdx1]);
1749 }
1750 };
1751 struct EvalAcos : public EvaluationStep
1752 {
1753 EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1754 : EvaluationStep(rn, i, l, r, s, c, p, v)
1755 {
1756 }
1757 void run_many(ci n) override
1758 {
1759 for (int i = 0; i < n; i++)
1760 {
1761 state[storeIdx * n + i] = std::acos(state[argIdx1 * n + i]);
1762 }
1763 }
1764 void run_once() override
1765 {
1766 state[storeIdx] = std::acos(state[argIdx1]);
1767 }
1768 };
1769 struct EvalAtan : public EvaluationStep
1770 {
1771 EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1772 : EvaluationStep(rn, i, l, r, s, c, p, v)
1773 {
1774 }
1775 void run_many(ci n) override
1776 {
1777 for (int i = 0; i < n; i++)
1778 {
1779 state[storeIdx * n + i] = std::atan(state[argIdx1 * n + i]);
1780 }
1781 }
1782 void run_once() override
1783 {
1784 state[storeIdx] = std::atan(state[argIdx1]);
1785 }
1786 };
1788 {
1789 EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1790 : EvaluationStep(rn, i, l, r, s, c, p, v)
1791 {
1792 }
1793 void run_many(ci n) override
1794 {
1795 for (int i = 0; i < n; i++)
1796 {
1797 state[storeIdx * n + i] =
1798 std::atan2(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1799 }
1800 }
1801 void run_once() override
1802 {
1803 state[storeIdx] = std::atan2(state[argIdx1], state[argIdx2]);
1804 }
1805 };
1806 struct EvalAng : public EvaluationStep
1807 {
1808 EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1809 : EvaluationStep(rn, i, l, r, s, c, p, v)
1810 {
1811 }
1812 void run_many(ci n) override
1813 {
1814 for (int i = 0; i < n; i++)
1815 {
1816 state[storeIdx * n + i] =
1817 ang(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1818 }
1819 }
1820 void run_once() override
1821 {
1823 }
1824 };
1826 {
1827 EvalBessel(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1828 : EvaluationStep(rn, i, l, r, s, c, p, v)
1829 {
1830 }
1831 void run_many(ci n) override
1832 {
1833 for (int i = 0; i < n; i++)
1834 {
1835 state[storeIdx * n + i] = boost::math::cyl_bessel_j(
1836 state[argIdx1 * n + i], state[argIdx2 * n + i]);
1837 }
1838 }
1839 void run_once() override
1840 {
1841 state[storeIdx] =
1842 boost::math::cyl_bessel_j(state[argIdx1], state[argIdx2]);
1843 }
1844 };
1845 struct EvalCeil : public EvaluationStep
1846 {
1847 EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1848 : EvaluationStep(rn, i, l, r, s, c, p, v)
1849 {
1850 }
1851 void run_many(ci n) override
1852 {
1853 for (int i = 0; i < n; i++)
1854 {
1855 state[storeIdx * n + i] = std::ceil(state[argIdx1 * n + i]);
1856 }
1857 }
1858 void run_once() override
1859 {
1860 state[storeIdx] = std::ceil(state[argIdx1]);
1861 }
1862 };
1863 struct EvalCos : public EvaluationStep
1864 {
1865 EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1866 : EvaluationStep(rn, i, l, r, s, c, p, v)
1867 {
1868 }
1869 void run_many(ci n) override
1870 {
1871 for (int i = 0; i < n; i++)
1872 {
1873 state[storeIdx * n + i] = std::cos(state[argIdx1 * n + i]);
1874 }
1875 }
1876 void run_once() override
1877 {
1878 state[storeIdx] = std::cos(state[argIdx1]);
1879 }
1880 };
1881 struct EvalCosh : public EvaluationStep
1882 {
1883 EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1884 : EvaluationStep(rn, i, l, r, s, c, p, v)
1885 {
1886 }
1887 void run_many(ci n) override
1888 {
1889 for (int i = 0; i < n; i++)
1890 {
1891 state[storeIdx * n + i] = std::cosh(state[argIdx1 * n + i]);
1892 }
1893 }
1894 void run_once() override
1895 {
1896 state[storeIdx] = std::cosh(state[argIdx1]);
1897 }
1898 };
1899 struct EvalExp : public EvaluationStep
1900 {
1901 EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1902 : EvaluationStep(rn, i, l, r, s, c, p, v)
1903 {
1904 }
1905 void run_many(ci n) override
1906 {
1907 for (int i = 0; i < n; i++)
1908 {
1909 state[storeIdx * n + i] = std::exp(state[argIdx1 * n + i]);
1910 }
1911 }
1912 void run_once() override
1913 {
1914 state[storeIdx] = std::exp(state[argIdx1]);
1915 }
1916 };
1917 struct EvalFabs : public EvaluationStep
1918 {
1919 EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1920 : EvaluationStep(rn, i, l, r, s, c, p, v)
1921 {
1922 }
1923 void run_many(ci n) override
1924 {
1925 for (int i = 0; i < n; i++)
1926 {
1927 state[storeIdx * n + i] = std::fabs(state[argIdx1 * n + i]);
1928 }
1929 }
1930 void run_once() override
1931 {
1932 state[storeIdx] = std::fabs(state[argIdx1]);
1933 }
1934 };
1936 {
1937 EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1938 : EvaluationStep(rn, i, l, r, s, c, p, v)
1939 {
1940 }
1941 void run_many(ci n) override
1942 {
1943 for (int i = 0; i < n; i++)
1944 {
1945 state[storeIdx * n + i] = std::floor(state[argIdx1 * n + i]);
1946 }
1947 }
1948 void run_once() override
1949 {
1950 state[storeIdx] = std::floor(state[argIdx1]);
1951 }
1952 };
1953 struct EvalFmod : public EvaluationStep
1954 {
1955 EvalFmod(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1956 : EvaluationStep(rn, i, l, r, s, c, p, v)
1957 {
1958 }
1959 void run_many(ci n) override
1960 {
1961 for (int i = 0; i < n; i++)
1962 {
1963 state[storeIdx * n + i] =
1964 fmod(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1965 }
1966 }
1967 void run_once() override
1968 {
1970 }
1971 };
1972 struct EvalLog : public EvaluationStep
1973 {
1974 EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1975 : EvaluationStep(rn, i, l, r, s, c, p, v)
1976 {
1977 }
1978 void run_many(ci n) override
1979 {
1980 for (int i = 0; i < n; i++)
1981 {
1982 state[storeIdx * n + i] = std::log(state[argIdx1 * n + i]);
1983 }
1984 }
1985 void run_once() override
1986 {
1988 }
1989 };
1991 {
1992 EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1993 : EvaluationStep(rn, i, l, r, s, c, p, v)
1994 {
1995 }
1996 void run_many(ci n) override
1997 {
1998 for (int i = 0; i < n; i++)
1999 {
2000 state[storeIdx * n + i] = std::log10(state[argIdx1 * n + i]);
2001 }
2002 }
2003 void run_once() override
2004 {
2005 state[storeIdx] = std::log10(state[argIdx1]);
2006 }
2007 };
2008 struct EvalMax : public EvaluationStep
2009 {
2010 EvalMax(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2011 : EvaluationStep(rn, i, l, r, s, c, p, v)
2012 {
2013 }
2014 void run_many(ci n) override
2015 {
2016 for (int i = 0; i < n; i++)
2017 {
2018 state[storeIdx * n + i] =
2019 fmax(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2020 }
2021 }
2022 void run_once() override
2023 {
2025 }
2026 };
2027 struct EvalMin : public EvaluationStep
2028 {
2029 EvalMin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2030 : EvaluationStep(rn, i, l, r, s, c, p, v)
2031 {
2032 }
2033 void run_many(ci n) override
2034 {
2035 for (int i = 0; i < n; i++)
2036 {
2037 state[storeIdx * n + i] =
2038 fmin(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2039 }
2040 }
2041 void run_once() override
2042 {
2044 }
2045 };
2046 struct EvalRad : public EvaluationStep
2047 {
2048 EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2049 : EvaluationStep(rn, i, l, r, s, c, p, v)
2050 {
2051 }
2052 void run_many(ci n) override
2053 {
2054 for (int i = 0; i < n; i++)
2055 {
2056 state[storeIdx * n + i] =
2057 rad(state[argIdx1 * n + i], state[argIdx2 * n + i]);
2058 }
2059 }
2060 void run_once() override
2061 {
2063 }
2064 };
2065 struct EvalSin : public EvaluationStep
2066 {
2067 EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2068 : EvaluationStep(rn, i, l, r, s, c, p, v)
2069 {
2070 }
2071 void run_many(ci n) override
2072 {
2073 for (int i = 0; i < n; i++)
2074 {
2075 state[storeIdx * n + i] = std::sin(state[argIdx1 * n + i]);
2076 }
2077 }
2078 void run_once() override
2079 {
2080 state[storeIdx] = std::sin(state[argIdx1]);
2081 }
2082 };
2083 struct EvalSinh : public EvaluationStep
2084 {
2085 EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2086 : EvaluationStep(rn, i, l, r, s, c, p, v)
2087 {
2088 }
2089 void run_many(ci n) override
2090 {
2091 for (int i = 0; i < n; i++)
2092 {
2093 state[storeIdx * n + i] = std::sinh(state[argIdx1 * n + i]);
2094 }
2095 }
2096 void run_once() override
2097 {
2098 state[storeIdx] = std::sinh(state[argIdx1]);
2099 }
2100 };
2101 struct EvalSqrt : public EvaluationStep
2102 {
2103 EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2104 : EvaluationStep(rn, i, l, r, s, c, p, v)
2105 {
2106 }
2107 void run_many(ci n) override
2108 {
2109 for (int i = 0; i < n; i++)
2110 {
2111 state[storeIdx * n + i] = std::sqrt(state[argIdx1 * n + i]);
2112 }
2113 }
2114 void run_once() override
2115 {
2117 }
2118 };
2119 struct EvalTan : public EvaluationStep
2120 {
2121 EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2122 : EvaluationStep(rn, i, l, r, s, c, p, v)
2123 {
2124 }
2125 void run_many(ci n) override
2126 {
2127 for (int i = 0; i < n; i++)
2128 {
2129 state[storeIdx * n + i] = std::tan(state[argIdx1 * n + i]);
2130 }
2131 }
2132 void run_once() override
2133 {
2134 state[storeIdx] = std::tan(state[argIdx1]);
2135 }
2136 };
2137 struct EvalTanh : public EvaluationStep
2138 {
2139 EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2140 : EvaluationStep(rn, i, l, r, s, c, p, v)
2141 {
2142 }
2143 void run_many(ci n) override
2144 {
2145 for (int i = 0; i < n; i++)
2146 {
2147 state[storeIdx * n + i] = std::tanh(state[argIdx1 * n + i]);
2148 }
2149 }
2150 void run_once() override
2151 {
2152 state[storeIdx] = std::tanh(state[argIdx1]);
2153 }
2154 };
2155 struct EvalAWGN : public EvaluationStep
2156 {
2157 EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
2158 : EvaluationStep(rn, i, l, r, s, c, p, v)
2159 {
2160 }
2161 void run_many(ci n) override
2162 {
2163 // assuming the argument to AWGN does not depend on spatial
2164 // variables =>
2165 std::normal_distribution<> _normal(0, state[storeIdx * n]);
2166 for (int i = 0; i < n; i++)
2167 {
2168 state[storeIdx * n + i] = _normal(rng);
2169 }
2170 }
2171 void run_once() override
2172 {
2173 std::normal_distribution<> _normal(0, state[storeIdx]);
2174 state[storeIdx] = _normal(rng);
2175 }
2176 };
2177};
2178
2180{
2181 m_impl = std::unique_ptr<ExpressionEvaluator>(new ExpressionEvaluator());
2182}
2183
2185{
2186}
2187
2188Interpreter::Interpreter(Interpreter &&r) : m_impl(std::move(r.m_impl))
2189{
2190}
2191
2193{
2194 m_impl = std::move(r.m_impl);
2195 return *this;
2196}
2197
2198void Interpreter::SetRandomSeed(unsigned int seed)
2199{
2200 m_impl->SetRandomSeed(seed);
2201}
2202
2204 std::map<std::string, NekDouble> const &constants)
2205{
2206 m_impl->AddConstants(constants);
2207}
2208
2209int Interpreter::AddConstant(std::string const &name, NekDouble value)
2210{
2211 return m_impl->AddConstant(name, value);
2212}
2213
2215{
2216 return m_impl->GetConstant(name);
2217}
2218
2219void Interpreter::SetParameters(std::map<std::string, NekDouble> const &params)
2220{
2221 m_impl->SetParameters(params);
2222}
2223
2224void Interpreter::SetParameter(std::string const &name, NekDouble value)
2225{
2226 m_impl->SetParameter(name, value);
2227}
2228
2230{
2231 return m_impl->GetParameter(name);
2232}
2233
2235{
2236 return m_impl->GetTime();
2237}
2238
2239int Interpreter::DefineFunction(const std::string &vlist,
2240 const std::string &function)
2241{
2242 return m_impl->DefineFunction(vlist, function);
2243}
2244
2245NekDouble Interpreter::Evaluate(const int AnalyticExpression_id)
2246{
2247 return m_impl->Evaluate(AnalyticExpression_id);
2248}
2249
2250NekDouble Interpreter::Evaluate(const int AnalyticExpression_id,
2251 const NekDouble x, const NekDouble y,
2252 const NekDouble z, const NekDouble t)
2253{
2254 return m_impl->Evaluate(AnalyticExpression_id, x, y, z, t);
2255}
2256
2257NekDouble Interpreter::EvaluateAtPoint(const int AnalyticExpression_id,
2258 std::vector<NekDouble> point)
2259{
2260 return m_impl->EvaluateAtPoint(AnalyticExpression_id, point);
2261}
2262
2263void Interpreter::Evaluate(const int expression_id,
2268 Array<OneD, NekDouble> &result)
2269{
2270 m_impl->Evaluate(expression_id, x, y, z, t, result);
2271}
2272
2274 const int expression_id,
2275 const std::vector<Array<OneD, const NekDouble>> &points,
2276 Array<OneD, NekDouble> &result)
2277{
2278 m_impl->Evaluate(expression_id, points, result);
2279}
2280
2281} // 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)