1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    UnitTestFunctionParser.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkSmartPointer.h"
17 
18 #include "vtkFunctionParser.h"
19 
20 #include "vtkMathUtilities.h"
21 #include "vtkMinimalStandardRandomSequence.h"
22 #include "vtkTestErrorObserver.h"
23 
24 #include <algorithm>
25 #include <sstream>
26 #include <string>
27 #include <vector>
28 
29 constexpr bool STATUS_SUCCESS = true;
30 constexpr bool STATUS_FAILURE = false;
31 
32 #define SCALAR_FUNC(proc, function, math)                                                          \
33   static bool proc(double low, double hi)                                                          \
34   {                                                                                                \
35     std::cout << "Testing " << #function << "...";                                                 \
36     auto parser = vtkSmartPointer<vtkFunctionParser>::New();                                       \
37     std::string _fun(#function);                                                                   \
38     _fun += "(x)";                                                                                 \
39     parser->SetFunction(_fun.c_str());                                                             \
40                                                                                                    \
41     auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();                          \
42     for (unsigned int i = 0; i < 1000; ++i)                                                        \
43     {                                                                                              \
44       double value = rand->GetNextRangeValue(low, hi);                                             \
45       parser->SetScalarVariableValue("x", value);                                                  \
46       double result = parser->GetScalarResult();                                                   \
47       double expected = math(value);                                                               \
48       if (!vtkMathUtilities::FuzzyCompare(                                                         \
49             result, expected, std::numeric_limits<double>::epsilon() * 1.0))                       \
50       {                                                                                            \
51         std::cout << "\n" #function " Expected " << expected << " but got " << result              \
52                   << " difference is " << result - expected << " eps ratio is: "                   \
53                   << (result - expected) / std::numeric_limits<double>::epsilon() << std::endl;    \
54         return STATUS_FAILURE;                                                                     \
55       }                                                                                            \
56     }                                                                                              \
57                                                                                                    \
58     std::cout << "PASSED\n";                                                                       \
59     return STATUS_SUCCESS;                                                                         \
60   }
61 
62 SCALAR_FUNC(TestAbs, abs, std::abs);
63 SCALAR_FUNC(TestAcos, acos, std::acos);
64 SCALAR_FUNC(TestAsin, asin, std::asin);
65 SCALAR_FUNC(TestAtan, atan, std::atan);
66 SCALAR_FUNC(TestCeil, ceil, std::ceil);
67 SCALAR_FUNC(TestCos, cos, std::cos);
68 SCALAR_FUNC(TestCosh, cosh, std::cosh);
69 SCALAR_FUNC(TestExp, exp, std::exp);
70 SCALAR_FUNC(TestFloor, floor, std::floor);
71 SCALAR_FUNC(TestLn, ln, std::log);
72 SCALAR_FUNC(TestLog10, log10, std::log10);
73 SCALAR_FUNC(TestSin, sin, std::sin);
74 SCALAR_FUNC(TestSinh, sinh, std::sinh);
75 SCALAR_FUNC(TestSqrt, sqrt, std::sqrt);
76 SCALAR_FUNC(TestTan, tan, std::tan);
77 SCALAR_FUNC(TestTanh, tanh, std::tanh);
78 static bool TestScalars();
79 static bool TestVariableNames();
80 static bool TestSpacing();
81 static bool TestUnaryOperations();
82 static bool TestScientificNotation();
83 static bool TestVectors();
84 static bool TestMinMax();
85 static bool TestScalarLogic();
86 static bool TestVectorLogic();
87 static bool TestMiscFunctions();
88 static bool TestErrors();
89 
UnitTestFunctionParser(int,char * [])90 int UnitTestFunctionParser(int, char*[])
91 {
92   bool status = STATUS_SUCCESS;
93 
94   status &= TestAbs(-1000.0, 1000);
95   status &= TestAcos(-1.0, 1.0);
96   status &= TestAsin(-1.0, 1.0);
97   status &= TestAtan(-1.0, 1.0);
98   status &= TestCeil(-1000.0, 1000.0);
99   status &= TestCos(-1000.0, 1000.0);
100   status &= TestCosh(-1.0, 1.0);
101   status &= TestExp(0, 2.0);
102   status &= TestFloor(-1000.0, 1000.0);
103   status &= TestLn(0.0, 1000.0);
104   status &= TestLog10(0.0, 1000.0);
105   status &= TestSin(-1000.0, 1000.0);
106   status &= TestSinh(-1.0, 1.0);
107   status &= TestSqrt(.1, 1000.0);
108   status &= TestTan(-1000.0, 1000.0);
109   status &= TestTanh(-1.0, 1.0);
110 
111   status &= TestScalars();
112   status &= TestVariableNames();
113   status &= TestSpacing();
114   status &= TestUnaryOperations();
115   status &= TestScientificNotation();
116   status &= TestVectors();
117   status &= TestMinMax();
118   status &= TestScalarLogic();
119   status &= TestVectorLogic();
120 
121   status &= TestMiscFunctions();
122   status &= TestErrors();
123   if (status == STATUS_FAILURE)
124   {
125     return EXIT_FAILURE;
126   }
127 
128   // Test printing of an uninitialized parser
129   std::ostringstream functionPrint;
130   auto functionParser = vtkSmartPointer<vtkFunctionParser>::New();
131   functionParser->Print(functionPrint);
132 
133   return EXIT_SUCCESS;
134 }
135 
TestUnaryOperations()136 bool TestUnaryOperations()
137 {
138   std::cout << "Testing Scalar Unary"
139             << "...";
140   std::string formula[4] = { "-x * +y", "+x + +y", "+x - -y", "-x - +y" };
141   double expected[4] = { -2., 3., 3., -3. };
142 
143   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
144   parser->SetScalarVariableValue("x", 1.0);
145   parser->SetScalarVariableValue("y", 2.0);
146   for (unsigned i = 0; i < 4; i++)
147   {
148     parser->SetFunction(&formula[i][0]);
149     double result = parser->GetScalarResult();
150     if (!vtkMathUtilities::FuzzyCompare(
151           result, expected[i], std::numeric_limits<double>::epsilon() * 1.0))
152     {
153       std::cout << "FAILED\n";
154       return STATUS_FAILURE;
155     }
156   }
157 
158   parser->SetScalarVariableValue("x", 3);
159   parser->SetScalarVariableValue("y", 2);
160   parser->SetFunction("(-x) ^ +y");
161   int result = parser->GetScalarResult();
162   if (result != 9)
163   {
164     std::cout << "FAILED\n";
165     return STATUS_FAILURE;
166   }
167 
168   parser->SetFunction("(-x)");
169   result = parser->GetScalarResult();
170   if (result != -3)
171   {
172     std::cout << "FAILED\n";
173     return STATUS_FAILURE;
174   }
175 
176   std::cout << "PASSED\n";
177   return STATUS_SUCCESS;
178 }
179 
TestScalars()180 bool TestScalars()
181 {
182   std::cout << "Testing Scalar Add / Subtract / Multiply / Divide"
183             << "...";
184   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
185   parser->SetScalarVariableValue("x", 1.0);
186   parser->SetScalarVariableValue("y", 2.0);
187   parser->SetFunction("+(x-y)/(x-y) * -(x-y)/(x-y) + (x - x)");
188   double result = parser->GetScalarResult();
189   if (result != -1.0)
190   {
191     std::cout << "FAILED\n";
192     return STATUS_FAILURE;
193   }
194   else
195   {
196     std::cout << "PASSED\n";
197     return STATUS_SUCCESS;
198   }
199 }
200 
TestVariableNames()201 bool TestVariableNames()
202 {
203   std::cout << "Testing variable names similar to math ops with parentheses "
204             << "...";
205   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
206   parser->SetScalarVariableValue("absolutex", 1.0);
207   parser->SetScalarVariableValue("y", 2.0);
208   parser->SetFunction("absolutex - (y)");
209   double result = parser->GetScalarResult();
210   if (result != -1.0)
211   {
212     std::cout << "FAILED\n";
213     return STATUS_FAILURE;
214   }
215   else
216   {
217     std::cout << "PASSED\n";
218     return STATUS_SUCCESS;
219   }
220 }
221 
TestSpacing()222 bool TestSpacing()
223 {
224   std::cout << "Testing spacing with math ops "
225             << "...";
226   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
227   parser->SetScalarVariableValue("x", -1.0);
228   parser->SetFunction("abs(x)");
229   double result = parser->GetScalarResult();
230   if (result != 1.0)
231   {
232     std::cout << "FAILED\n";
233     return STATUS_FAILURE;
234   }
235   parser->SetFunction("abs  (x)");
236   result = parser->GetScalarResult();
237   if (result != 1.0)
238   {
239     std::cout << "FAILED\n";
240     return STATUS_FAILURE;
241   }
242   else
243   {
244     std::cout << "PASSED\n";
245     return STATUS_SUCCESS;
246   }
247 }
248 
TestScientificNotation()249 bool TestScientificNotation()
250 {
251   std::cout << "Testing Scientific notation"
252             << "...";
253   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
254   parser->SetFunction("3.0e+01");
255   double expected = 3.0e+01;
256   double result = parser->GetScalarResult();
257   if (!vtkMathUtilities::FuzzyCompare(
258         result, expected, std::numeric_limits<double>::epsilon() * 1.0))
259   {
260     std::cout << " Scientific notation expected " << expected << " but got " << result;
261     std::cout << "eps ratio is: " << (result - expected) / std::numeric_limits<double>::epsilon()
262               << std::endl;
263     std::cout << "FAILED\n";
264     return STATUS_FAILURE;
265   }
266   else
267   {
268     std::cout << "PASSED\n";
269     return STATUS_SUCCESS;
270   }
271 }
272 
TestVectors()273 bool TestVectors()
274 {
275   std::cout << "Testing Cross"
276             << "...";
277   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
278 
279   bool status1 = STATUS_SUCCESS;
280   bool status2 = STATUS_SUCCESS;
281   bool status3 = STATUS_SUCCESS;
282   bool status4 = STATUS_SUCCESS;
283   bool status5 = STATUS_SUCCESS;
284 
285   auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
286   // Cross
287   for (unsigned int i = 0; i < 10; ++i)
288   {
289     double x0 = rand->GetNextRangeValue(-1.0, 1.0);
290     double x1 = rand->GetNextRangeValue(-1.0, 1.0);
291     double x2 = rand->GetNextRangeValue(-1.0, 1.0);
292     parser->SetVectorVariableValue("x", x0, x1, x2);
293 
294     double y0 = rand->GetNextRangeValue(-1.0, 1.0);
295     double y1 = rand->GetNextRangeValue(-1.0, 1.0);
296     double y2 = rand->GetNextRangeValue(-1.0, 1.0);
297     parser->SetVectorVariableValue("y", y0, y1, y2);
298 
299     parser->SetFunction("cross(x,y)");
300     double* result = parser->GetVectorResult();
301     double axb[3];
302     axb[0] = result[0];
303     axb[1] = result[1];
304     axb[2] = result[2];
305     // repeat to cover a 0 return from Evaluate()
306     parser->IsVectorResult();
307     parser->IsVectorResult();
308 
309     parser->SetFunction("cross(-y,x)");
310     result = parser->GetVectorResult();
311     double minusBxa[3];
312     minusBxa[0] = result[0];
313     minusBxa[1] = result[1];
314     minusBxa[2] = result[2];
315 
316     // a x b = -b x a
317     for (int j = 0; j < 3; ++j)
318     {
319       if (!vtkMathUtilities::FuzzyCompare(
320             axb[j], minusBxa[j], std::numeric_limits<double>::epsilon() * 1.0))
321       {
322         std::cout << " Cross expected " << minusBxa[j] << " but got " << axb[j];
323         std::cout << "eps ratio is: "
324                   << (axb[j] - minusBxa[j]) / std::numeric_limits<double>::epsilon() << std::endl;
325         status1 = STATUS_FAILURE;
326       }
327     }
328   }
329   if (status1 == STATUS_SUCCESS)
330   {
331     std::cout << "PASSED\n";
332   }
333   else
334   {
335     std::cout << "FAILED\n";
336   }
337 
338   parser->RemoveAllVariables();
339   // Add / Subtract / Multiply / Unary / Dot / Mag / Norm
340   std::cout << "Testing Add / Subtract / Multiply / Unary / Dot"
341             << "...";
342   for (unsigned int i = 0; i < 10; ++i)
343   {
344     double x0 = rand->GetNextRangeValue(-1.0, 1.0);
345     double x1 = rand->GetNextRangeValue(-1.0, 1.0);
346     double x2 = rand->GetNextRangeValue(-1.0, 1.0);
347     parser->SetVectorVariableValue("x", x0, x1, x2);
348 
349     double y0 = rand->GetNextRangeValue(-1.0, 1.0);
350     double y1 = rand->GetNextRangeValue(-1.0, 1.0);
351     double y2 = rand->GetNextRangeValue(-1.0, 1.0);
352     parser->SetVectorVariableValue("y", y0, y1, y2);
353 
354     parser->SetScalarVariableValue("t", 2.0);
355     parser->SetFunction("t*(x + y - (x + y))/t");
356     double* result = parser->GetVectorResult();
357     double a[3];
358     a[0] = result[0];
359     a[1] = result[1];
360     a[2] = result[2];
361 
362     parser->SetScalarVariableValue("s", 0.0);
363     parser->SetFunction("x * s");
364     result = parser->GetVectorResult();
365     double b[3];
366     b[0] = result[0];
367     b[1] = result[1];
368     b[2] = result[2];
369 
370     // 2.0 * ((x + y - (x + y)) / 2.0 = x * 0.0
371     for (int j = 0; j < 3; ++j)
372     {
373       if (!vtkMathUtilities::FuzzyCompare(a[j], b[j], std::numeric_limits<double>::epsilon() * 1.0))
374       {
375         std::cout << " Cross expected " << a[j] << " but got " << b[j];
376         std::cout << "eps ratio is: " << (a[j] - b[j]) / std::numeric_limits<double>::epsilon()
377                   << std::endl;
378         status2 = STATUS_FAILURE;
379       }
380     }
381     // Test Dot / Mag / Norm
382     // a x b dot a = 0
383     parser->SetFunction("cross(x, y).x");
384     double dot = parser->GetScalarResult();
385     if (!vtkMathUtilities::FuzzyCompare(dot, 0.0, std::numeric_limits<double>::epsilon() * 1.0))
386     {
387       std::cout << " Dot " << 0.0 << " but got " << dot;
388       std::cout << "eps ratio is: " << (dot - 0.0) / std::numeric_limits<double>::epsilon()
389                 << std::endl;
390       status3 = STATUS_FAILURE;
391     }
392 
393     // Test Mag and Norm
394     // mag(norm(x) == 1
395     parser->SetFunction("mag(norm(x))");
396     double mag = parser->GetScalarResult();
397     if (!vtkMathUtilities::FuzzyCompare(mag, 1.0, std::numeric_limits<double>::epsilon() * 2.0))
398     {
399       std::cout << " Mag expected" << 1.0 << " but got " << mag;
400       std::cout << " eps ratio is: " << (mag - 1.0) / std::numeric_limits<double>::epsilon()
401                 << std::endl;
402       status4 = STATUS_FAILURE;
403     }
404   }
405 
406   parser->RemoveAllVariables();
407   // x *iHat + y * jHat + z * zHat
408   parser->SetScalarVariableValue("x", 1.0);
409   parser->SetScalarVariableValue("y", 2.0);
410   parser->SetScalarVariableValue("z", 3.0);
411   parser->SetFunction("x*iHat + y*jHat + z*kHat");
412   double* xyz = parser->GetVectorResult();
413   if (xyz[0] != 1.0 || xyz[1] != 2.0 || xyz[2] != 3.0)
414   {
415     std::cout << "x*iHat + y*jHat + z*kHat expected "
416               << "(" << 1.0 << "," << 2.0 << "," << 3.0 << ") but got "
417               << "(" << xyz[0] << "," << xyz[1] << "," << xyz[2] << ")" << std::endl;
418     status5 = STATUS_FAILURE;
419   }
420 
421   // Test printing of an initialized parser
422   std::ostringstream parserPrint;
423   parser->Print(parserPrint);
424 
425   // Now clear the variables
426   parser->RemoveAllVariables();
427   if (parser->GetNumberOfScalarVariables() != 0 || parser->GetNumberOfVectorVariables() != 0)
428   {
429     std::cout << "RemoveAllVariables failed" << std::endl;
430     status1 = STATUS_FAILURE;
431   }
432 
433   // Invalidate function should change the function's mtime
434   vtkMTimeType before = parser->GetMTime();
435   parser->InvalidateFunction();
436   vtkMTimeType after = parser->GetMTime();
437 
438   if (before >= after)
439   {
440     std::cout << "InvalidateFunction() failed. MTime should have been modified" << std::endl;
441     status5 = STATUS_FAILURE;
442   }
443 
444   bool statusAll = status1 && status2 && status3 & status4 && status5;
445   if (statusAll == STATUS_SUCCESS)
446   {
447     std::cout << "PASSED\n";
448   }
449   return statusAll;
450 }
451 
TestMinMax()452 bool TestMinMax()
453 {
454   std::cout << "Testing Min/Max"
455             << "...";
456   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
457 
458   parser->SetFunction("min(x,y)");
459 
460   auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
461   bool status = STATUS_SUCCESS;
462   for (unsigned int i = 0; i < 1000; ++i)
463   {
464     double value = rand->GetNextRangeValue(-1000.0, 1000.0);
465     parser->SetScalarVariableValue("x", value);
466     parser->SetScalarVariableValue("y", -value);
467 
468     double result = parser->GetScalarResult();
469     double expected = std::min(value, -value);
470     if (!vtkMathUtilities::FuzzyCompare(
471           result, expected, std::numeric_limits<double>::epsilon() * 1.0))
472     {
473       std::cout << "\n";
474       std::cout << "Min Expected " << expected << " but got " << result << " difference is "
475                 << result - expected << " ";
476       std::cout << "eps ratio is: " << (result - expected) / std::numeric_limits<double>::epsilon()
477                 << std::endl;
478       status = STATUS_FAILURE;
479     }
480   }
481 
482   parser->SetFunction("max(x,y)");
483 
484   for (unsigned int i = 0; i < 1000; ++i)
485   {
486     double value = rand->GetNextRangeValue(-1000.0, 1000.0);
487     parser->SetScalarVariableValue("x", value);
488     parser->SetScalarVariableValue("y", -value);
489 
490     double result = parser->GetScalarResult();
491     double expected = std::max(value, -value);
492     if (!vtkMathUtilities::FuzzyCompare(
493           result, expected, std::numeric_limits<double>::epsilon() * 1.0))
494     {
495       std::cout << "\n";
496       std::cout << "Max Expected " << expected << " but got " << result << " difference is "
497                 << result - expected << " ";
498       std::cout << "eps ratio is: " << (result - expected) / std::numeric_limits<double>::epsilon()
499                 << std::endl;
500       status = STATUS_FAILURE;
501     }
502   }
503 
504   if (status == STATUS_SUCCESS)
505   {
506     std::cout << "PASSED\n";
507   }
508   return status;
509 }
510 
TestScalarLogic()511 bool TestScalarLogic()
512 {
513   bool status = STATUS_SUCCESS;
514   auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
515 
516   std::cout << "Testing Scalar Logic"
517             << "...";
518   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
519 
520   parser->SetFunction("if(x < y, x, y)");
521   for (unsigned int i = 0; i < 1000; ++i)
522   {
523     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
524     double y = rand->GetNextRangeValue(-1000.0, 1000.0);
525     parser->SetScalarVariableValue("x", x);
526     parser->SetScalarVariableValue("y", y);
527 
528     double result = parser->GetScalarResult();
529     double expected = x < y ? x : y;
530     if (result != expected)
531     {
532       std::cout << "\n";
533       std::cout << x << " < " << y << " Expected " << expected << " but got " << result
534                 << std::endl;
535       status = STATUS_FAILURE;
536     }
537   }
538 
539   parser->SetFunction("if(x > y, x, y)");
540   for (unsigned int i = 0; i < 1000; ++i)
541   {
542     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
543     double y = rand->GetNextRangeValue(-1000.0, 1000.0);
544     parser->SetScalarVariableValue("x", x);
545     parser->SetScalarVariableValue("y", y);
546 
547     double result = parser->GetScalarResult();
548     double expected = x > y ? x : y;
549     if (result != expected)
550     {
551       std::cout << "\n";
552       std::cout << x << " > " << y << " Expected " << expected << " but got " << result
553                 << std::endl;
554       status = STATUS_FAILURE;
555     }
556   }
557 
558   parser->SetFunction("if(x = y, x, 0.0)");
559   for (unsigned int i = 0; i < 1000; ++i)
560   {
561     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
562     double y = x;
563     parser->SetScalarVariableValue("x", x);
564     parser->SetScalarVariableValue("y", y);
565 
566     double result = parser->GetScalarResult();
567     double expected = x == y ? x : 0.0;
568     if (result != expected)
569     {
570       std::cout << "\n";
571       std::cout << x << " == " << y << " Expected " << expected << " but got " << result
572                 << std::endl;
573       status = STATUS_FAILURE;
574     }
575   }
576 
577   double ii[] = { 0.0, 0.0, 1.0, 1.0 };
578   double jj[] = { 0.0, 1.0, 0.0, 1.0 };
579   double expectedOr[] = { 0.0, 1.0, 1.0, 1.0 };
580   double expectedAnd[] = { .0, 0.0, 0.0, 1.0 };
581 
582   parser->SetFunction("i | j");
583   for (int i = 0; i < 3; ++i)
584   {
585     parser->SetScalarVariableValue("i", ii[i]);
586     parser->SetScalarVariableValue("j", jj[i]);
587     double result = parser->GetScalarResult();
588     if (result != expectedOr[i])
589     {
590       std::cout << "i | j expected " << expectedOr[i] << " but got " << result << std::endl;
591       status = STATUS_FAILURE;
592     }
593   }
594 
595   parser->SetFunction("i & j");
596   for (int i = 0; i < 3; ++i)
597   {
598     parser->SetScalarVariableValue("i", ii[i]);
599     parser->SetScalarVariableValue("j", jj[i]);
600     double result = parser->GetScalarResult();
601     if (result != expectedAnd[i])
602     {
603       std::cout << "i | j expected " << expectedAnd[i] << " but got " << result << std::endl;
604       status = STATUS_FAILURE;
605     }
606   }
607 
608   if (status == STATUS_SUCCESS)
609   {
610     std::cout << "PASSED\n";
611   }
612   else
613   {
614     std::cout << "FAILED\n";
615   }
616   return status;
617 }
618 
TestVectorLogic()619 bool TestVectorLogic()
620 {
621   bool status = STATUS_SUCCESS;
622   auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
623 
624   std::cout << "Testing Vector Logic"
625             << "...";
626   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
627 
628   parser->SetFunction("if(x < y, v, w)");
629   for (unsigned int i = 0; i < 1000; ++i)
630   {
631     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
632     double y = rand->GetNextRangeValue(-1000.0, 1000.0);
633     parser->SetScalarVariableValue("x", x);
634     parser->SetScalarVariableValue("y", y);
635 
636     double v1 = rand->GetNextRangeValue(-1000.0, 1000.0);
637     double v2 = rand->GetNextRangeValue(-1000.0, 1000.0);
638     double v3 = rand->GetNextRangeValue(-1000.0, 1000.0);
639     double w1 = rand->GetNextRangeValue(-1000.0, 1000.0);
640     double w2 = rand->GetNextRangeValue(-1000.0, 1000.0);
641     double w3 = rand->GetNextRangeValue(-1000.0, 1000.0);
642     parser->SetVectorVariableValue("v", v1, v2, v3);
643     parser->SetVectorVariableValue("w", w1, w2, w3);
644 
645     double result = parser->GetVectorResult()[0];
646     double expected = x < y ? v1 : w1;
647     if (result != expected)
648     {
649       std::cout << "\n";
650       std::cout << x << " < " << y << " Expected " << expected << " but got " << result
651                 << std::endl;
652       status = STATUS_FAILURE;
653     }
654   }
655 
656   parser->SetFunction("if(x > y, v, w)");
657   for (unsigned int i = 0; i < 1000; ++i)
658   {
659     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
660     double y = rand->GetNextRangeValue(-1000.0, 1000.0);
661     parser->SetScalarVariableValue("x", x);
662     parser->SetScalarVariableValue("y", y);
663 
664     double v1 = rand->GetNextRangeValue(-1000.0, 1000.0);
665     double v2 = rand->GetNextRangeValue(-1000.0, 1000.0);
666     double v3 = rand->GetNextRangeValue(-1000.0, 1000.0);
667     double w1 = rand->GetNextRangeValue(-1000.0, 1000.0);
668     double w2 = rand->GetNextRangeValue(-1000.0, 1000.0);
669     double w3 = rand->GetNextRangeValue(-1000.0, 1000.0);
670     parser->SetVectorVariableValue("v", v1, v2, v3);
671     parser->SetVectorVariableValue("w", w1, w2, w3);
672 
673     double result = parser->GetVectorResult()[0];
674     double expected = x > y ? v1 : w1;
675     if (result != expected)
676     {
677       std::cout << "\n";
678       std::cout << x << " > " << y << " Expected " << expected << " but got " << result
679                 << std::endl;
680       status = STATUS_FAILURE;
681     }
682   }
683 
684   parser->SetFunction("if(x = y, w, v * 0.0)");
685   for (unsigned int i = 0; i < 1000; ++i)
686   {
687 
688     double x = rand->GetNextRangeValue(-1000.0, 1000.0);
689     double y = x;
690     parser->SetScalarVariableValue("x", x);
691     parser->SetScalarVariableValue("y", y);
692 
693     double v1 = rand->GetNextRangeValue(-1000.0, 1000.0);
694     double v2 = rand->GetNextRangeValue(-1000.0, 1000.0);
695     double v3 = rand->GetNextRangeValue(-1000.0, 1000.0);
696     double w1 = rand->GetNextRangeValue(-1000.0, 1000.0);
697     double w2 = rand->GetNextRangeValue(-1000.0, 1000.0);
698     double w3 = rand->GetNextRangeValue(-1000.0, 1000.0);
699     parser->SetVectorVariableValue("v", v1, v2, v3);
700     parser->SetVectorVariableValue("w", w1, w2, w3);
701 
702     double result = parser->GetVectorResult()[0];
703     double expected = x > y ? v1 : w1;
704     if (result != expected)
705     {
706       std::cout << "\n";
707       std::cout << x << " == " << y << " Expected " << expected << " but got " << result
708                 << std::endl;
709       status = STATUS_FAILURE;
710     }
711   }
712 
713   if (status == STATUS_SUCCESS)
714   {
715     std::cout << "PASSED\n";
716   }
717   else
718   {
719     std::cout << "FAILED\n";
720   }
721 
722   return status;
723 }
724 
TestMiscFunctions()725 bool TestMiscFunctions()
726 {
727   bool statusAll = STATUS_SUCCESS;
728   auto rand = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
729 
730   std::cout << "Testing Sign"
731             << "...";
732   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
733   parser->SetFunction("sign(x)");
734   double values[3] = { -100.0, 0.0, 100.0 };
735   double expecteds[3] = { -1.0, 0.0, 1.0 };
736 
737   bool status = STATUS_SUCCESS;
738   for (unsigned int i = 0; i < 3; ++i)
739   {
740     parser->SetScalarVariableValue("x", values[i]);
741     double result = parser->GetScalarResult();
742     if (result != expecteds[i])
743     {
744       std::cout << "Sign expected " << expecteds[i] << " but got " << result << ". ";
745       status = STATUS_FAILURE;
746     }
747   }
748 
749   if (status == STATUS_SUCCESS)
750   {
751     std::cout << "PASSED\n";
752   }
753   else
754   {
755     statusAll = STATUS_FAILURE;
756     std::cout << "FAILED\n";
757   }
758 
759   std::cout << "Testing Pow"
760             << "...";
761   status = STATUS_SUCCESS;
762   for (unsigned int i = 0; i < 1000; ++i)
763   {
764     double x = rand->GetNextRangeValue(0.0, 10.0);
765     double y = rand->GetNextRangeValue(0.0, 2.0);
766     parser->SetScalarVariableValue("x", x);
767     parser->SetScalarVariableValue("y", y);
768     parser->SetFunction("x ^ y");
769     double result = parser->GetScalarResult();
770     double expected = std::pow(x, y);
771     if (!vtkMathUtilities::FuzzyCompare(
772           result, expected, std::numeric_limits<double>::epsilon() * 128.0))
773     {
774       std::cout << "\n";
775       std::cout << " pow Expected " << expected << " but got " << result << " difference is "
776                 << result - expected << " ";
777       std::cout << "eps ratio is: " << (result - expected) / std::numeric_limits<double>::epsilon()
778                 << std::endl;
779       status = STATUS_FAILURE;
780     }
781   }
782   if (status == STATUS_SUCCESS)
783   {
784     std::cout << "PASSED\n";
785   }
786   else
787   {
788     statusAll = STATUS_FAILURE;
789     std::cout << "FAILED\n";
790   }
791 
792   std::cout << "Testing Scalar divide"
793             << "...";
794   status = STATUS_SUCCESS;
795   for (unsigned int i = 0; i < 1000; ++i)
796   {
797     double x = rand->GetNextRangeValue(-10.0, 10.0);
798     double y = rand->GetNextRangeValue(-10.0, 10.0);
799     parser->SetScalarVariableValue("x", x);
800     parser->SetScalarVariableValue("y", y);
801     parser->SetFunction("x / y");
802     double result = parser->GetScalarResult();
803     double expected = x / y;
804     if (!vtkMathUtilities::FuzzyCompare(
805           result, expected, std::numeric_limits<double>::epsilon() * 256.0))
806     {
807       std::cout << "\n";
808       std::cout << " x / y Expected " << expected << " but got " << result << " difference is "
809                 << result - expected << " ";
810       std::cout << "eps ratio is: " << (result - expected) / std::numeric_limits<double>::epsilon()
811                 << std::endl;
812       status = STATUS_FAILURE;
813     }
814   }
815   if (status == STATUS_SUCCESS)
816   {
817     std::cout << "PASSED\n";
818   }
819   else
820   {
821     statusAll = STATUS_FAILURE;
822     std::cout << "FAILED\n";
823   }
824 
825   // SetScalarVariableValue
826   std::cout << "Testing SetScalarVariableValue...";
827   parser->SetScalarVariableValue(parser->GetScalarVariableName(0), 123.456);
828   if (parser->GetScalarVariableValue(parser->GetScalarVariableName(0)) != 123.456)
829   {
830     statusAll = STATUS_FAILURE;
831     std::cout << "FAILED\n";
832   }
833   else
834   {
835     std::cout << "PASSED\n";
836   }
837   parser->SetScalarVariableValue(0, 123.45);
838   parser->GetScalarVariableValue("x");
839 
840   parser->SetVectorVariableValue("v1", 1.0, 2.0, 3.0);
841   parser->SetVectorVariableValue("v1", 1.0, 1.0, 3.0);
842   parser->SetVectorVariableValue("v1", 1.0, 1.0, 1.0);
843   parser->SetVectorVariableValue(0, 1.0, 2.0, 3.0);
844   parser->SetVectorVariableValue(0, 1.0, 1.0, 3.0);
845   parser->SetVectorVariableValue(0, 1.0, 1.0, 1.0);
846   parser->GetVectorVariableValue(parser->GetVectorVariableName(0));
847   parser->GetVectorVariableName(1000);
848 
849   // test functions that can use ReplaceInvalidValue
850   std::vector<std::string> testFuncs;
851   testFuncs.emplace_back("sqrt(s)");
852   testFuncs.emplace_back("ln(s)");
853   testFuncs.emplace_back("log10(s)");
854   testFuncs.emplace_back("asin(s)");
855   testFuncs.emplace_back("acos(s)");
856   testFuncs.emplace_back("s/zero");
857 
858   parser->ReplaceInvalidValuesOn();
859   parser->SetReplacementValue(1234.5);
860   parser->SetScalarVariableValue("s", -1000.0);
861   parser->SetScalarVariableValue("zero", 0.0);
862 
863   for (size_t f = 0; f < testFuncs.size(); ++f)
864   {
865     parser->SetFunction(testFuncs[f].c_str());
866     if (parser->GetScalarResult() != 1234.5)
867     {
868       std::cout << testFuncs[f]
869                 << " failed to return a replacement value when ReplaceInvaliValues was On"
870                 << std::endl;
871       statusAll = STATUS_FAILURE;
872     }
873   }
874   parser->GetScalarResult();
875   return statusAll;
876 }
877 
TestErrors()878 bool TestErrors()
879 {
880   bool status = STATUS_SUCCESS;
881   std::cout << "Testing Errors"
882             << "...";
883 
884   auto parser = vtkSmartPointer<vtkFunctionParser>::New();
885 
886   auto errorObserver = vtkSmartPointer<vtkTest::ErrorObserver>::New();
887   parser->AddObserver(vtkCommand::ErrorEvent, errorObserver);
888 
889   // Parse: no function has been set
890   parser->SetFunction("cos(a)");
891   parser->SetFunction(nullptr);
892   parser->IsScalarResult();
893   status &= !errorObserver->CheckErrorMessage("Parse: no function has been set");
894 
895   double s = -2.0;
896   double v[3] = { 1.0, 2.0, 3.0 };
897   double w[3] = { 2.0, 1.0, 0.0 };
898   parser->SetScalarVariableValue("s", s);
899   parser->SetScalarVariableValue("zero", 0.0);
900   parser->SetVectorVariableValue("v", v[0], v[1], v[2]);
901   parser->SetVectorVariableValue("w", w[0], w[1], w[2]);
902 
903   // addition expects either 2 vectors or 2 scalars
904   parser->SetFunction("s + v");
905   parser->IsScalarResult();
906   status &= !errorObserver->CheckErrorMessage("addition expects either 2 vectors or 2 scalars");
907 
908   // subtraction expects either 2 vectors or 2 scalars
909   parser->SetFunction("s - v");
910   parser->IsScalarResult();
911   status &= !errorObserver->CheckErrorMessage("subtraction expects either 2 vectors or 2 scalars");
912 
913   // multiply expecting either 2 scalars or a scalar and a vector
914   parser->SetFunction("v * w");
915   parser->IsScalarResult();
916   status &= !errorObserver->CheckErrorMessage(
917     "multiply expecting either 2 scalars or a scalar and a vector");
918 
919   // can't divide vectors
920   parser->SetFunction("v / w");
921   parser->IsScalarResult();
922   status &= !errorObserver->CheckErrorMessage("can't divide vectors");
923 
924   // can't raise a vector to a power
925   parser->SetFunction("v ^ 2");
926   parser->IsScalarResult();
927   status &= !errorObserver->CheckErrorMessage("can't raise a vector to a power");
928 
929   // Vectors cannot be used in boolean expressions
930   parser->SetFunction("v | w");
931   parser->IsScalarResult();
932   status &= !errorObserver->CheckErrorMessage("Vectors cannot be used in boolean expressions");
933 
934   // expecting a scalar, but got a vector
935   parser->SetFunction("cos(v)");
936   parser->IsScalarResult();
937   status &= !errorObserver->CheckErrorMessage("expecting a scalar, but got a vector");
938 
939   // can't apply min to vectors
940   parser->SetFunction("min(v,w)");
941   parser->IsScalarResult();
942   status &= !errorObserver->CheckErrorMessage("can't apply min to vectors");
943   // can't apply max to vectors
944   parser->SetFunction("max(v,w)");
945   parser->IsScalarResult();
946   status &= !errorObserver->CheckErrorMessage("can't apply max to vectors");
947 
948   // can't apply cross to scalars
949   parser->SetFunction("cross(s,w)");
950   parser->IsScalarResult();
951   status &= !errorObserver->CheckErrorMessage("can't apply cross to scalars");
952 
953   // dot product does not operate on scalars
954   parser->SetFunction("s . v");
955   parser->IsScalarResult();
956   status &= !errorObserver->CheckErrorMessage("dot product does not operate on scalars");
957 
958   // magnitude expects a vector, but got a scalar
959   parser->SetFunction("mag(s)");
960   parser->IsScalarResult();
961   status &= !errorObserver->CheckErrorMessage("magnitude expects a vector, but got a scalar");
962 
963   // normalize expects a vector, but got a scalar
964   parser->SetFunction("norm(s)");
965   parser->IsScalarResult();
966   status &= !errorObserver->CheckErrorMessage("normalize expects a vector, but got a scalar");
967 
968   // first argument of if(bool,valtrue,valfalse) cannot be a vector
969   parser->SetFunction("if(v,s,s)");
970   parser->IsScalarResult();
971   status &= !errorObserver->CheckErrorMessage(
972     "first argument of if(bool,valtrue,valfalse) cannot be a vector");
973 
974   // first argument of if(bool,valtrue,valfalse) cannot be a vector
975   parser->SetFunction("if(v,s,s)");
976   parser->IsScalarResult();
977   status &= !errorObserver->CheckErrorMessage(
978     "first argument of if(bool,valtrue,valfalse) cannot be a vector");
979 
980   // the if function expects the second and third arguments to be either 2 vectors or 2 scalars
981   parser->SetFunction("if(s,v,s)");
982   parser->IsScalarResult();
983   status &= !errorObserver->CheckErrorMessage(
984     "the if function expects the second and third arguments to be either 2 vectors or 2 scalars");
985 
986   // Trying to take a natural logarithm of a non-positive value
987   parser->SetFunction("ln(s)");
988   parser->IsScalarResult();
989   status &=
990     !errorObserver->CheckErrorMessage("Trying to take a natural logarithm of a non-positive value");
991 
992   // Trying to take a log10 of a non-positive value
993   parser->SetFunction("log10(s)");
994   parser->IsScalarResult();
995   status &= !errorObserver->CheckErrorMessage("Trying to take a log10 of a non-positive value");
996 
997   // Trying to take a square root of a negative value
998   parser->SetFunction("sqrt(s)");
999   parser->IsScalarResult();
1000   status &= !errorObserver->CheckErrorMessage("Trying to take a square root of a negative value");
1001 
1002   // Trying to take asin of a value < -1 or > 1
1003   parser->SetFunction("asin(s)");
1004   parser->IsScalarResult();
1005   status &= !errorObserver->CheckErrorMessage("Trying to take asin of a value < -1 or > 1");
1006 
1007   // Trying to take acos of a value < -1 or > 1
1008   parser->SetFunction("acos(s)");
1009   parser->IsScalarResult();
1010   status &= !errorObserver->CheckErrorMessage("Trying to take acos of a value < -1 or > 1");
1011 
1012   // Trying to divide by zero<
1013   parser->SetFunction("s/zero");
1014   parser->IsScalarResult();
1015   status &= !errorObserver->CheckErrorMessage("Trying to divide by zero");
1016 
1017   // GetScalarResult: no valid scalar result
1018   parser->SetFunction("cross(v,w)");
1019   parser->GetScalarResult();
1020   status &= !errorObserver->CheckErrorMessage("GetScalarResult: no valid scalar result");
1021 
1022   // GetVectorResult: no valid vector result
1023   parser->SetFunction("v . w");
1024   parser->GetVectorResult();
1025   status &= !errorObserver->CheckErrorMessage("GetVectorResult: no valid vector result");
1026 
1027   // GetScalarVariableValue: scalar variable name ... does not exist
1028   parser->GetScalarVariableValue("xyz");
1029   status &= !errorObserver->CheckErrorMessage("GetScalarVariableValue: scalar variable name");
1030 
1031   // GetScalarVariableValue: scalar variable number ... does not exist
1032   parser->GetScalarVariableValue(128);
1033   status &= !errorObserver->CheckErrorMessage("GetScalarVariableValue: scalar variable number");
1034 
1035   // GetVectorVariableValue: vector variable name ... does not exist
1036   parser->GetVectorVariableValue("xyz");
1037   status &= !errorObserver->CheckErrorMessage("GetVectorVariableValue: vector variable name");
1038 
1039   // GetVectorVariableValue: vector variable number ... does not exist
1040   parser->GetVectorVariableValue(128);
1041   status &= !errorObserver->CheckErrorMessage("GetVectorVariableValue: vector variable number");
1042 
1043   // Syntax error: expecting a variable name
1044   parser->SetFunction("acos()");
1045   parser->IsScalarResult();
1046   status &= !errorObserver->CheckErrorMessage("Syntax error: expecting a variable name");
1047 
1048   // Parse errors
1049   parser->SetFunction("-");
1050   parser->IsScalarResult();
1051   status &= !errorObserver->CheckErrorMessage("Syntax error: unary minus with no operand");
1052 
1053   parser->SetFunction("s *");
1054   parser->IsScalarResult();
1055   status &= !errorObserver->CheckErrorMessage("Syntax error: expecting a variable name");
1056 
1057   parser->SetFunction("cross(v)");
1058   parser->IsScalarResult();
1059   status &=
1060     !errorObserver->CheckErrorMessage("Syntax Error: two parameters separated by commas expected");
1061 
1062   parser->SetFunction("if(v,s)");
1063   parser->IsScalarResult();
1064   status &= !errorObserver->CheckErrorMessage(
1065     "Syntax Error: three parameters separated by commas expected");
1066 
1067   parser->SetFunction("s * (v + w");
1068   parser->IsScalarResult();
1069   status &= !errorObserver->CheckErrorMessage("Syntax Error: missing closing parenthesis");
1070 
1071   parser->SetFunction("v + w)*s");
1072   parser->IsScalarResult();
1073   status &= !errorObserver->CheckErrorMessage("Syntax Error: mismatched parenthesis");
1074 
1075   parser->SetFunction("s s");
1076   parser->IsScalarResult();
1077   status &= !errorObserver->CheckErrorMessage("Syntax error: operator expected");
1078 
1079   parser->SetFunction("s*()");
1080   parser->IsScalarResult();
1081   status &= !errorObserver->CheckErrorMessage("Syntax error: expecting a variable name");
1082 
1083   if (status == STATUS_SUCCESS)
1084   {
1085     std::cout << "PASSED\n";
1086   }
1087   else
1088   {
1089     std::cout << "FAILED\n";
1090   }
1091   return status;
1092 }
1093