1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 // Author: keir@google.com (Keir Mierle)
31 #include "ceres/jet.h"
36 #include "glog/logging.h"
37 #include "gtest/gtest.h"
38 #include "ceres/fpclassify.h"
39 #include "ceres/stringprintf.h"
40 #include "ceres/test_util.h"
47 const double kE = 2.71828182845904523536;
49 typedef Jet<double, 2> J;
51 // Convenient shorthand for making a jet.
52 J MakeJet(double a, double v0, double v1) {
60 // On a 32-bit optimized build, the mismatch is about 1.4e-14.
61 double const kTolerance = 1e-13;
63 void ExpectJetsClose(const J &x, const J &y) {
64 ExpectClose(x.a, y.a, kTolerance);
65 ExpectClose(x.v[0], y.v[0], kTolerance);
66 ExpectClose(x.v[1], y.v[1], kTolerance);
70 // Pick arbitrary values for x and y.
71 J x = MakeJet(2.3, -2.7, 1e-3);
72 J y = MakeJet(1.7, 0.5, 1e+2);
77 { // Check that log(exp(x)) == x.
82 ExpectJetsClose(w, x);
85 { // Check that (x * y) / x == y.
90 ExpectJetsClose(w, y);
93 { // Check that sqrt(x * x) == x.
98 ExpectJetsClose(w, x);
101 { // Check that sqrt(y) * sqrt(y) == y.
106 ExpectJetsClose(w, y);
109 { // Check that cos(2*x) = cos(x)^2 - sin(x)^2
110 J z = cos(J(2.0) * x);
111 J w = cos(x)*cos(x) - sin(x)*sin(x);
114 ExpectJetsClose(w, z);
117 { // Check that sin(2*x) = 2*cos(x)*sin(x)
118 J z = sin(J(2.0) * x);
119 J w = J(2.0)*cos(x)*sin(x);
122 ExpectJetsClose(w, z);
125 { // Check that cos(x)*cos(x) + sin(x)*sin(x) = 1
126 J z = cos(x) * cos(x);
127 J w = sin(x) * sin(x);
130 ExpectJetsClose(z + w, J(1.0));
133 { // Check that atan2(r*sin(t), r*cos(t)) = t.
134 J t = MakeJet(0.7, -0.3, +1.5);
135 J r = MakeJet(2.3, 0.13, -2.4);
139 J u = atan2(r * sin(t), r * cos(t));
142 ExpectJetsClose(u, t);
145 { // Check that tan(x) = sin(x) / cos(x).
147 J w = sin(x) / cos(x);
150 ExpectJetsClose(z, w);
153 { // Check that tan(atan(x)) = x.
158 ExpectJetsClose(z, w);
161 { // Check that cosh(x)*cosh(x) - sinh(x)*sinh(x) = 1
162 J z = cosh(x) * cosh(x);
163 J w = sinh(x) * sinh(x);
166 ExpectJetsClose(z - w, J(1.0));
169 { // Check that tanh(x + y) = (tanh(x) + tanh(y)) / (1 + tanh(x) tanh(y))
171 J w = (tanh(x) + tanh(y)) / (J(1.0) + tanh(x) * tanh(y));
174 ExpectJetsClose(z, w);
177 { // Check that pow(x, 1) == x.
183 ExpectJetsClose(x, u);
186 { // Check that pow(x, 1) == x.
187 J y = MakeJet(1, 0.0, 0.0);
194 ExpectJetsClose(x, u);
197 { // Check that pow(e, log(x)) == x.
206 ExpectJetsClose(x, u);
209 { // Check that pow(e, log(x)) == x.
211 J e = MakeJet(kE, 0., 0.);
213 VL << "log(x) = " << logx;
218 ExpectJetsClose(x, u);
221 { // Check that pow(e, log(x)) == x.
223 J e = MakeJet(kE, 0., 0.);
225 VL << "logx = " << logx;
230 ExpectJetsClose(x, u);
233 { // Check that pow(x,y) = exp(y*log(x)).
235 J e = MakeJet(kE, 0., 0.);
237 VL << "logx = " << logx;
239 J u = pow(e, y*logx);
244 ExpectJetsClose(v, u);
247 { // Check that pow(0, y) == 0 for y > 1, with both arguments Jets.
248 // This tests special case handling inside pow().
249 J a = MakeJet(0, 1, 2);
250 J b = MakeJet(2, 3, 4);
256 ExpectJetsClose(c, MakeJet(0, 0, 0));
259 { // Check that pow(0, y) == 0 for y == 1, with both arguments Jets.
260 // This tests special case handling inside pow().
261 J a = MakeJet(0, 1, 2);
262 J b = MakeJet(1, 3, 4);
268 ExpectJetsClose(c, MakeJet(0, 1, 2));
271 { // Check that pow(0, <1) is not finite, with both arguments Jets.
272 for (int i = 1; i < 10; i++) {
273 J a = MakeJet(0, 1, 2);
274 J b = MakeJet(i*0.1, 3, 4); // b = 0.1 ... 0.9
281 EXPECT_FALSE(IsFinite(c.v[0]));
282 EXPECT_FALSE(IsFinite(c.v[1]));
284 for (int i = -10; i < 0; i++) {
285 J a = MakeJet(0, 1, 2);
286 J b = MakeJet(i*0.1, 3, 4); // b = -1,-0.9 ... -0.1
292 EXPECT_FALSE(IsFinite(c.a));
293 EXPECT_FALSE(IsFinite(c.v[0]));
294 EXPECT_FALSE(IsFinite(c.v[1]));
298 // The special case of 0^0 = 1 defined by the C standard.
299 J a = MakeJet(0, 1, 2);
300 J b = MakeJet(0, 3, 4);
307 EXPECT_FALSE(IsFinite(c.v[0]));
308 EXPECT_FALSE(IsFinite(c.v[1]));
312 { // Check that pow(<0, b) is correct for integer b.
313 // This tests special case handling inside pow().
314 J a = MakeJet(-1.5, 3, 4);
317 for (int i = -10; i <= 10; i++) {
318 J b = MakeJet(i, 0, 5);
324 ExpectClose(c.a, pow(-1.5, i), kTolerance);
325 EXPECT_TRUE(IsFinite(c.v[0]));
326 EXPECT_FALSE(IsFinite(c.v[1]));
327 ExpectClose(c.v[0], i * pow(-1.5, i - 1) * 3.0, kTolerance);
331 { // Check that pow(<0, b) is correct for noninteger b.
332 // This tests special case handling inside pow().
333 J a = MakeJet(-1.5, 3, 4);
334 J b = MakeJet(-2.5, 0, 5);
340 EXPECT_FALSE(IsFinite(c.a));
341 EXPECT_FALSE(IsFinite(c.v[0]));
342 EXPECT_FALSE(IsFinite(c.v[1]));
346 // Check that pow(0,y) == 0 for y == 2, with the second argument a
347 // Jet. This tests special case handling inside pow().
349 J b = MakeJet(2, 3, 4);
355 ExpectJetsClose(c, MakeJet(0, 0, 0));
359 // Check that pow(<0,y) is correct for integer y. This tests special case
360 // handling inside pow().
362 for (int i = -10; i <= 10; i++) {
363 J b = MakeJet(i, 3, 0);
369 ExpectClose(c.a, pow(-1.5, i), kTolerance);
370 EXPECT_FALSE(IsFinite(c.v[0]));
371 EXPECT_TRUE(IsFinite(c.v[1]));
372 ExpectClose(c.v[1], 0, kTolerance);
377 // Check that pow(<0,y) is correct for noninteger y. This tests special
378 // case handling inside pow().
380 J b = MakeJet(-3.14, 3, 0);
386 EXPECT_FALSE(IsFinite(c.a));
387 EXPECT_FALSE(IsFinite(c.v[0]));
388 EXPECT_FALSE(IsFinite(c.v[1]));
391 { // Check that 1 + x == x + 1.
397 ExpectJetsClose(a, b);
398 ExpectJetsClose(a, c);
401 { // Check that 1 - x == -(x - 1).
407 ExpectJetsClose(a, b);
408 ExpectJetsClose(a, -c);
411 { // Check that (x/s)*s == (x*s)/s.
419 ExpectJetsClose(5.0 * a, b / 5.0);
420 ExpectJetsClose(a, c);
421 ExpectJetsClose(b, d);
424 { // Check that x / y == 1 / (y / x).
430 ExpectJetsClose(a, b);
433 { // Check that abs(-x * x) == sqrt(x * x).
434 ExpectJetsClose(abs(-x), sqrt(x * x));
437 { // Check that cos(acos(x)) == x.
438 J a = MakeJet(0.1, -2.7, 1e-3);
439 ExpectJetsClose(cos(acos(a)), a);
440 ExpectJetsClose(acos(cos(a)), a);
442 J b = MakeJet(0.6, 0.5, 1e+2);
443 ExpectJetsClose(cos(acos(b)), b);
444 ExpectJetsClose(acos(cos(b)), b);
447 { // Check that sin(asin(x)) == x.
448 J a = MakeJet(0.1, -2.7, 1e-3);
449 ExpectJetsClose(sin(asin(a)), a);
450 ExpectJetsClose(asin(sin(a)), a);
452 J b = MakeJet(0.4, 0.5, 1e+2);
453 ExpectJetsClose(sin(asin(b)), b);
454 ExpectJetsClose(asin(sin(b)), b);
460 // Check that J0(0) == 1.
461 ExpectJetsClose(BesselJ0(zero), J(1.0));
463 // Check that J1(0) == 0.
464 ExpectJetsClose(BesselJ1(zero), zero);
466 // Check that J2(0) == 0.
467 ExpectJetsClose(BesselJn(2, zero), zero);
469 // Check that J3(0) == 0.
470 ExpectJetsClose(BesselJn(3, zero), zero);
472 J z = MakeJet(0.1, -2.7, 1e-3);
474 // Check that J0(z) == Jn(0,z).
475 ExpectJetsClose(BesselJ0(z), BesselJn(0, z));
477 // Check that J1(z) == Jn(1,z).
478 ExpectJetsClose(BesselJ1(z), BesselJn(1, z));
480 // Check that J0(z)+J2(z) == (2/z)*J1(z).
481 // See formula http://dlmf.nist.gov/10.6.E1
482 ExpectJetsClose(BesselJ0(z) + BesselJn(2, z), (2.0 / z) * BesselJ1(z));
485 { // Check that floor of a positive number works.
486 J a = MakeJet(0.1, -2.7, 1e-3);
488 J expected = MakeJet(floor(a.a), 0.0, 0.0);
489 EXPECT_EQ(expected, b);
492 { // Check that floor of a negative number works.
493 J a = MakeJet(-1.1, -2.7, 1e-3);
495 J expected = MakeJet(floor(a.a), 0.0, 0.0);
496 EXPECT_EQ(expected, b);
499 { // Check that floor of a positive number works.
500 J a = MakeJet(10.123, -2.7, 1e-3);
502 J expected = MakeJet(floor(a.a), 0.0, 0.0);
503 EXPECT_EQ(expected, b);
506 { // Check that ceil of a positive number works.
507 J a = MakeJet(0.1, -2.7, 1e-3);
509 J expected = MakeJet(ceil(a.a), 0.0, 0.0);
510 EXPECT_EQ(expected, b);
513 { // Check that ceil of a negative number works.
514 J a = MakeJet(-1.1, -2.7, 1e-3);
516 J expected = MakeJet(ceil(a.a), 0.0, 0.0);
517 EXPECT_EQ(expected, b);
520 { // Check that ceil of a positive number works.
521 J a = MakeJet(10.123, -2.7, 1e-3);
523 J expected = MakeJet(ceil(a.a), 0.0, 0.0);
524 EXPECT_EQ(expected, b);
528 TEST(Jet, JetsInEigenMatrices) {
529 J x = MakeJet(2.3, -2.7, 1e-3);
530 J y = MakeJet(1.7, 0.5, 1e+2);
531 J z = MakeJet(5.3, -4.7, 1e-3);
532 J w = MakeJet(9.7, 1.5, 10.1);
534 Eigen::Matrix<J, 2, 2> M;
535 Eigen::Matrix<J, 2, 1> v, r1, r2;
540 // Check that M * v == (v^T * M^T)^T
542 r2 = (v.transpose() * M.transpose()).transpose();
544 ExpectJetsClose(r1(0), r2(0));
545 ExpectJetsClose(r1(1), r2(1));
548 TEST(JetTraitsTest, ClassificationMixed) {
549 Jet<double, 3> a(5.5, 0);
550 a.v[0] = std::numeric_limits<double>::quiet_NaN();
551 a.v[1] = std::numeric_limits<double>::infinity();
552 a.v[2] = -std::numeric_limits<double>::infinity();
553 EXPECT_FALSE(IsFinite(a));
554 EXPECT_FALSE(IsNormal(a));
555 EXPECT_TRUE(IsInfinite(a));
556 EXPECT_TRUE(IsNaN(a));
559 TEST(JetTraitsTest, ClassificationNaN) {
560 Jet<double, 3> a(5.5, 0);
561 a.v[0] = std::numeric_limits<double>::quiet_NaN();
564 EXPECT_FALSE(IsFinite(a));
565 EXPECT_FALSE(IsNormal(a));
566 EXPECT_FALSE(IsInfinite(a));
567 EXPECT_TRUE(IsNaN(a));
570 TEST(JetTraitsTest, ClassificationInf) {
571 Jet<double, 3> a(5.5, 0);
572 a.v[0] = std::numeric_limits<double>::infinity();
575 EXPECT_FALSE(IsFinite(a));
576 EXPECT_FALSE(IsNormal(a));
577 EXPECT_TRUE(IsInfinite(a));
578 EXPECT_FALSE(IsNaN(a));
581 TEST(JetTraitsTest, ClassificationFinite) {
582 Jet<double, 3> a(5.5, 0);
586 EXPECT_TRUE(IsFinite(a));
587 EXPECT_TRUE(IsNormal(a));
588 EXPECT_FALSE(IsInfinite(a));
589 EXPECT_FALSE(IsNaN(a));
592 // ScalarBinaryOpTraits is only supported on Eigen versions >= 3.3
593 #if EIGEN_VERSION_AT_LEAST(3, 3, 0)
594 TEST(JetTraitsTest, MatrixScalarUnaryOps) {
595 const J x = MakeJet(2.3, -2.7, 1e-3);
596 const J y = MakeJet(1.7, 0.5, 1e+2);
597 Eigen::Matrix<J, 2, 1> a;
600 const J sum = a.sum();
601 const J sum2 = a(0) + a(1);
602 ExpectJetsClose(sum, sum2);
605 TEST(JetTraitsTest, MatrixScalarBinaryOps) {
606 const J x = MakeJet(2.3, -2.7, 1e-3);
607 const J y = MakeJet(1.7, 0.5, 1e+2);
608 const J z = MakeJet(5.3, -4.7, 1e-3);
609 const J w = MakeJet(9.7, 1.5, 10.1);
611 Eigen::Matrix<J, 2, 2> M;
617 // Check that M * v == M * v.cast<J>().
618 const Eigen::Matrix<J, 2, 1> r1 = M * v;
619 const Eigen::Matrix<J, 2, 1> r2 = M * v.cast<J>();
621 ExpectJetsClose(r1(0), r2(0));
622 ExpectJetsClose(r1(1), r2(1));
624 // Check that M * a == M * T(a).
625 const double a = 3.1;
626 const Eigen::Matrix<J, 2, 2> r3 = M * a;
627 const Eigen::Matrix<J, 2, 2> r4 = M * J(a);
629 ExpectJetsClose(r3(0, 0), r4(0, 0));
630 ExpectJetsClose(r3(1, 0), r4(1, 0));
631 ExpectJetsClose(r3(0, 1), r4(0, 1));
632 ExpectJetsClose(r3(1, 1), r4(1, 1));
635 TEST(JetTraitsTest, ArrayScalarUnaryOps) {
636 const J x = MakeJet(2.3, -2.7, 1e-3);
637 const J y = MakeJet(1.7, 0.5, 1e+2);
638 Eigen::Array<J, 2, 1> a;
641 const J sum = a.sum();
642 const J sum2 = a(0) + a(1);
643 ExpectJetsClose(sum, sum2);
646 TEST(JetTraitsTest, ArrayScalarBinaryOps) {
647 const J x = MakeJet(2.3, -2.7, 1e-3);
648 const J y = MakeJet(1.7, 0.5, 1e+2);
650 Eigen::Array<J, 2, 1> a;
656 // Check that a * b == a * b.cast<T>()
657 const Eigen::Array<J, 2, 1> r1 = a * b;
658 const Eigen::Array<J, 2, 1> r2 = a * b.cast<J>();
660 ExpectJetsClose(r1(0), r2(0));
661 ExpectJetsClose(r1(1), r2(1));
663 // Check that a * c == a * T(c).
664 const double c = 3.1;
665 const Eigen::Array<J, 2, 1> r3 = a * c;
666 const Eigen::Array<J, 2, 1> r4 = a * J(c);
668 ExpectJetsClose(r3(0), r3(0));
669 ExpectJetsClose(r4(1), r4(1));
671 #endif // EIGEN_VERSION_AT_LEAST(3, 3, 0)
673 } // namespace internal