UnitTestMath.cxx 84.8 KB
Newer Older
Bill Lorensen's avatar
Bill Lorensen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    UnitTestMath.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkMath.h"
#include "vtkMathUtilities.h"
#include "vtkSmartPointer.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnsignedShortArray.h"
#include "vtkType.h"

#include <vector>

static int TestPi();
Bill Lorensen's avatar
Bill Lorensen committed
26
#if 0
Bill Lorensen's avatar
Bill Lorensen committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
static int TestDoublePi();
static int TestDoubleTwoPi();
#endif
static int TestDegreesFromRadians();
static int TestRound();
static int TestFloor();
static int TestCeil();
static int TestCeilLog2();
static int TestIsPowerOfTwo();
static int TestNearestPowerOfTwo();
static int TestFactorial();
static int TestBinomial();
static int TestRandom();
static int TestAddSubtract();
static int TestMultiplyScalar();
static int TestMultiplyScalar2D();
static int TestDot();
static int TestOuter();
static int TestCross();
static int TestNorm();
static int TestNormalize();
static int TestPerpendiculars();
static int TestProjectVector();
static int TestProjectVector2D();
static int TestDistance2BetweenPoints();
static int TestAngleBetweenVectors();
static int TestGaussianAmplitude();
static int TestGaussianWeight();
static int TestDot2D();
static int TestNorm2D();
static int TestNormalize2D();
static int TestDeterminant2x2();
static int TestDeterminant3x3();
static int TestLUFactor3x3();
static int TestLUSolve3x3();
static int TestLinearSolve3x3();
static int TestMultiply3x3();
static int TestMultiplyMatrix();
static int TestTranspose3x3();
static int TestInvert3x3();
static int TestInvertMatrix();
static int TestIdentity3x3();
static int TestQuaternionToMatrix3x3();
static int TestMatrix3x3ToQuaternion();
static int TestMultiplyQuaternion();
static int TestOrthogonalize3x3();
static int TestDiagonalize3x3();
static int TestSingularValueDecomposition3x3();
static int TestSolveLinearSystem();
static int TestSolveLeastSquares();
static int TestSolveHomogeneousLeastSquares();
static int TestLUSolveLinearSystemEstimateMatrixCondition();
static int TestJacobiN();
static int TestClampValue();
static int TestClampValues();
static int TestClampAndNormalizeValue();
83
static int TestTensorFromSymmetricTensor();
Bill Lorensen's avatar
Bill Lorensen committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
static int TestGetScalarTypeFittingRange();
static int TestGetAdjustedScalarRange();
static int TestExtentIsWithinOtherExtent();
static int TestBoundsIsWithinOtherBounds();
static int TestPointIsWithinBounds();
static int TestSolve3PointCircle();
static int TestRGBToHSV();
static int TestInf();
static int TestNegInf();
static int TestNan();

int UnitTestMath(int,char *[])
{
  int status = 0;

  status += TestPi();

Bill Lorensen's avatar
Bill Lorensen committed
101
#if 0
Bill Lorensen's avatar
Bill Lorensen committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  status += TestDoublePi(); // legacy
  status += TestDoubleTwoPi(); // legacy
#endif

  status += TestDegreesFromRadians();
  status += TestRound();
  status += TestFloor();
  status += TestCeil();
  status += TestCeilLog2();
  status += TestIsPowerOfTwo();
  status += TestNearestPowerOfTwo();
  status += TestFactorial();
  status += TestBinomial();
  status += TestRandom();
  status += TestAddSubtract();
  status += TestMultiplyScalar();
  status += TestMultiplyScalar2D();
  status += TestDot();
  status += TestOuter();
  status += TestCross();
  status += TestNorm();
  status += TestNormalize();
  status += TestPerpendiculars();
  status += TestProjectVector();
  status += TestProjectVector2D();
  status += TestDistance2BetweenPoints();
  status += TestAngleBetweenVectors();
  status += TestGaussianAmplitude();
  status += TestGaussianWeight();
  status += TestDot2D();
  status += TestNorm2D();
  status += TestNormalize2D();
  status += TestDeterminant2x2();
  status += TestDeterminant3x3();
  status += TestLUFactor3x3();
  status += TestLUSolve3x3();
  status += TestLinearSolve3x3();
  status += TestMultiply3x3();
  status += TestMultiplyMatrix();
  status += TestTranspose3x3();
  status += TestInvert3x3();
  status += TestInvertMatrix();
  status += TestIdentity3x3();
  status += TestQuaternionToMatrix3x3();
  status += TestMatrix3x3ToQuaternion();
  status += TestMultiplyQuaternion();
  status += TestOrthogonalize3x3();
  status += TestDiagonalize3x3();
  status += TestSingularValueDecomposition3x3();
  status += TestSolveLinearSystem();
  status += TestSolveLeastSquares();
  status += TestSolveHomogeneousLeastSquares();
  status += TestLUSolveLinearSystemEstimateMatrixCondition();
  status += TestJacobiN();
  status += TestClampValue();
  status += TestClampValues();
  status += TestClampAndNormalizeValue();
159
  status += TestTensorFromSymmetricTensor();
Bill Lorensen's avatar
Bill Lorensen committed
160 161 162 163 164 165 166 167 168 169 170
  status += TestGetScalarTypeFittingRange();
  status += TestGetAdjustedScalarRange();
  status += TestExtentIsWithinOtherExtent();
  status += TestBoundsIsWithinOtherBounds();
  status += TestPointIsWithinBounds();
  status += TestSolve3PointCircle();
  status += TestRGBToHSV();
  status += TestInf();
  status += TestNegInf();
  status += TestNan();
  if (status != 0)
171
  {
Bill Lorensen's avatar
Bill Lorensen committed
172
    return EXIT_FAILURE;
173
  }
Bill Lorensen's avatar
Bill Lorensen committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187

  vtkSmartPointer<vtkMath> math =
    vtkSmartPointer<vtkMath>::New();
  math->Print(std::cout);

  return EXIT_SUCCESS;
}

