Isis 3 Programmer Reference
InlineCalculator.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "InlineCalculator.h"
8
9// std library
10#include <cmath>
11
12// Qt library
13#include <QMap>
14#include <QString>
15#include <QStringList>
16#include <QVariant>
17#include <QVector>
18
19// boost library
20#include <boost/foreach.hpp>
21
22// naif library
23#include <SpiceUsr.h>
24#include <SpiceZfc.h>
25#include <SpiceZmc.h>
26
27// other ISIS
28#include "IException.h"
29#include "InlineInfixToPostfix.h"
30#include "IString.h"
31#include "NaifStatus.h"
32
33using namespace std;
34
35namespace Isis {
36
44
45
52 InlineCalculator::InlineCalculator(const QString &equation) : Calculator() {
53 initialize();
55 }
56
57
64
65
74 return (m_functions.size());
75 }
76
77
86 return (m_equation);
87 }
88
89
106 bool InlineCalculator::compile(const QString &equation) {
107 // Transform equation to postfix order
108
109 QString tokenOps = toPostfix(equation);
110 tokenOps = tokenOps.simplified();
111
112 int nerrors = 0;
113 QString error = "Errors parsing inline equation[" + equation + "].";
114 IException errList(IException::User, error, _FILEINFO_);
115
116 Clear(); // Clear the stack
118 m_functions.clear(); // Clear function list
119
120 QStringList tokenList = tokenOps.split(" ");
121 while ( !tokenList.isEmpty() ) {
122 QString token = tokenList.takeFirst();
123 if ( !token.isEmpty() ) {
124
125 // See if the function already exists. Note that scalars and variables
126 // that are already present can safely be reused. New occuring ones are
127 // created fresh!
128 FxTypePtr fx = find(token);
129 if ( 0 != fx ) {
130 m_functions.push_back(fx);
131 }
132 // New scalars and variables will create new unique function objects if
133 // they do not already exist (they would be found above then)
134 else if ( isScalar(token) ) {
135 fx = addFunction(new ParameterFx(token, &InlineCalculator::scalar, this));
136 m_functions.push_back(fx);
137 }
138 else if ( isVariable(token) ) {
139 // Will also get line, sample, band, etc...
140 fx = addFunction(new ParameterFx(token, &InlineCalculator::variable, this));
141 m_functions.push_back(fx);
142 }
143 else {
144 // Parameter not recognized during compile. All unknown tokens are
145 // assumed to be variables until run time when they are searched for
146 // in the current state of the resource pool.
147 try {
148 if ( !orphanTokenHandler(token) ) {
149 error = "Equation element (" + token + ") invalid - token not recognized.";
150 errList.append(IException(IException::User, error, _FILEINFO_));
151 nerrors++;
152 }
153 }
154 // Catch all failures from orphaned tokens
155 catch (IException &e) {
156 errList.append(e);
157 nerrors++;
158 }
159 }
160 }
161 }
162
163 // Might want to make this optional here
164 if (nerrors > 0) {
165 throw errList;
166 }
167 return (nerrors == 0);
168 }
169
170
187 QVector<double> InlineCalculator::evaluate(CalculatorVariablePool *variablePool) {
188 QVector<double> value;
189 try {
190 pushVariables(variablePool);
191 value = evaluate();
192 popVariables();
193 }
194 catch (IException &ie) {
195 popVariables();
197 "Calculation with variable pool failed.",
198 _FILEINFO_);
199 }
200 return (value);
201 }
202
203
218 QVector<double> InlineCalculator::evaluate() {
219
220 BOOST_FOREACH (FxTypePtr function, m_functions) {
221 function->execute();
222 }
223
224 if (StackSize() != 1) {
225 QString msg = "Too many operands in the equation [" + m_equation + "].";
226 throw IException(IException::Unknown, msg, _FILEINFO_);
227 }
228
229 return (Pop(true));
230 }
231
232
241 QString InlineCalculator::toPostfix(const QString &equation) const {
243 return (parser.convert(equation));
244 }
245
246
255 bool InlineCalculator::isScalar(const QString &scalar) {
256 if (scalar.isEmpty()) return (false);
257 try {
259 return (true);
260 }
261 catch (IException &e) {
262 return (false);
263 }
264 }
265
266
275 bool InlineCalculator::isVariable(const QString &str) {
276 if (str.isEmpty()) {
277 return (false);
278 }
279 if (!isScalar(str)) {
280 return (true);
281 }
282 return (false);
283 }
284
285
294 void InlineCalculator::scalar(const QVariant &scalar) {
295 Push(toDouble(scalar.toString()));
296 }
297
298
309 void InlineCalculator::variable(const QVariant &variable) {
310 CalculatorVariablePool *variablePool = variables();
311 QString key = variable.toString();
312 if (variablePool->exists(key)) {
313 QVector<double> values = variablePool->value(key);
314 Push(values);
315 return;
316 }
317
318 // Error!
319 QString error = "Could not find variable [" + key + "] in variable pool.";
320 throw IException(IException::User, error, _FILEINFO_);
321 }
322
323
335 double floatModulusOperator(double a, double b) {
336 return (fmod(a, b));
337 }
338
339
346 QVector<double> y = Pop();
347 QVector<double> x = Pop();
348 QVector<double> result;
349 PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
351 Push(result);
352 return;
353 }
354
355
361 QVector<double> degree = Pop();
362 QVector<double> result;
363 BOOST_FOREACH(double d, degree) {
364 result.push_back(d * rpd_c());
365 }
366 Push(result);
367 return;
368 }
369
370
376 QVector<double> radians = Pop();
377 QVector<double> result;
378 BOOST_FOREACH(double r, radians) {
379 result.push_back(r * dpr_c());
380 }
381 Push(result);
382 return;
383 }
384
385
394 QVector<double> inputA = Pop();
395 QVector<double> inputB = Pop();
396 QVector<double> results;
397 if ( inputA.size() != inputB.size() ) {
398 QString msg = "Failed performing logical or operation, "
399 "input vectors are of differnet lengths.";
400 throw IException(IException::Unknown, msg, _FILEINFO_);
401 }
402 for (int i = 0; i < inputA.size(); i++) {
403 results.push_back( inputA[i] || inputB[i] );
404 }
405 Push(results);
406 return;
407 }
408
409
418 QVector<double> inputA = Pop();
419 QVector<double> inputB = Pop();
420 QVector<double> results;
421 if ( inputA.size() != inputB.size() ) {
422 QString msg = "Failed performing logical and operation, "
423 "input vectors are of differnet lengths.";
424 throw IException(IException::Unknown, msg, _FILEINFO_);
425 }
426 for (int i = 0; i < inputA.size(); i++) {
427 results.push_back( inputA[i] && inputB[i] );
428 }
429 Push(results);
430 return;
431 }
432
433
438 Push(pi_c());
439 return;
440 }
441
442
447 Push(E);
448 return;
449 }
450
451
461 bool InlineCalculator::fxExists(const QString &fxname) const {
462 return (m_fxPool.contains(fxname));
463 }
464
465
479 FxTypePtr func = find(function->name());
480 if (!func) {
481 m_fxPool.insert(function->name(), function);
482 }
483 else {
484 QString msg = "Function operator [" + function->name() +
485 "] exists! Cannot replace existing functions in the pool :-(";
486 throw IException(IException::Programmer, msg, _FILEINFO_);
487 }
488 return (function);
489 }
490
491
512 bool InlineCalculator::orphanTokenHandler(const QString &token) {
513 return (false);
514 }
515
516
524 m_variablePoolList.push_back(variablePool);
525 return;
526 }
527
528
537 if ( !m_variablePoolList.isEmpty() ) {
538 return (m_variablePoolList.back());
539 }
541 "Request for nonexistent variable pool.",
542 _FILEINFO_);
543 }
544
545
550 Clear();
551 if ( !m_variablePoolList.isEmpty() ) {
552 m_variablePoolList.pop_back();
553 }
554 return;
555 }
556
557
569 FxPoolType::iterator fx = m_fxPool.find(fxname);
570 if ( m_fxPool.end() == fx ) return NULL;
571 return (*fx);
572 }
573
574
579 // Set up calculator function lookup list
580 addFunction(new VoidFx("^", &Calculator::Exponent, this));
581 addFunction(new VoidFx("/", &Calculator::Divide, this));
582 addFunction(new VoidFx("*", &Calculator::Multiply, this));
583 addFunction(new VoidFx("<<", &Calculator::LeftShift, this));
584 addFunction(new VoidFx(">>", &Calculator::RightShift, this));
585 addFunction(new VoidFx("+", &Calculator::Add, this));
586 addFunction(new VoidFx("-", &Calculator::Subtract, this));
588 addFunction(new VoidFx("<", &Calculator::LessThan, this));
591 addFunction(new VoidFx("==", &Calculator::Equal, this));
592 addFunction(new VoidFx("!=", &Calculator::NotEqual, this));
593
594 // These are not part of the Calculator class because InfixToPostfix didn't
595 // add/recognize them in the tokenizer. See InlineInfixToPostfix class which
596 // is part of this calculator.
597 addFunction(new VoidFx("&", &Calculator::And, this));
598 addFunction(new VoidFx("and", &Calculator::And, this));
599 addFunction(new VoidFx("|", &Calculator::Or, this));
600 addFunction(new VoidFx("or", &Calculator::Or, this));
602 addFunction(new VoidFx("mod", &Calculator::Modulus, this));
604
605 addFunction(new VoidFx("--", &Calculator::Negative, this));
606 addFunction(new VoidFx("neg", &Calculator::Negative, this));
607
608 addFunction(new VoidFx("min", &Calculator::MinimumPixel, this));
609 addFunction(new VoidFx("max", &Calculator::MaximumPixel, this));
610 addFunction(new VoidFx("abs", &Calculator::AbsoluteValue, this));
611 addFunction(new VoidFx("sqrt", &Calculator::SquareRoot, this));
612 addFunction(new VoidFx("log", &Calculator::Log, this));
613 addFunction(new VoidFx("ln", &Calculator::Log, this));
614 addFunction(new VoidFx("log10", &Calculator::Log10, this));
616
617 addFunction(new VoidFx("sin", &Calculator::Sine, this));
618 addFunction(new VoidFx("cos", &Calculator::Cosine, this));
619 addFunction(new VoidFx("tan", &Calculator::Tangent, this));
620 addFunction(new VoidFx("sec", &Calculator::Secant, this));
621 addFunction(new VoidFx("csc", &Calculator::Cosecant, this));
622 addFunction(new VoidFx("cot", &Calculator::Cotangent, this));
623 addFunction(new VoidFx("asin", &Calculator::Arcsine, this));
624 addFunction(new VoidFx("acos", &Calculator::Arccosine, this));
625 addFunction(new VoidFx("atan", &Calculator::Arctangent, this));
626 addFunction(new VoidFx("atan2", &Calculator::Arctangent2, this));
627
633
634 // Add new functions available for inlining
635 // m_variablePoolList = defaultVariables();
636
637 return;
638 }
639
640
646 BOOST_FOREACH (FxTypePtr function, m_fxPool) {
647 delete function;
648 }
649
650 m_fxPool.clear();
651 m_functions.clear();
652 return;
653 }
654
655
661
662
668
669
676 bool CalculatorVariablePool::exists(const QString &variable) const {
677 return (true);
678 }
679
680
691 QVector<double> CalculatorVariablePool::value(const QString &variable,
692 const int &index) const {
693 QString mess = "No implementation in Calculator variable pool to provide "
694 " value for variable [" + variable + "].";
695 throw IException(IException::Programmer, mess, _FILEINFO_);
696 }
697
698
711 void CalculatorVariablePool::add(const QString &key, QVector<double> &values) {
712 QString mess = "No implementation in Calculator variable pool to add "
713 " value for variable [" + key + "].";
714 throw IException(IException::Programmer, mess, _FILEINFO_);
715 }
716
717
723 FxBinder::FxBinder(const QString &name) : m_name(name) {
724 }
725
726
732
733
739 QString FxBinder::name() const {
740 return (m_name);
741 }
742
743
749 dispatch();
750 }
751
752
758 dispatch();
759 }
760
761
768 QVariant FxBinder::args() {
769 return (QVariant(m_name));
770 }
771
772
781 InlineVoidFx::InlineVoidFx(const QString &name, calcOp function,
782 InlineCalculator *calculator) : FxBinder(name),
783 m_func(function),
784 m_calc(calculator) {
785 }
786
787
793
794
800 CALL_MEMBER_FN(*m_calc, m_func)();
801 }
802
803
815 ParameterFx::ParameterFx(const QString &name, calcOp function,
816 InlineCalculator *calculator) : FxBinder(name),
817 m_func(function),
818 m_calc(calculator){
819 }
820
821
827
828
835 CALL_MEMBER_FN(*m_calc, m_func)(args());
836 }
837
838
847 VoidFx::VoidFx(const QString &name, calcOp function,
848 InlineCalculator *calculator) : FxBinder(name),
849 m_func(function),
850 m_calc(calculator) {
851 }
852
853
859
860
866 CALL_MEMBER_FN(*m_calc, m_func)();
867 }
868} // namespace Isis
Calculator for arrays.
Definition Calculator.h:55
void LessThan()
Pop two elements off the stack and compare them to see where one is less than the other,...
void Cosecant()
Pops one element and push the cosecant.
void Arctangent2()
Pops two elements and push the arctangent.
void Modulus()
Pops two elements, mods them, then pushes the result on the stack.
void Tangent()
Pops one element and push the tangent.
int StackSize()
Returns the current stack size.
void Arctangent()
Pops one element and push the arctangent.
void Divide()
Pops two, divides them, then pushes the quotient on the stack.
void GreaterThanOrEqual()
Pop two elements off the stack and compare them to see where one is greater than or equal to the othe...
void Push(double scalar)
Push a scalar onto the stack.
void Cotangent()
Pops one element and push the cotangent.
void Add()
Pops two elements, adds them, then pushes the sum on the stack.
void Multiply()
Pops two elements, multiplies them, then pushes the product on the stack.
void Negative()
Pops an element, negates it, then pushes the result.
void RightShift()
Pop the top element, then perform a right shift with zero fill.
void Or()
Pop two elements, OR them, then push the result on the stack.
void Sine()
Pops one element and push the sine.
virtual void Clear()
Clear out the stack.
void PerformOperation(QVector< double > &results, QVector< double >::iterator arg1Start, QVector< double >::iterator arg1End, double operation(double))
Performs the mathematical operations on each argument.
void Arcsine()
Pops one element and push the arcsine.
void LeftShift()
Pop the top element, then perform a left shift with zero fill.
void LessThanOrEqual()
Pop two elements off the stack and compare them to see where one is less than or equal to the other,...
void NotEqual()
Pop two elements off the stack and compare them to see where one is not equal to the other,...
void GreaterThan()
Pop two elements off the stack and compare them to see where one is greater than the other,...
void Arccosine()
Pops one element and push the arccosine.
void Log10()
Pop an element, compute its base 10 log, then push the result on the stack.
void MaximumPixel()
Pop two elements, then push the maximum on a pixel by pixel basis back on the stack.
void Secant()
Pops one element and push the secant.
void Log()
Pop an element, compute its log, then push the result on the stack.
void Subtract()
Pops two elements, subtracts them, then pushes the difference on the stack.
void Equal()
Pop two elements off the stack and compare them to see where one is equal to the other,...
QVector< double > Pop(bool keepSpecials=false)
Pop an element off the stack.
void AbsoluteValue()
Pop an element, compute its absolute value, then push the result on the stack.
void MinimumPixel()
Pop two elements, then push the minimum on a pixel by pixel basis back on the stack.
void Exponent()
Pops two elements, computes the power then pushes the result on the stack The exponent has to be a sc...
void And()
Pop two elements, AND them, then push the result on the stack.
void SquareRoot()
Pop an element, compute its square root, then push the root on the stack.
void Cosine()
Pops one element and push the cosine.
This is a simple class to model a Calculator Variable Pool.
CalculatorVariablePool()
Constructs a CalculatorVariablePool object.
virtual void add(const QString &key, QVector< double > &values)
Add a parameter to the variable pool.
virtual QVector< double > value(const QString &variable, const int &index=0) const
Return vector of doubles for Calculator functions.
virtual bool exists(const QString &variable) const
Returns true so the real error can be reported.
~CalculatorVariablePool()
Destroys the CalculatorVariablePool object.
This is the parent class to the various function classes.
QString m_name
Name of function.
void operator()()
Executes the function.
virtual ~FxBinder()
Destroys the FxBinder object.
void execute()
Executes the function.
FxBinder(const QString &name)
Constructs a function binder given a name.
virtual void dispatch()=0
This method defines how to execute this function.
virtual QVariant args()
Accesses the arguments for this function.
QString name() const
The name assigned to this function binder.
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
QString convert(const QString &infix)
This method converts infix to postfix.
Provides a calculator for inline equations.
virtual QString toPostfix(const QString &equation) const
Converts the given string from infix to postfix format.
void degrees()
Pops the top vector off the current stack and converts from radians to degrees.
FxTypePtr find(const QString &fxname)
Gets a pointer to the function from the current pool that corresponds to the given function name.
void initialize()
Adds the recognized functions to the function pool.
QVector< double > evaluate()
Evaluate compiled equation with existing variable pool.
bool isVariable(const QString &str)
Determines whether the given string is a variable.
void pushVariables(CalculatorVariablePool *variablePool)
Push the given variable pool onto the current variable pool list.
QList< CalculatorVariablePool * > m_variablePoolList
The list of variable pool pointers.
CalculatorVariablePool * variables()
Accesses the last variable pool in the current pool list.
void logicalOr()
Pops the top two vectors off the current stack and performs a logical or on each pair.
void scalar(const QVariant &scalar)
Pushes the given value onto the stack as a scalar.
virtual bool orphanTokenHandler(const QString &token)
Default token handler if it is undefined during parsing/compilation.
void floatModulus()
Pops the top two vectors off the current stack and performs the floatModulusOperator() on the corresp...
void destruct()
Discard of all the function pool and class resources.
void pi()
Pushes the PI constant onto the current stack.
void logicalAnd()
Pops the top two vectors off the current stack and performs a logical and on each pair.
void eConstant()
Pushes the Euler constant (e) onto the current stack.
virtual ~InlineCalculator()
Destroys the InlineCalculator object.
void variable(const QVariant &variable)
Pushes the given value onto the stack as a variable.
int size() const
Accesses the number of functions, operators, variables, and scalars to be executed.
void popVariables()
Removes the last variable pool in the current variable pool list.
void radians()
Pops the top vector off the current stack and converts from degrees to radians.
QString m_equation
The equation to be evaluated.
InlineCalculator()
Constructs an InlineCalculator object by initializing the operator lookup list.
bool compile(const QString &equation)
Compiles the given equation for evaluation.
bool fxExists(const QString &fxname) const
Determines whether the given function name exists in the current function pool.
QString equation() const
Accesses the string representation of the current equation, in postfix format.
FxTypePtr addFunction(FxTypePtr function)
Adds a function to the function pool.
FxPoolType m_fxPool
The map between function names and equation lists.
FxEqList m_functions
The list of pointers to function equations for the calculator.
bool isScalar(const QString &scalar)
Determines whether the given string contains a scalar value (i.e.
A parser for converting equation strings to postfix.
This class is used to bind function names with corresponding InlineCalculator functions that do not t...
calcOp m_func
The InlineCalculator operator that takes no parameters.
InlineCalculator * m_calc
The InlineCalculator used to evaluate this function.
InlineVoidFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs an InlineVoid function from the given name, InlineCalculator operator, and InlineCalculato...
void dispatch()
Calls the function corresponding to this object using its stored InlineCalculator and InlineCalculato...
virtual ~InlineVoidFx()
Destroys the InlineVoidFx object.
This class is used to bind function names with corresponding Calculator functions that take a paramet...
InlineCalculator * m_calc
The InlineCalculator used to evaluate this function.
virtual ~ParameterFx()
Destroys the ParameterFx object.
calcOp m_func
The InlineCalculator operator that takes parameters.
void dispatch()
Calls the function corresponding to this object using its stored InlineCalculator,...
ParameterFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs a Parameter function from the given name (containing the appropriate parameters),...
This class is used to bind function names with corresponding Calculator functions that do not take pa...
InlineCalculator * m_calc
The Calculator used to evaluate this function.
virtual ~VoidFx()
Destroys the VoidFx object.
void dispatch()
Calls the function corresponding to this object using its stored Calculator and Calculator operator.
calcOp m_func
The Calculator operator that takes no parameters.
VoidFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs a Void function from the given name, Calculator operator, and Calculator.
const double E
Sets some basic constants for use in ISIS programming.
Definition Constants.h:39
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
double floatModulusOperator(double a, double b)
Determines the remainder of the quotient a/b whose sign is the same as that of a.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
Namespace for the standard library.