Blame internal/ceres/residual_block_utils_test.cc

Packit ea1746
// Ceres Solver - A fast non-linear least squares minimizer
Packit ea1746
// Copyright 2015 Google Inc. All rights reserved.
Packit ea1746
// http://ceres-solver.org/
Packit ea1746
//
Packit ea1746
// Redistribution and use in source and binary forms, with or without
Packit ea1746
// modification, are permitted provided that the following conditions are met:
Packit ea1746
//
Packit ea1746
// * Redistributions of source code must retain the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer.
Packit ea1746
// * Redistributions in binary form must reproduce the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer in the documentation
Packit ea1746
//   and/or other materials provided with the distribution.
Packit ea1746
// * Neither the name of Google Inc. nor the names of its contributors may be
Packit ea1746
//   used to endorse or promote products derived from this software without
Packit ea1746
//   specific prior written permission.
Packit ea1746
//
Packit ea1746
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit ea1746
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit ea1746
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit ea1746
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit ea1746
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit ea1746
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit ea1746
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit ea1746
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit ea1746
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit ea1746
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit ea1746
// POSSIBILITY OF SUCH DAMAGE.
Packit ea1746
//
Packit ea1746
// Author: sameeragarwal@google.com (Sameer Agarwal)
Packit ea1746
Packit ea1746
#include <cmath>
Packit ea1746
#include <limits>
Packit ea1746
#include "gtest/gtest.h"
Packit ea1746
#include "ceres/parameter_block.h"
Packit ea1746
#include "ceres/residual_block.h"
Packit ea1746
#include "ceres/residual_block_utils.h"
Packit ea1746
#include "ceres/cost_function.h"
Packit ea1746
#include "ceres/internal/scoped_ptr.h"
Packit ea1746
#include "ceres/sized_cost_function.h"
Packit ea1746
Packit ea1746
namespace ceres {
Packit ea1746
namespace internal {
Packit ea1746
Packit ea1746
// Routine to check if ResidualBlock::Evaluate for unary CostFunction
Packit ea1746
// with one residual succeeds with true or dies.
Packit ea1746
void CheckEvaluation(const CostFunction& cost_function, bool is_good) {
Packit ea1746
  double x = 1.0;
Packit ea1746
  ParameterBlock parameter_block(&x, 1, -1);
Packit ea1746
  std::vector<ParameterBlock*> parameter_blocks;
Packit ea1746
  parameter_blocks.push_back(&parameter_block);
Packit ea1746
Packit ea1746
  ResidualBlock residual_block(&cost_function,
Packit ea1746
                               NULL,
Packit ea1746
                               parameter_blocks,
Packit ea1746
                               -1);
Packit ea1746
Packit ea1746
  scoped_array<double> scratch(
Packit ea1746
      new double[residual_block.NumScratchDoublesForEvaluate()]);
Packit ea1746
Packit ea1746
  double cost;
Packit ea1746
  double residuals;
Packit ea1746
  double jacobian;
Packit ea1746
  double* jacobians[] = { &jacobian };
Packit ea1746
Packit ea1746
  EXPECT_EQ(residual_block.Evaluate(true,
Packit ea1746
                                    &cost,
Packit ea1746
                                    &residuals,
Packit ea1746
                                    jacobians,
Packit ea1746
                                    scratch.get()), is_good);
Packit ea1746
}
Packit ea1746
Packit ea1746
// A CostFunction that behaves normaly, i.e., it computes numerically
Packit ea1746
// valid residuals and jacobians.
Packit ea1746
class GoodCostFunction: public SizedCostFunction<1, 1> {
Packit ea1746
 public:
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    residuals[0] = 1;
Packit ea1746
    if (jacobians != NULL && jacobians[0] != NULL) {
Packit ea1746
      jacobians[0][0] = 0.0;
Packit ea1746
    }
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
// The following four CostFunctions simulate the different ways in
Packit ea1746
// which user code can cause ResidualBlock::Evaluate to fail.
Packit ea1746
class NoResidualUpdateCostFunction: public SizedCostFunction<1, 1> {
Packit ea1746
 public:
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    // Forget to update the residuals.
Packit ea1746
    // residuals[0] = 1;
Packit ea1746
    if (jacobians != NULL && jacobians[0] != NULL) {
Packit ea1746
      jacobians[0][0] = 0.0;
Packit ea1746
    }
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
class NoJacobianUpdateCostFunction: public SizedCostFunction<1, 1> {
Packit ea1746
 public:
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    residuals[0] = 1;
Packit ea1746
    if (jacobians != NULL && jacobians[0] != NULL) {
Packit ea1746
      // Forget to update the jacobians.
Packit ea1746
      // jacobians[0][0] = 0.0;
Packit ea1746
    }
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
class BadResidualCostFunction: public SizedCostFunction<1, 1> {
Packit ea1746
 public:
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    residuals[0] = std::numeric_limits<double>::infinity();
Packit ea1746
    if (jacobians != NULL && jacobians[0] != NULL) {
Packit ea1746
      jacobians[0][0] = 0.0;
Packit ea1746
    }
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
class BadJacobianCostFunction: public SizedCostFunction<1, 1> {
Packit ea1746
 public:
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    residuals[0] = 1.0;
Packit ea1746
    if (jacobians != NULL && jacobians[0] != NULL) {
Packit ea1746
      jacobians[0][0] = std::numeric_limits<double>::quiet_NaN();
Packit ea1746
    }
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
// Note: It is preferable to write the below test as:
Packit ea1746
//
Packit ea1746
//  CheckEvaluation(GoodCostFunction(), true);
Packit ea1746
//  CheckEvaluation(NoResidualUpdateCostFunction(), false);
Packit ea1746
//  CheckEvaluation(NoJacobianUpdateCostFunction(), false);
Packit ea1746
//  ...
Packit ea1746
//
Packit ea1746
// however, there is a bug in the version of GCC on Mac OS X we tested, which
Packit ea1746
// requires the objects get put into local variables instead of getting
Packit ea1746
// instantiated on the stack.
Packit ea1746
TEST(ResidualBlockUtils, CheckAllCombinationsOfBadness) {
Packit ea1746
  GoodCostFunction good_fun;
Packit ea1746
  CheckEvaluation(good_fun, true);
Packit ea1746
  NoResidualUpdateCostFunction no_residual;
Packit ea1746
  CheckEvaluation(no_residual, false);
Packit ea1746
  NoJacobianUpdateCostFunction no_jacobian;
Packit ea1746
  CheckEvaluation(no_jacobian, false);
Packit ea1746
  BadResidualCostFunction bad_residual;
Packit ea1746
  CheckEvaluation(bad_residual, false);
Packit ea1746
  BadJacobianCostFunction bad_jacobian;
Packit ea1746
  CheckEvaluation(bad_jacobian, false);
Packit ea1746
}
Packit ea1746
Packit ea1746
}  // namespace internal
Packit ea1746
}  // namespace ceres