// Validate by comparing to atan/4
int TestPi()
{
  int status = 0;
  std::cout << "Pi..";
  if (vtkMath::Pi() != std::atan(1.0) * 4.0)
188
  {
Bill Lorensen's avatar
Bill Lorensen committed
189 190 191
    std::cout << "Expected " << vtkMath::Pi()
              << " but got " << std::atan(1.0) * 4.0;
    ++status;
192
  }
Bill Lorensen's avatar
Bill Lorensen committed
193 194

  if (status)
195
  {
Bill Lorensen's avatar
Bill Lorensen committed
196
    std::cout << "..FAILED" << std::endl;
197
  }
Bill Lorensen's avatar
Bill Lorensen committed
198
  else
199
  {
Bill Lorensen's avatar
Bill Lorensen committed
200
    std::cout << ".PASSED" << std::endl;
201
  }
Bill Lorensen's avatar
Bill Lorensen committed
202 203 204
  return status;
}

Bill Lorensen's avatar
Bill Lorensen committed
205
#if 0
Bill Lorensen's avatar
Bill Lorensen committed
206 207 208 209 210 211 212
// Validate by comparing to atan/4
int TestDoublePi()
{
  int status = 0;
  std::cout << "DoublePi..";

  if (vtkMath::DoublePi() != std::atan(1.0) * 4.0)
213
  {
Bill Lorensen's avatar
Bill Lorensen committed
214 215 216
    std::cout << "Expected " << vtkMath::Pi()
              << " but got " << std::atan(1.0) * 4.0;
    ++status;
217
  }
Bill Lorensen's avatar
Bill Lorensen committed
218 219

  if (status)
220
  {
Bill Lorensen's avatar
Bill Lorensen committed
221
    std::cout << "..FAILED" << std::endl;
222
  }
Bill Lorensen's avatar
Bill Lorensen committed
223
  else
224
  {
Bill Lorensen's avatar
Bill Lorensen committed
225
    std::cout << ".PASSED" << std::endl;
226
  }
Bill Lorensen's avatar
Bill Lorensen committed
227 228 229 230 231 232 233 234 235 236
  return status;
}

// Validate by comparing to atan/4 * 2
int TestDoubleTwoPi()
{
  int status = 0;
  std::cout << "DoubleTwoPi..";

  if (vtkMath::DoubleTwoPi() != std::atan(1.0) * 4.0 * 2.0)
237
  {
Bill Lorensen's avatar
Bill Lorensen committed
238 239 240
    std::cout << "Expected " << vtkMath::Pi() * 2.0
              << " but got " << std::atan(1.0) * 4.0 * 2.0;
    ++status;
241
  }
Bill Lorensen's avatar
Bill Lorensen committed
242 243

  if (status)
244
  {
Bill Lorensen's avatar
Bill Lorensen committed
245
    std::cout << "..FAILED" << std::endl;
246
  }
Bill Lorensen's avatar
Bill Lorensen committed
247
  else
248
  {
Bill Lorensen's avatar
Bill Lorensen committed
249
    std::cout << ".PASSED" << std::endl;
250
  }
Bill Lorensen's avatar
Bill Lorensen committed
251 252 253 254 255 256 257 258 259 260 261 262
  return status;
}
#endif

