Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 1 | // Ceres Solver - A fast non-linear least squares minimizer |
| 2 | // Copyright 2010, 2011, 2012 Google Inc. All rights reserved. |
| 3 | // http://code.google.com/p/ceres-solver/ |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are met: |
| 7 | // |
| 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. |
| 16 | // |
| 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. |
| 28 | // |
| 29 | // Author: keir@google.com (Keir Mierle) |
| 30 | |
| 31 | #include "ceres/jet.h" |
| 32 | |
| 33 | #include <algorithm> |
| 34 | #include <cmath> |
| 35 | |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 36 | #include "glog/logging.h" |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 37 | #include "gtest/gtest.h" |
Keir Mierle | 58ede27 | 2012-06-24 17:23:57 -0700 | [diff] [blame] | 38 | #include "ceres/fpclassify.h" |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 39 | #include "ceres/stringprintf.h" |
| 40 | #include "ceres/test_util.h" |
| 41 | |
| 42 | #define VL VLOG(1) |
| 43 | |
| 44 | namespace ceres { |
| 45 | namespace internal { |
| 46 | |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 47 | const double kE = 2.71828182845904523536; |
| 48 | |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 49 | typedef Jet<double, 2> J; |
| 50 | |
| 51 | // Convenient shorthand for making a jet. |
| 52 | J MakeJet(double a, double v0, double v1) { |
| 53 | J z; |
| 54 | z.a = a; |
| 55 | z.v[0] = v0; |
| 56 | z.v[1] = v1; |
| 57 | return z; |
| 58 | } |
| 59 | |
| 60 | // On a 32-bit optimized build, the mismatch is about 1.4e-14. |
| 61 | double const kTolerance = 1e-13; |
| 62 | |
| 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); |
| 67 | } |
| 68 | |
| 69 | TEST(Jet, Jet) { |
| 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); |
| 73 | |
| 74 | VL << "x = " << x; |
| 75 | VL << "y = " << y; |
| 76 | |
| 77 | { // Check that log(exp(x)) == x. |
| 78 | J z = exp(x); |
| 79 | J w = log(z); |
| 80 | VL << "z = " << z; |
| 81 | VL << "w = " << w; |
| 82 | ExpectJetsClose(w, x); |
| 83 | } |
| 84 | |
| 85 | { // Check that (x * y) / x == y. |
| 86 | J z = x * y; |
| 87 | J w = z / x; |
| 88 | VL << "z = " << z; |
| 89 | VL << "w = " << w; |
| 90 | ExpectJetsClose(w, y); |
| 91 | } |
| 92 | |
| 93 | { // Check that sqrt(x * x) == x. |
| 94 | J z = x * x; |
| 95 | J w = sqrt(z); |
| 96 | VL << "z = " << z; |
| 97 | VL << "w = " << w; |
| 98 | ExpectJetsClose(w, x); |
| 99 | } |
| 100 | |
| 101 | { // Check that sqrt(y) * sqrt(y) == y. |
| 102 | J z = sqrt(y); |
| 103 | J w = z * z; |
| 104 | VL << "z = " << z; |
| 105 | VL << "w = " << w; |
| 106 | ExpectJetsClose(w, y); |
| 107 | } |
| 108 | |
| 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); |
| 112 | VL << "z = " << z; |
| 113 | VL << "w = " << w; |
| 114 | ExpectJetsClose(w, z); |
| 115 | } |
| 116 | |
| 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); |
| 120 | VL << "z = " << z; |
| 121 | VL << "w = " << w; |
| 122 | ExpectJetsClose(w, z); |
| 123 | } |
| 124 | |
| 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); |
| 128 | VL << "z = " << z; |
| 129 | VL << "w = " << w; |
| 130 | ExpectJetsClose(z + w, J(1.0)); |
| 131 | } |
| 132 | |
| 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); |
| 136 | VL << "t = " << t; |
| 137 | VL << "r = " << r; |
| 138 | |
| 139 | J u = atan2(r * sin(t), r * cos(t)); |
| 140 | VL << "u = " << u; |
| 141 | |
| 142 | ExpectJetsClose(u, t); |
| 143 | } |
| 144 | |
| 145 | { // Check that pow(x, 1) == x. |
| 146 | VL << "x = " << x; |
| 147 | |
| 148 | J u = pow(x, 1.); |
| 149 | VL << "u = " << u; |
| 150 | |
| 151 | ExpectJetsClose(x, u); |
| 152 | } |
| 153 | |
| 154 | { // Check that pow(x, 1) == x. |
| 155 | J y = MakeJet(1, 0.0, 0.0); |
| 156 | VL << "x = " << x; |
| 157 | VL << "y = " << y; |
| 158 | |
| 159 | J u = pow(x, y); |
| 160 | VL << "u = " << u; |
| 161 | |
| 162 | ExpectJetsClose(x, u); |
| 163 | } |
| 164 | |
| 165 | { // Check that pow(e, log(x)) == x. |
| 166 | J logx = log(x); |
| 167 | |
| 168 | VL << "x = " << x; |
| 169 | VL << "y = " << y; |
| 170 | |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 171 | J u = pow(kE, logx); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 172 | VL << "u = " << u; |
| 173 | |
| 174 | ExpectJetsClose(x, u); |
| 175 | } |
| 176 | |
| 177 | { // Check that pow(e, log(x)) == x. |
| 178 | J logx = log(x); |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 179 | J e = MakeJet(kE, 0., 0.); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 180 | VL << "x = " << x; |
| 181 | VL << "log(x) = " << logx; |
| 182 | |
| 183 | J u = pow(e, logx); |
| 184 | VL << "u = " << u; |
| 185 | |
| 186 | ExpectJetsClose(x, u); |
| 187 | } |
| 188 | |
| 189 | { // Check that pow(e, log(x)) == x. |
| 190 | J logx = log(x); |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 191 | J e = MakeJet(kE, 0., 0.); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 192 | VL << "x = " << x; |
| 193 | VL << "logx = " << logx; |
| 194 | |
| 195 | J u = pow(e, logx); |
| 196 | VL << "u = " << u; |
| 197 | |
| 198 | ExpectJetsClose(x, u); |
| 199 | } |
| 200 | |
| 201 | { // Check that pow(x,y) = exp(y*log(x)). |
| 202 | J logx = log(x); |
Keir Mierle | efe7ac6 | 2012-06-24 22:25:28 -0700 | [diff] [blame] | 203 | J e = MakeJet(kE, 0., 0.); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 204 | VL << "x = " << x; |
| 205 | VL << "logx = " << logx; |
| 206 | |
| 207 | J u = pow(e, y*logx); |
| 208 | J v = pow(x, y); |
| 209 | VL << "u = " << u; |
| 210 | VL << "v = " << v; |
| 211 | |
| 212 | ExpectJetsClose(v, u); |
| 213 | } |
| 214 | |
| 215 | { // Check that 1 + x == x + 1. |
| 216 | J a = x + 1.0; |
| 217 | J b = 1.0 + x; |
| 218 | |
| 219 | ExpectJetsClose(a, b); |
| 220 | } |
| 221 | |
| 222 | { // Check that 1 - x == -(x - 1). |
| 223 | J a = 1.0 - x; |
| 224 | J b = -(x - 1.0); |
| 225 | |
| 226 | ExpectJetsClose(a, b); |
| 227 | } |
| 228 | |
| 229 | { // Check that x/s == x*s. |
| 230 | J a = x / 5.0; |
| 231 | J b = x * 5.0; |
| 232 | |
| 233 | ExpectJetsClose(5.0 * a, b / 5.0); |
| 234 | } |
| 235 | |
| 236 | { // Check that x / y == 1 / (y / x). |
| 237 | J a = x / y; |
| 238 | J b = 1.0 / (y / x); |
| 239 | VL << "a = " << a; |
| 240 | VL << "b = " << b; |
| 241 | |
| 242 | ExpectJetsClose(a, b); |
| 243 | } |
| 244 | |
| 245 | { // Check that abs(-x * x) == sqrt(x * x). |
| 246 | ExpectJetsClose(abs(-x), sqrt(x * x)); |
| 247 | } |
| 248 | |
| 249 | { // Check that cos(acos(x)) == x. |
| 250 | J a = MakeJet(0.1, -2.7, 1e-3); |
| 251 | ExpectJetsClose(cos(acos(a)), a); |
| 252 | ExpectJetsClose(acos(cos(a)), a); |
| 253 | |
| 254 | J b = MakeJet(0.6, 0.5, 1e+2); |
| 255 | ExpectJetsClose(cos(acos(b)), b); |
| 256 | ExpectJetsClose(acos(cos(b)), b); |
| 257 | } |
| 258 | |
| 259 | { // Check that sin(asin(x)) == x. |
| 260 | J a = MakeJet(0.1, -2.7, 1e-3); |
| 261 | ExpectJetsClose(sin(asin(a)), a); |
| 262 | ExpectJetsClose(asin(sin(a)), a); |
| 263 | |
| 264 | J b = MakeJet(0.4, 0.5, 1e+2); |
| 265 | ExpectJetsClose(sin(asin(b)), b); |
| 266 | ExpectJetsClose(asin(sin(b)), b); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | TEST(Jet, JetsInEigenMatrices) { |
| 271 | J x = MakeJet(2.3, -2.7, 1e-3); |
| 272 | J y = MakeJet(1.7, 0.5, 1e+2); |
| 273 | J z = MakeJet(5.3, -4.7, 1e-3); |
| 274 | J w = MakeJet(9.7, 1.5, 10.1); |
| 275 | |
| 276 | Eigen::Matrix<J, 2, 2> M; |
| 277 | Eigen::Matrix<J, 2, 1> v, r1, r2; |
| 278 | |
| 279 | M << x, y, z, w; |
| 280 | v << x, z; |
| 281 | |
| 282 | // Check that M * v == (v^T * M^T)^T |
| 283 | r1 = M * v; |
| 284 | r2 = (v.transpose() * M.transpose()).transpose(); |
| 285 | |
| 286 | ExpectJetsClose(r1(0), r2(0)); |
| 287 | ExpectJetsClose(r1(1), r2(1)); |
| 288 | } |
| 289 | |
| 290 | TEST(JetTraitsTest, ClassificationMixed) { |
| 291 | Jet<double, 3> a(5.5, 0); |
| 292 | a.v[0] = std::numeric_limits<double>::quiet_NaN(); |
| 293 | a.v[1] = std::numeric_limits<double>::infinity(); |
| 294 | a.v[2] = -std::numeric_limits<double>::infinity(); |
Keir Mierle | 58ede27 | 2012-06-24 17:23:57 -0700 | [diff] [blame] | 295 | EXPECT_FALSE(IsFinite(a)); |
| 296 | EXPECT_FALSE(IsNormal(a)); |
| 297 | EXPECT_TRUE(IsInfinite(a)); |
| 298 | EXPECT_TRUE(IsNaN(a)); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | TEST(JetTraitsTest, ClassificationNaN) { |
| 302 | Jet<double, 3> a(5.5, 0); |
| 303 | a.v[0] = std::numeric_limits<double>::quiet_NaN(); |
| 304 | a.v[1] = 0.0; |
| 305 | a.v[2] = 0.0; |
Keir Mierle | 58ede27 | 2012-06-24 17:23:57 -0700 | [diff] [blame] | 306 | EXPECT_FALSE(IsFinite(a)); |
| 307 | EXPECT_FALSE(IsNormal(a)); |
| 308 | EXPECT_FALSE(IsInfinite(a)); |
| 309 | EXPECT_TRUE(IsNaN(a)); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | TEST(JetTraitsTest, ClassificationInf) { |
| 313 | Jet<double, 3> a(5.5, 0); |
| 314 | a.v[0] = std::numeric_limits<double>::infinity(); |
| 315 | a.v[1] = 0.0; |
| 316 | a.v[2] = 0.0; |
Keir Mierle | 58ede27 | 2012-06-24 17:23:57 -0700 | [diff] [blame] | 317 | EXPECT_FALSE(IsFinite(a)); |
| 318 | EXPECT_FALSE(IsNormal(a)); |
| 319 | EXPECT_TRUE(IsInfinite(a)); |
| 320 | EXPECT_FALSE(IsNaN(a)); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 321 | } |
| 322 | |
| 323 | TEST(JetTraitsTest, ClassificationFinite) { |
| 324 | Jet<double, 3> a(5.5, 0); |
| 325 | a.v[0] = 100.0; |
| 326 | a.v[1] = 1.0; |
| 327 | a.v[2] = 3.14159; |
Keir Mierle | 58ede27 | 2012-06-24 17:23:57 -0700 | [diff] [blame] | 328 | EXPECT_TRUE(IsFinite(a)); |
| 329 | EXPECT_TRUE(IsNormal(a)); |
| 330 | EXPECT_FALSE(IsInfinite(a)); |
| 331 | EXPECT_FALSE(IsNaN(a)); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | } // namespace internal |
| 335 | } // namespace ceres |