| // Ceres Solver - A fast non-linear least squares minimizer |
| // Copyright 2020 Google Inc. All rights reserved. |
| // http://code.google.com/p/ceres-solver/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of Google Inc. nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| // POSSIBILITY OF SUCH DAMAGE. |
| // |
| // Author: darius.rueckert@fau.de (Darius Rueckert) |
| // |
| // This file includes unit test functors for every supported expression type. |
| // This is similar to expression_ref_test and codegeneration_test, but for the |
| // complete pipeline including automatic differentation. For each of the structs |
| // below, the Evaluate function is generated using GenerateCodeForFunctor. After |
| // that this function is executed with random parameters. The result of the |
| // residuals and jacobians is then compared to AutoDiff (without code |
| // generation). Of course, the correctness of this module depends on the |
| // correctness of autodiff. |
| // |
| #include <cmath> |
| #include <limits> |
| |
| #include "ceres/codegen/codegen_cost_function.h" |
| namespace test { |
| |
| struct InputOutputAssignment : public ceres::CodegenCostFunction<7, 4, 2, 1> { |
| template <typename T> |
| bool operator()(const T* x0, const T* x1, const T* x2, T* y) const { |
| y[0] = x0[0]; |
| y[1] = x0[1]; |
| y[2] = x0[2]; |
| y[3] = x0[3]; |
| |
| y[4] = x1[0]; |
| y[5] = x1[1]; |
| |
| y[6] = x2[0]; |
| return true; |
| } |
| #include "tests/inputoutputassignment.h" |
| }; |
| |
| struct CompileTimeConstants : public ceres::CodegenCostFunction<7, 1> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| y[0] = T(0); |
| y[1] = T(1); |
| y[2] = T(-1); |
| y[3] = T(1e-10); |
| y[4] = T(1e10); |
| y[5] = T(std::numeric_limits<double>::infinity()); |
| y[6] = T(std::numeric_limits<double>::quiet_NaN()); |
| |
| return true; |
| } |
| #include "tests/compiletimeconstants.h" |
| }; |
| |
| struct Assignments : public ceres::CodegenCostFunction<8, 2> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| T b = x0[1]; |
| y[0] = a; |
| y[1] = b; |
| y[2] = y[3] = a; |
| |
| T c = a; |
| y[4] = c; |
| |
| T d(b); |
| y[5] = d; |
| |
| y[6] = std::move(c); |
| |
| y[7] = std::move(T(T(std::move(T(a))))); |
| return true; |
| } |
| #include "tests/assignments.h" |
| }; |
| |
| struct BinaryArithmetic : public ceres::CodegenCostFunction<9, 2> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| T b = x0[1]; |
| y[0] = a + b; |
| y[1] = a - b; |
| y[2] = a * b; |
| y[3] = a / b; |
| |
| y[4] = a; |
| y[4] += b; |
| y[5] = a; |
| y[5] -= b; |
| y[6] = a; |
| y[6] *= b; |
| y[7] = a; |
| y[7] /= b; |
| |
| y[8] = a + b * a / a - b + b / a; |
| return true; |
| } |
| #include "tests/binaryarithmetic.h" |
| }; |
| |
| struct UnaryArithmetic : public ceres::CodegenCostFunction<3, 1> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| y[0] = -a; |
| y[1] = +a; |
| y[2] = a; |
| return true; |
| } |
| #include "tests/unaryarithmetic.h" |
| }; |
| |
| struct BinaryComparison : public ceres::CodegenCostFunction<12, 2> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| T b = x0[1]; |
| |
| // For each operator we swap the inputs so both branches are evaluated once. |
| CERES_IF(a < b) { y[0] = T(0); } |
| CERES_ELSE { y[0] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b < a) { y[1] = T(0); } |
| CERES_ELSE { y[1] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(a > b) { y[2] = T(0); } |
| CERES_ELSE { y[2] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b > a) { y[3] = T(0); } |
| CERES_ELSE { y[3] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(a <= b) { y[4] = T(0); } |
| CERES_ELSE { y[4] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b <= a) { y[5] = T(0); } |
| CERES_ELSE { y[5] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(a >= b) { y[6] = T(0); } |
| CERES_ELSE { y[6] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b >= a) { y[7] = T(0); } |
| CERES_ELSE { y[7] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(a == b) { y[8] = T(0); } |
| CERES_ELSE { y[8] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b == a) { y[9] = T(0); } |
| CERES_ELSE { y[9] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(a != b) { y[10] = T(0); } |
| CERES_ELSE { y[10] = T(1); } |
| CERES_ENDIF |
| CERES_IF(b != a) { y[11] = T(0); } |
| CERES_ELSE { y[11] = T(1); } |
| CERES_ENDIF |
| |
| return true; |
| } |
| #include "tests/binarycomparison.h" |
| }; |
| |
| struct LogicalOperators : public ceres::CodegenCostFunction<8, 3> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| T b = x0[1]; |
| T c = x0[2]; |
| auto r1 = a < b; |
| auto r2 = a < c; |
| |
| CERES_IF(r1) { y[0] = T(0); } |
| CERES_ELSE { y[0] = T(1); } |
| CERES_ENDIF |
| CERES_IF(r2) { y[1] = T(0); } |
| CERES_ELSE { y[1] = T(1); } |
| CERES_ENDIF |
| CERES_IF(!r1) { y[2] = T(0); } |
| CERES_ELSE { y[2] = T(1); } |
| CERES_ENDIF |
| CERES_IF(!r2) { y[3] = T(0); } |
| CERES_ELSE { y[3] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(r1 && r2) { y[4] = T(0); } |
| CERES_ELSE { y[4] = T(1); } |
| CERES_ENDIF |
| CERES_IF(!r1 && !r2) { y[5] = T(0); } |
| CERES_ELSE { y[5] = T(1); } |
| CERES_ENDIF |
| |
| CERES_IF(r1 || r2) { y[6] = T(0); } |
| CERES_ELSE { y[6] = T(1); } |
| CERES_ENDIF |
| CERES_IF(!r1 || !r2) { y[7] = T(0); } |
| CERES_ELSE { y[7] = T(1); } |
| CERES_ENDIF |
| |
| return true; |
| } |
| #include "tests/logicaloperators.h" |
| }; |
| |
| struct ScalarFunctions : public ceres::CodegenCostFunction<20, 22> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| y[0] = abs(x0[0]); |
| y[1] = acos(x0[1]); |
| y[2] = asin(x0[2]); |
| y[3] = atan(x0[3]); |
| y[4] = cbrt(x0[4]); |
| y[5] = ceil(x0[5]); |
| y[6] = cos(x0[6]); |
| y[7] = cosh(x0[7]); |
| y[8] = exp(x0[8]); |
| y[9] = exp2(x0[9]); |
| y[10] = floor(x0[10]); |
| y[11] = log(x0[11]); |
| y[12] = log2(x0[12]); |
| y[13] = sin(x0[13]); |
| y[14] = sinh(x0[14]); |
| y[15] = sqrt(x0[15]); |
| y[16] = tan(x0[16]); |
| y[17] = tanh(x0[17]); |
| y[18] = atan2(x0[18], x0[19]); |
| y[19] = pow(x0[20], x0[21]); |
| return true; |
| } |
| #include "tests/scalarfunctions.h" |
| }; |
| |
| struct LogicalFunctions : public ceres::CodegenCostFunction<4, 4> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| using std::isfinite; |
| using std::isinf; |
| using std::isnan; |
| using std::isnormal; |
| T a = x0[0]; |
| auto r1 = isfinite(a); |
| auto r2 = isinf(a); |
| auto r3 = isnan(a); |
| auto r4 = isnormal(a); |
| |
| CERES_IF(r1) { y[0] = T(0); } |
| CERES_ELSE { y[0] = T(1); } |
| CERES_ENDIF |
| CERES_IF(r2) { y[1] = T(0); } |
| CERES_ELSE { y[1] = T(1); } |
| CERES_ENDIF |
| CERES_IF(r3) { y[2] = T(0); } |
| CERES_ELSE { y[2] = T(1); } |
| CERES_ENDIF |
| CERES_IF(r4) { y[3] = T(0); } |
| CERES_ELSE { y[3] = T(1); } |
| CERES_ENDIF |
| |
| return true; |
| } |
| #include "tests/logicalfunctions.h" |
| }; |
| |
| struct Branches : public ceres::CodegenCostFunction<4, 3> { |
| template <typename T> |
| bool operator()(const T* x0, T* y) const { |
| T a = x0[0]; |
| T b = x0[1]; |
| T c = x0[2]; |
| auto r1 = a < b; |
| auto r2 = a < c; |
| auto r3 = b < c; |
| |
| // If without else |
| y[0] = T(0); |
| CERES_IF(r1) { y[0] += T(1); } |
| CERES_ENDIF |
| |
| // If else |
| y[1] = T(0); |
| CERES_IF(r1) { y[1] += T(-1); } |
| CERES_ELSE { y[1] += T(1); } |
| CERES_ENDIF |
| |
| // Nested if |
| y[2] = T(0); |
| CERES_IF(r1) { |
| y[2] += T(1); |
| CERES_IF(r2) { |
| y[2] += T(4); |
| CERES_IF(r2) { y[2] += T(8); } |
| CERES_ENDIF |
| } |
| CERES_ENDIF |
| } |
| CERES_ENDIF |
| |
| // Nested if-else |
| y[3] = T(0); |
| CERES_IF(r1) { |
| y[3] += T(1); |
| CERES_IF(r2) { |
| y[3] += T(2); |
| CERES_IF(r3) { y[3] += T(4); } |
| CERES_ELSE { y[3] += T(8); } |
| CERES_ENDIF |
| } |
| CERES_ELSE { |
| y[3] += T(16); |
| CERES_IF(r3) { y[3] += T(32); } |
| CERES_ELSE { y[3] += T(64); } |
| CERES_ENDIF |
| } |
| CERES_ENDIF |
| } |
| CERES_ELSE { |
| y[3] += T(128); |
| CERES_IF(r2) { y[3] += T(256); } |
| CERES_ELSE { y[3] += T(512); } |
| CERES_ENDIF |
| } |
| CERES_ENDIF |
| |
| return true; |
| } |
| #include "tests/branches.h" |
| }; |
| |
| } // namespace test |