// Validate against RadiansFromDegress
int TestDegreesFromRadians()
{
  int status = 0;
  std::cout << "DegreesFromRadians..";

  unsigned int numSamples = 1000;
  for (unsigned int i = 0; i < numSamples; ++i)
263
  {
Bill Lorensen's avatar
Bill Lorensen committed
264 265 266 267 268 269
    float floatDegrees = vtkMath::Random(-180.0, 180.0);
    float floatRadians = vtkMath::RadiansFromDegrees(floatDegrees);
    float result = vtkMath::DegreesFromRadians(floatRadians);
    if (!vtkMathUtilities::FuzzyCompare(
          result, floatDegrees,
          std::numeric_limits<float>::epsilon()*128.0f))
270
    {
luz.paz's avatar
luz.paz committed
271
      std::cout << "Float Expected " << floatDegrees
Bill Lorensen's avatar
Bill Lorensen committed
272 273 274 275 276 277
                << " but got " << result
                << " difference is " << result - floatDegrees << " ";
      std::cout << "eps ratio is: " << (result - floatDegrees)
        / std::numeric_limits<float>::epsilon() << std::endl;
      ++status;
    }
278
  }
Bill Lorensen's avatar
Bill Lorensen committed
279
  for (unsigned int i = 0; i < numSamples; ++i)
280
  {
Bill Lorensen's avatar
Bill Lorensen committed
281 282 283 284 285 286
    double doubleDegrees = vtkMath::Random(-180.0, 180.0);
    double doubleRadians = vtkMath::RadiansFromDegrees(doubleDegrees);
    double result = vtkMath::DegreesFromRadians(doubleRadians);
    if (!vtkMathUtilities::FuzzyCompare(
          result, doubleDegrees,
          std::numeric_limits<double>::epsilon()*256.0))
287
    {
Bill Lorensen's avatar
Bill Lorensen committed
288 289 290 291 292 293 294
      std::cout << " Double Expected " << doubleDegrees
                << " but got " << result
                << " difference is " << result - doubleDegrees;
      std::cout << " eps ratio is: " << (result - doubleDegrees)
        / std::numeric_limits<double>::epsilon() << std::endl;
      ++status;
    }
295
  }
Bill Lorensen's avatar
Bill Lorensen committed
296
  if (status)
297
  {
Bill Lorensen's avatar
Bill Lorensen committed
298
    std::cout << "..FAILED" << std::endl;
299
  }
Bill Lorensen's avatar
Bill Lorensen committed
300
  else
301
  {
Bill Lorensen's avatar
Bill Lorensen committed
302
    std::cout << ".PASSED" << std::endl;
303
  }
Bill Lorensen's avatar
Bill Lorensen committed
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
  return status;
}

// Validate with http://en.wikipedia.org/wiki/Rounding#Rounding_to_integer
int TestRound()
{
  int status = 0;
  std::cout << "Round..";
  int result;
  {
  std::vector<float> values;
  std::vector<int> expecteds;

  values.push_back(23.67f); expecteds.push_back(24);
  values.push_back(23.50f); expecteds.push_back(24);
  values.push_back(23.35f); expecteds.push_back(23);
  values.push_back(23.00f); expecteds.push_back(23);
  values.push_back(0.00f); expecteds.push_back(  0);
  values.push_back(-23.00f); expecteds.push_back(-23);
  values.push_back(-23.35f); expecteds.push_back(-23);
  values.push_back(-23.50f); expecteds.push_back(-24);
  values.push_back(-23.67f); expecteds.push_back(-24);
  for ( size_t i = 0; i < values.size(); ++i)
327
  {
Bill Lorensen's avatar
Bill Lorensen committed
328 329
    result = vtkMath::Round(values[i]);
    if (result != expecteds[i])
330
    {
Bill Lorensen's avatar
Bill Lorensen committed
331 332 333 334 335
      std::cout << " Float Round(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
  }
336
  }
Bill Lorensen's avatar
Bill Lorensen committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350
  {
  std::vector<double> values;
  std::vector<int> expecteds;

  values.push_back(23.67); expecteds.push_back(24);
  values.push_back(23.50); expecteds.push_back(24);
  values.push_back(23.35); expecteds.push_back(23);
  values.push_back(23.00); expecteds.push_back(23);
  values.push_back(0.00); expecteds.push_back(  0);
  values.push_back(-23.00); expecteds.push_back(-23);
  values.push_back(-23.35); expecteds.push_back(-23);
  values.push_back(-23.50); expecteds.push_back(-24);
  values.push_back(-23.67); expecteds.push_back(-24);
  for ( size_t i = 0; i < values.size(); ++i)
351
  {
Bill Lorensen's avatar
Bill Lorensen committed
352 353
    result = vtkMath::Round(values[i]);
    if (result != expecteds[i])
354
    {
Bill Lorensen's avatar
Bill Lorensen committed
355 356 357 358 359
      std::cout << " Double Round(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
  }
360
  }
Bill Lorensen's avatar
Bill Lorensen committed
361
  if (status)
362
  {
Bill Lorensen's avatar
Bill Lorensen committed
363
    std::cout << "..FAILED" << std::endl;
364
  }
Bill Lorensen's avatar
Bill Lorensen committed
365
  else
366
  {
Bill Lorensen's avatar
Bill Lorensen committed
367
    std::cout << ".PASSED" << std::endl;
368
  }
Bill Lorensen's avatar
Bill Lorensen committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
  return status;
}

// Validate with http://en.wikipedia.org/wiki/Floor_and_ceiling_functions
int TestFloor()
{
  int status = 0;
  std::cout << "Floor..";

  int result;
  std::vector<double> values;
  std::vector<int> expecteds;

  values.push_back(2.4); expecteds.push_back(2);
  values.push_back(2.7); expecteds.push_back(2);
  values.push_back(-2.7); expecteds.push_back(-3);
  values.push_back(-2.0); expecteds.push_back(-2);
  for ( size_t i = 0; i < values.size(); ++i)
387
  {
Bill Lorensen's avatar
Bill Lorensen committed
388 389
    result = vtkMath::Floor(values[i]);
    if (result != expecteds[i])
390
    {
Bill Lorensen's avatar
Bill Lorensen committed
391 392 393 394
      std::cout << " Floor(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
395
  }
Bill Lorensen's avatar
Bill Lorensen committed
396
  if (status)
397
  {
Bill Lorensen's avatar
Bill Lorensen committed
398
    std::cout << "..FAILED" << std::endl;
399
  }
Bill Lorensen's avatar
Bill Lorensen committed
400
  else
401
  {
Bill Lorensen's avatar
Bill Lorensen committed
402
    std::cout << ".PASSED" << std::endl;
403
  }
Bill Lorensen's avatar
Bill Lorensen committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  return status;
}

// Validate with http://en.wikipedia.org/wiki/Floor_and_ceiling_functions
int TestCeil()
{
  int status = 0;
  std::cout << "Ceil..";

  int result;
  std::vector<double> values;
  std::vector<int> expecteds;

  values.push_back(2.4); expecteds.push_back(3);
  values.push_back(2.7); expecteds.push_back(3);
  values.push_back(-2.7); expecteds.push_back(-2);
  values.push_back(-2.0); expecteds.push_back(-2);
  for ( size_t i = 0; i < values.size(); ++i)
422
  {
Bill Lorensen's avatar
Bill Lorensen committed
423 424
    result = vtkMath::Ceil(values[i]);
    if (result != expecteds[i])
425
    {
Bill Lorensen's avatar
Bill Lorensen committed
426 427 428 429
      std::cout << " Ceil(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
430
  }
Bill Lorensen's avatar
Bill Lorensen committed
431
  if (status)
432
  {
Bill Lorensen's avatar
Bill Lorensen committed
433
    std::cout << "..FAILED" << std::endl;
434
  }
Bill Lorensen's avatar
Bill Lorensen committed
435
  else
436
  {
Bill Lorensen's avatar
Bill Lorensen committed
437
    std::cout << ".PASSED" << std::endl;
438
  }
Bill Lorensen's avatar
Bill Lorensen committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452
  return status;
}

// Validate by powers of 2 perturbations
int TestCeilLog2()
{
  int status = 0;
  std::cout << "CeilLog2..";

  int result;
  std::vector<vtkTypeUInt64> values;
  std::vector<int> expecteds;

  for ( unsigned int p = 0; p < 30; ++p)
453
  {
Bill Lorensen's avatar
Bill Lorensen committed
454 455 456 457
    vtkTypeUInt64 shifted = (2 << p) + 1;
    values.push_back(shifted); expecteds.push_back(p + 2);
    shifted = (2 << p);
    values.push_back(shifted); expecteds.push_back(p + 1);
458
  }
Bill Lorensen's avatar
Bill Lorensen committed
459
  for ( size_t i = 0; i < values.size(); ++i)
460
  {
Bill Lorensen's avatar
Bill Lorensen committed
461 462
    result = vtkMath::CeilLog2(values[i]);
    if (result != expecteds[i])
463
    {
Bill Lorensen's avatar
Bill Lorensen committed
464 465 466 467
      std::cout << " CeilLog2(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
468
  }
Bill Lorensen's avatar
Bill Lorensen committed
469 470

  if (status)
471
  {
Bill Lorensen's avatar
Bill Lorensen committed
472
    std::cout << "..FAILED" << std::endl;
473
  }
Bill Lorensen's avatar
Bill Lorensen committed
474
  else
475
  {
Bill Lorensen's avatar
Bill Lorensen committed
476
    std::cout << ".PASSED" << std::endl;
477
  }
Bill Lorensen's avatar
Bill Lorensen committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
  return status;
}

// Validate by powers of 2 perturbations
int TestIsPowerOfTwo()
{
  int status = 0;
  std::cout << "IsPowerOfTwo..";
  bool result;

  std::vector<vtkTypeUInt64> values;
  std::vector<bool> expecteds;
  int largestPower = std::numeric_limits<vtkTypeUInt64>::digits;
  vtkTypeUInt64 shifted = 1;
  for ( int p = 1; p < largestPower - 1; ++p)
493
  {
Bill Lorensen's avatar
Bill Lorensen committed
494 495 496
    shifted *= 2;
    values.push_back(shifted); expecteds.push_back(true);
    if (shifted != 2)
497
    {
Bill Lorensen's avatar
Bill Lorensen committed
498
      values.push_back(shifted - 1); expecteds.push_back(false);
499
    }
Bill Lorensen's avatar
Bill Lorensen committed
500
    if (shifted < std::numeric_limits<vtkTypeUInt64>::max() - 1)
501
    {
Bill Lorensen's avatar
Bill Lorensen committed
502 503
      values.push_back(shifted + 1); expecteds.push_back(false);
    }
504
  }
Bill Lorensen's avatar
Bill Lorensen committed
505
  for ( size_t i = 0; i < values.size(); ++i)
506
  {
Bill Lorensen's avatar
Bill Lorensen committed
507 508
    result = vtkMath::IsPowerOfTwo(values[i]);
    if (result != expecteds[i])
509
    {
Bill Lorensen's avatar
Bill Lorensen committed
510 511 512 513
      std::cout << " IsPowerOfTwo(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
514
  }
Bill Lorensen's avatar
Bill Lorensen committed
515 516

  if (status)
517
  {
Bill Lorensen's avatar
Bill Lorensen committed
518
    std::cout << "..FAILED" << std::endl;
519
  }
Bill Lorensen's avatar
Bill Lorensen committed
520
  else
521
  {
Bill Lorensen's avatar
Bill Lorensen committed
522
    std::cout << ".PASSED" << std::endl;
523
  }
Bill Lorensen's avatar
Bill Lorensen committed
524 525 526 527 528 529 530 531 532
  return status;
}

// Validate by powers of 2 perturbations
int TestNearestPowerOfTwo()
{
  int status = 0;
  std::cout << "NearestPowerOfTwo..";

Bill Lorensen's avatar
Bill Lorensen committed
533
  std::vector<vtkTypeUInt64> values;
Bill Lorensen's avatar
Bill Lorensen committed
534 535
  std::vector<int> expecteds;
  int largestPower = std::numeric_limits<int>::digits;
Bill Lorensen's avatar
Bill Lorensen committed
536
  vtkTypeUInt64 shifted = 1;
Bill Lorensen's avatar
Bill Lorensen committed
537
  for ( int p = 1; p < largestPower; ++p)
538
  {
Bill Lorensen's avatar
Bill Lorensen committed
539 540 541 542
    shifted *= 2;
    values.push_back(shifted); expecteds.push_back(shifted);
    values.push_back(shifted + 1); expecteds.push_back(shifted * 2);
    if (shifted !=2 )
543
    {
Bill Lorensen's avatar
Bill Lorensen committed
544 545
      values.push_back(shifted - 1); expecteds.push_back(shifted);
    }
546
  }
Bill Lorensen's avatar
Bill Lorensen committed
547
  for ( size_t i = 0; i < values.size(); ++i)
548
  {
Bill Lorensen's avatar
Bill Lorensen committed
549 550
    int result = vtkMath::NearestPowerOfTwo(values[i]);
    if (result != expecteds[i])
551
    {
Bill Lorensen's avatar
Bill Lorensen committed
552 553 554 555
      std::cout << " NearestPowerOfTwo(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
556
  }
Bill Lorensen's avatar
Bill Lorensen committed
557 558

  if (status)
559
  {
Bill Lorensen's avatar
Bill Lorensen committed
560
    std::cout << "..FAILED" << std::endl;
561
  }
Bill Lorensen's avatar
Bill Lorensen committed
562
  else
563
  {
Bill Lorensen's avatar
Bill Lorensen committed
564
    std::cout << ".PASSED" << std::endl;
565
  }
Bill Lorensen's avatar
Bill Lorensen committed
566 567 568 569 570 571 572 573 574 575 576 577 578
  return status;
}

// Validate by alternate computation
int TestFactorial()
{
  int status = 0;
  std::cout << "Factorial..";

  std::vector<int> values;
  std::vector<vtkTypeInt64> expecteds;
  vtkTypeInt64 expected = 1;
  for ( int f = 2; f < 10; ++f)
579
  {
Bill Lorensen's avatar
Bill Lorensen committed
580 581
    expected *= f;
    values.push_back(f); expecteds.push_back(expected);
582
  }
Bill Lorensen's avatar
Bill Lorensen committed
583
  for ( size_t i = 0; i < values.size(); ++i)
584
  {
Bill Lorensen's avatar
Bill Lorensen committed
585 586
    int result = vtkMath::Factorial(values[i]);
    if (result != expecteds[i])
587
    {
Bill Lorensen's avatar
Bill Lorensen committed
588 589 590 591
      std::cout << " Factorial(" << values[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
592
  }
Bill Lorensen's avatar
Bill Lorensen committed
593 594

  if (status)
595
  {
Bill Lorensen's avatar
Bill Lorensen committed
596
    std::cout << "..FAILED" << std::endl;
597
  }
Bill Lorensen's avatar
Bill Lorensen committed
598
  else
599
  {
Bill Lorensen's avatar
Bill Lorensen committed
600
    std::cout << ".PASSED" << std::endl;
601
  }
Bill Lorensen's avatar
Bill Lorensen committed
602 603 604 605 606 607 608
  return status;
}

// Validate by alternative computations
int TestBinomial()
{
  int status = 0;
609 610
  int m;
  int n;
Bill Lorensen's avatar
Bill Lorensen committed
611 612 613 614 615 616
  std::cout << "Binomial..";

  std::vector<int> mvalues;
  std::vector<int> nvalues;

  std::vector<vtkTypeInt64> expecteds;
617
  double expected;
618
  for (m = 1; m < 31; ++m)
619
  {
620
    for (n = 1; n <= m; ++n)
621
    {
Bill Lorensen's avatar
Bill Lorensen committed
622 623 624 625
      mvalues.push_back(m);
      nvalues.push_back(n);
      expected = 1;
      for (int i = 1; i <= n; ++i)
626
      {
Bill Lorensen's avatar
Bill Lorensen committed
627 628
        expected *= static_cast<double>(m - i + 1) / i;
      }
629
      expecteds.push_back(static_cast<vtkTypeInt64>(expected));
Bill Lorensen's avatar
Bill Lorensen committed
630
    }
631
  }
Bill Lorensen's avatar
Bill Lorensen committed
632 633

  for ( size_t i = 0; i < mvalues.size(); ++i)
634
  {
Bill Lorensen's avatar
Bill Lorensen committed
635 636
    int result = vtkMath::Binomial(mvalues[i], nvalues[i]);
    if (result != expecteds[i])
637
    {
Bill Lorensen's avatar
Bill Lorensen committed
638 639 640 641 642
      std::cout << " Binomial("
                << mvalues[i] << ", " << nvalues[i] << ") got " << result
                << " but expected " << expecteds[i];
      ++status;
    }
643
  }
Bill Lorensen's avatar
Bill Lorensen committed
644 645

  // Now test the combination iterator
646 647
  m = 6;
  n = 3;
Bill Lorensen's avatar
Bill Lorensen committed
648 649 650 651 652
  int more = 1;
  int count = 0;
  int *comb;
  // First, m < n should produce 0
  comb = vtkMath::BeginCombination(n, m);
653
  if (comb != nullptr)
654
  {
Bill Lorensen's avatar
Bill Lorensen committed
655 656 657 658
    ++status;
    std::cout << " Combinations("
              << n << ", " << m << ") should return 0 "
                << " but got " << comb;
659
  }
Bill Lorensen's avatar
Bill Lorensen committed
660 661
  comb =  vtkMath::BeginCombination(m, n);
  while (more)
662
  {
Bill Lorensen's avatar
Bill Lorensen committed
663 664
    ++count;
    more = vtkMath::NextCombination (m, n, comb);
665
  }
Bill Lorensen's avatar
Bill Lorensen committed
666 667
  vtkMath::FreeCombination(comb);
  if (count != vtkMath::Binomial(m, n))
668
  {
Bill Lorensen's avatar
Bill Lorensen committed
669 670 671 672
    ++status;
    std::cout << " Combinations("
              << m << ", " << n << ") got " << count
                << " but expected " << vtkMath::Binomial(m, n);
673
  }
Bill Lorensen's avatar
Bill Lorensen committed
674
  if (status)
675
  {
Bill Lorensen's avatar
Bill Lorensen committed
676
    std::cout << "..FAILED" << std::endl;
677
  }
Bill Lorensen's avatar
Bill Lorensen committed
678
  else
679
  {
Bill Lorensen's avatar
Bill Lorensen committed
680
    std::cout << ".PASSED" << std::endl;
681
  }
Bill Lorensen's avatar
Bill Lorensen committed
682 683 684 685 686 687 688 689 690 691 692 693 694 695
  return status;
}

// No validation
int TestRandom()
{
  int status = 0;
  std::cout << "Random..";
  // Not really a test of randomness, just covering code
  int n = 1000;
  vtkMath::RandomSeed(8775070);
  vtkMath::GetSeed(); // just for coverage
  double accum = 0.0;
  for (int i = 0; i < n; ++i)
696
  {
Bill Lorensen's avatar
Bill Lorensen committed
697 698 699
    float random = vtkMath::Random();
    accum += random;
    if ( random < 0.0 || random > 1.0)
700
    {
Bill Lorensen's avatar
Bill Lorensen committed
701 702
      std::cout << "Random(): " << random <<  " out of range" << std::endl;
      ++status;
703
    }
Bill Lorensen's avatar
Bill Lorensen committed
704 705 706 707 708 709 710 711 712
    random = vtkMath::Gaussian ();
    accum += random;

    random = vtkMath::Gaussian (0.0, 1.0);
    accum += random;

    random = vtkMath::Random (-1000.0, 1000.0);
    accum += random;
    if (random < -1000.0 || random > 1000.0)
713
    {
Bill Lorensen's avatar
Bill Lorensen committed
714 715 716
      std::cout << "Random (-1000.0, 1000.0): " << random <<  " out of range" << std::endl;
      ++status;
    }
717
  }
Bill Lorensen's avatar
Bill Lorensen committed
718
  if (accum == 0.0)
719
  {
Bill Lorensen's avatar
Bill Lorensen committed
720
    ++status;
721
  }
Bill Lorensen's avatar
Bill Lorensen committed
722
  if (status)
723
  {
Bill Lorensen's avatar
Bill Lorensen committed
724
    std::cout << "..FAILED" << std::endl;
725
  }
Bill Lorensen's avatar
Bill Lorensen committed
726
  else
727
  {
Bill Lorensen's avatar
Bill Lorensen committed
728
    std::cout << ".PASSED" << std::endl;
729
  }
Bill Lorensen's avatar
Bill Lorensen committed
730 731 732 733 734 735 736 737 738
  return status;
}

template<typename T>
int AddSubtract()
{
  int status = 0;
  T da[3], db[3], dc[3], dd[3];
  for (int n = 0; n < 100000; ++n)
739
  {
Bill Lorensen's avatar
Bill Lorensen committed
740
    for (int i = 0; i < 3; ++i)
741
    {
Bill Lorensen's avatar
Bill Lorensen committed
742 743
      da[i] = vtkMath::Random(-10.0, 10.0);
      db[i] = vtkMath::Random(-10.0, 10.0);
744
    }
Bill Lorensen's avatar
Bill Lorensen committed
745 746 747
    vtkMath::Add(da, db, dc);
    vtkMath::Subtract(dc, db, dd);
    for (int i = 0; i < 3; ++i)
748
    {
Bill Lorensen's avatar
Bill Lorensen committed
749 750 751
      if (!vtkMathUtilities::FuzzyCompare(
            da[i], dd[i],
            std::numeric_limits<T>::epsilon() * (T) 256.0))
752
      {
Bill Lorensen's avatar
Bill Lorensen committed
753 754 755 756
        std::cout << " Add/Subtract got " << dd[i]
                  << " but expected " << da[i];
      }
    }
757
  }
Bill Lorensen's avatar
Bill Lorensen committed
758 759 760 761 762 763 764 765 766 767 768 769 770
  return status;
}

// Validate by a + b - b = a
int TestAddSubtract()
{
  int status = 0;
  std::cout << "AddSubtract..";

  status += AddSubtract<double>();
  status += AddSubtract<float>();

  if (status)
771
  {
Bill Lorensen's avatar
Bill Lorensen committed
772
    std::cout << "..FAILED" << std::endl;
773
  }
Bill Lorensen's avatar
Bill Lorensen committed
774
  else
775
  {
Bill Lorensen's avatar
Bill Lorensen committed
776
    std::cout << ".PASSED" << std::endl;
777
  }
Bill Lorensen's avatar
Bill Lorensen committed
778 779 780 781 782 783 784 785 786 787
  return status;
}

template<typename T>
int MultiplyScalar()
{
  int status = 0;
  // first T
  T da[3], db[3];
  for (int n = 0; n < 100000; ++n)
788
  {
Bill Lorensen's avatar
Bill Lorensen committed
789
    for (int i = 0; i < 3; ++i)
790
    {
Bill Lorensen's avatar
Bill Lorensen committed
791 792
      da[i] = vtkMath::Random(-10.0, 10.0);
      db[i] = da[i];
793
    }
Bill Lorensen's avatar
Bill Lorensen committed
794 795 796 797
    T scale = vtkMath::Random();
    vtkMath::MultiplyScalar(da, scale);

    for (int i = 0; i < 3; ++i)
798
    {
Bill Lorensen's avatar
Bill Lorensen committed
799 800 801
      if (!vtkMathUtilities::FuzzyCompare(
            da[i], db[i] * scale,
            std::numeric_limits<T>::epsilon() * (T) 256.0))
802
      {
Bill Lorensen's avatar
Bill Lorensen committed
803 804 805 806
        std::cout << " MultiplyScalar got " << da[i]
                  << " but expected " << db[i] * scale;
      }
    }
807
  }
Bill Lorensen's avatar
Bill Lorensen committed
808 809 810 811 812 813 814 815 816 817 818 819 820

  return status;
}

int TestMultiplyScalar()
{
  int status = 0;
  std::cout << "MultiplyScalar..";

  status += MultiplyScalar<double>();
  status += MultiplyScalar<float>();

  if (status)
821
  {
Bill Lorensen's avatar
Bill Lorensen committed
822
    std::cout << "..FAILED" << std::endl;
823
  }
Bill Lorensen's avatar
Bill Lorensen committed
824
  else
825
  {
Bill Lorensen's avatar
Bill Lorensen committed
826
    std::cout << ".PASSED" << std::endl;
827
  }
Bill Lorensen's avatar
Bill Lorensen committed
828 829 830 831 832 833 834 835 836 837 838 839
  return status;
}

int TestMultiplyScalar2D()
{
  int status = 0;
  std::cout << "MultiplyScalar2D..";

  // now 2D
  // first double
  double da[2], db[2];
  for (int n = 0; n < 100000; ++n)
840
  {
Bill Lorensen's avatar
Bill Lorensen committed
841
    for (int i = 0; i < 2; ++i)
842
    {
Bill Lorensen's avatar
Bill Lorensen committed
843 844
      da[i] = vtkMath::Random(-10.0, 10.0);
      db[i] = da[i];
845
    }
Bill Lorensen's avatar
Bill Lorensen committed
846 847 848 849
    double scale = vtkMath::Random();
    vtkMath::MultiplyScalar2D(da, scale);

    for (int i = 0; i < 2; ++i)
850
    {
Bill Lorensen's avatar
Bill Lorensen committed
851 852 853
      if (!vtkMathUtilities::FuzzyCompare(
            da[i], db[i] * scale,
            std::numeric_limits<double>::epsilon() * 256.0))
854
      {
Bill Lorensen's avatar
Bill Lorensen committed
855 856 857 858
        std::cout << " MultiplyScalar2D got " << da[i]
                  << " but expected " << db[i] * scale;
      }
    }
859
  }
Bill Lorensen's avatar
Bill Lorensen committed
860 861 862 863

  // then float
  float fa[2], fb[2];
  for (int n = 0; n < 100000; ++n)
864
  {
Bill Lorensen's avatar
Bill Lorensen committed
865
    for (int i = 0; i < 2; ++i)
866
    {
Bill Lorensen's avatar
Bill Lorensen committed
867 868
      fa[i] = vtkMath::Random(-10.0, 10.0);
      fb[i] = fa[i];
869
    }
Bill Lorensen's avatar
Bill Lorensen committed
870 871 872 873
    float scale = vtkMath::Random();
    vtkMath::MultiplyScalar2D(fa, scale);

    for (int i = 0; i < 2; ++i)
874
    {
Bill Lorensen's avatar
Bill Lorensen committed
875 876 877
      if (!vtkMathUtilities::FuzzyCompare(
            fa[i], fb[i] * scale,
            std::numeric_limits<float>::epsilon() * 256.0f))
878
      {
Bill Lorensen's avatar
Bill Lorensen committed
879 880 881 882
        std::cout << " MultiplyScalar2D got " << fa[i]
                  << " but expected " << fb[i] * scale;
      }
    }
883
  }
Bill Lorensen's avatar
Bill Lorensen committed
884 885

  if (status)
886
  {
Bill Lorensen's avatar
Bill Lorensen committed
887
    std::cout << "..FAILED" << std::endl;
888
  }
Bill Lorensen's avatar
Bill Lorensen committed
889
  else
890
  {
Bill Lorensen's avatar
Bill Lorensen committed
891
    std::cout << ".PASSED" << std::endl;
892
  }
Bill Lorensen's avatar
Bill Lorensen committed
893 894 895 896 897 898
  return status;
}

class valueDouble3D
{
public:
899
  valueDouble3D() = default;
Bill Lorensen's avatar
Bill Lorensen committed
900 901 902
  valueDouble3D(double aa[3], double bb[3])
  {
    for (int i = 0; i < 3; ++i)
903
    {
Bill Lorensen's avatar
Bill Lorensen committed
904 905
      a[i] = aa[i];
      b[i] = bb[i];
906
    }
Bill Lorensen's avatar
Bill Lorensen committed
907 908 909 910 911 912 913 914
  }
  double a[3];
  double b[3];
};

class valueFloat3D
{
public:
915
  valueFloat3D() = default;
Bill Lorensen's avatar
Bill Lorensen committed
916 917 918
  valueFloat3D(float aa[3], float bb[3])
  {
    for (int i = 0; i < 3; ++i)
919
    {
Bill Lorensen's avatar
Bill Lorensen committed
920 921
      a[i] = aa[i];
      b[i] = bb[i];
922
    }
Bill Lorensen's avatar
Bill Lorensen committed
923 924 925 926 927 928 929 930 931 932 933 934 935
  }
  float a[3];
  float b[3];
};
int TestDot()
{
  int status = 0;
  std::cout << "Dot..";

  {
  std::vector<valueDouble3D> values;
  std::vector<double> expecteds;
  for (int n = 0; n < 100; ++n)
936
  {
Bill Lorensen's avatar
Bill Lorensen committed
937 938 939
    valueDouble3D v;
    double dot = 0.0;
    for (int i = 0; i < 3; ++i)
940
    {
Bill Lorensen's avatar
Bill Lorensen committed
941 942 943
      v.a[i] = vtkMath::Random();
      v.b[i] = vtkMath::Random();
      dot += (v.a[i] * v.b[i]);
944
    }
Bill Lorensen's avatar
Bill Lorensen committed
945 946
    values.push_back(v);
    expecteds.push_back(dot);
947
  }
Bill Lorensen's avatar
Bill Lorensen committed
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
  valueDouble3D test;
  test.a[0] = 0.0; test.a[1] = 0.0;   test.a[2] = 1.0;
  test.b[0] = 1.0; test.b[1] = 0.0;   test.b[2] = 0.0;
  values.push_back(test);
  expecteds.push_back(0.0);
  test.a[0] = 0.0; test.a[1] = 0.0;   test.a[2] = 1.0;
  test.b[0] = 0.0;