Blame internal/ceres/residual_block.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: keir@google.com (Keir Mierle)
Packit ea1746
//         sameeragarwal@google.com (Sameer Agarwal)
Packit ea1746
Packit ea1746
#include "ceres/residual_block.h"
Packit ea1746
Packit ea1746
#include <algorithm>
Packit ea1746
#include <cstddef>
Packit ea1746
#include <vector>
Packit ea1746
#include "ceres/corrector.h"
Packit ea1746
#include "ceres/parameter_block.h"
Packit ea1746
#include "ceres/residual_block_utils.h"
Packit ea1746
#include "ceres/cost_function.h"
Packit ea1746
#include "ceres/internal/eigen.h"
Packit ea1746
#include "ceres/internal/fixed_array.h"
Packit ea1746
#include "ceres/local_parameterization.h"
Packit ea1746
#include "ceres/loss_function.h"
Packit ea1746
#include "ceres/small_blas.h"
Packit ea1746
Packit ea1746
using Eigen::Dynamic;
Packit ea1746
Packit ea1746
namespace ceres {
Packit ea1746
namespace internal {
Packit ea1746
Packit ea1746
ResidualBlock::ResidualBlock(
Packit ea1746
    const CostFunction* cost_function,
Packit ea1746
    const LossFunction* loss_function,
Packit ea1746
    const std::vector<ParameterBlock*>& parameter_blocks,
Packit ea1746
    int index)
Packit ea1746
    : cost_function_(cost_function),
Packit ea1746
      loss_function_(loss_function),
Packit ea1746
      parameter_blocks_(
Packit ea1746
          new ParameterBlock* [
Packit ea1746
              cost_function->parameter_block_sizes().size()]),
Packit ea1746
      index_(index) {
Packit ea1746
  std::copy(parameter_blocks.begin(),
Packit ea1746
            parameter_blocks.end(),
Packit ea1746
            parameter_blocks_.get());
Packit ea1746
}
Packit ea1746
Packit ea1746
bool ResidualBlock::Evaluate(const bool apply_loss_function,
Packit ea1746
                             double* cost,
Packit ea1746
                             double* residuals,
Packit ea1746
                             double** jacobians,
Packit ea1746
                             double* scratch) const {
Packit ea1746
  const int num_parameter_blocks = NumParameterBlocks();
Packit ea1746
  const int num_residuals = cost_function_->num_residuals();
Packit ea1746
Packit ea1746
  // Collect the parameters from their blocks. This will rarely allocate, since
Packit ea1746
  // residuals taking more than 8 parameter block arguments are rare.
Packit ea1746
  FixedArray<const double*, 8> parameters(num_parameter_blocks);
Packit ea1746
  for (int i = 0; i < num_parameter_blocks; ++i) {
Packit ea1746
    parameters[i] = parameter_blocks_[i]->state();
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Put pointers into the scratch space into global_jacobians as appropriate.
Packit ea1746
  FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
Packit ea1746
  if (jacobians != NULL) {
Packit ea1746
    for (int i = 0; i < num_parameter_blocks; ++i) {
Packit ea1746
      const ParameterBlock* parameter_block = parameter_blocks_[i];
Packit ea1746
      if (jacobians[i] != NULL &&
Packit ea1746
          parameter_block->LocalParameterizationJacobian() != NULL) {
Packit ea1746
        global_jacobians[i] = scratch;
Packit ea1746
        scratch += num_residuals * parameter_block->Size();
Packit ea1746
      } else {
Packit ea1746
        global_jacobians[i] = jacobians[i];
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // If the caller didn't request residuals, use the scratch space for them.
Packit ea1746
  bool outputting_residuals = (residuals != NULL);
Packit ea1746
  if (!outputting_residuals) {
Packit ea1746
    residuals = scratch;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Invalidate the evaluation buffers so that we can check them after
Packit ea1746
  // the CostFunction::Evaluate call, to see if all the return values
Packit ea1746
  // that were required were written to and that they are finite.
Packit ea1746
  double** eval_jacobians = (jacobians != NULL) ? global_jacobians.get() : NULL;
Packit ea1746
Packit ea1746
  InvalidateEvaluation(*this, cost, residuals, eval_jacobians);
Packit ea1746
Packit ea1746
  if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians)) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  if (!IsEvaluationValid(*this,
Packit ea1746
                         parameters.get(),
Packit ea1746
                         cost,
Packit ea1746
                         residuals,
Packit ea1746
                         eval_jacobians)) {
Packit ea1746
    std::string message =
Packit ea1746
        "\n\n"
Packit ea1746
        "Error in evaluating the ResidualBlock.\n\n"
Packit ea1746
        "There are two possible reasons. Either the CostFunction did not evaluate and fill all    \n"  // NOLINT
Packit ea1746
        "residual and jacobians that were requested or there was a non-finite value (nan/infinite)\n"  // NOLINT
Packit ea1746
        "generated during the or jacobian computation. \n\n" +
Packit ea1746
        EvaluationToString(*this,
Packit ea1746
                           parameters.get(),
Packit ea1746
                           cost,
Packit ea1746
                           residuals,
Packit ea1746
                           eval_jacobians);
Packit ea1746
    LOG(WARNING) << message;
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
Packit ea1746
Packit ea1746
  // Update the jacobians with the local parameterizations.
Packit ea1746
  if (jacobians != NULL) {
Packit ea1746
    for (int i = 0; i < num_parameter_blocks; ++i) {
Packit ea1746
      if (jacobians[i] != NULL) {
Packit ea1746
        const ParameterBlock* parameter_block = parameter_blocks_[i];
Packit ea1746
Packit ea1746
        // Apply local reparameterization to the jacobians.
Packit ea1746
        if (parameter_block->LocalParameterizationJacobian() != NULL) {
Packit ea1746
          // jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
Packit ea1746
          MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
Packit ea1746
              global_jacobians[i],
Packit ea1746
              num_residuals,
Packit ea1746
              parameter_block->Size(),
Packit ea1746
              parameter_block->LocalParameterizationJacobian(),
Packit ea1746
              parameter_block->Size(),
Packit ea1746
              parameter_block->LocalSize(),
Packit ea1746
              jacobians[i], 0, 0,  num_residuals, parameter_block->LocalSize());
Packit ea1746
        }
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  if (loss_function_ == NULL || !apply_loss_function) {
Packit ea1746
    *cost = 0.5 * squared_norm;
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  double rho[3];
Packit ea1746
  loss_function_->Evaluate(squared_norm, rho);
Packit ea1746
  *cost = 0.5 * rho[0];
Packit ea1746
Packit ea1746
  // No jacobians and not outputting residuals? All done. Doing an early exit
Packit ea1746
  // here avoids constructing the "Corrector" object below in a common case.
Packit ea1746
  if (jacobians == NULL && !outputting_residuals) {
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Correct for the effects of the loss function. The jacobians need to be
Packit ea1746
  // corrected before the residuals, since they use the uncorrected residuals.
Packit ea1746
  Corrector correct(squared_norm, rho);
Packit ea1746
  if (jacobians != NULL) {
Packit ea1746
    for (int i = 0; i < num_parameter_blocks; ++i) {
Packit ea1746
      if (jacobians[i] != NULL) {
Packit ea1746
        const ParameterBlock* parameter_block = parameter_blocks_[i];
Packit ea1746
Packit ea1746
        // Correct the jacobians for the loss function.
Packit ea1746
        correct.CorrectJacobian(num_residuals,
Packit ea1746
                                parameter_block->LocalSize(),
Packit ea1746
                                residuals,
Packit ea1746
                                jacobians[i]);
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Correct the residuals with the loss function.
Packit ea1746
  if (outputting_residuals) {
Packit ea1746
    correct.CorrectResiduals(num_residuals, residuals);
Packit ea1746
  }
Packit ea1746
  return true;
Packit ea1746
}
Packit ea1746
Packit ea1746
int ResidualBlock::NumScratchDoublesForEvaluate() const {
Packit ea1746
  // Compute the amount of scratch space needed to store the full-sized
Packit ea1746
  // jacobians. For parameters that have no local parameterization  no storage
Packit ea1746
  // is needed and the passed-in jacobian array is used directly. Also include
Packit ea1746
  // space to store the residuals, which is needed for cost-only evaluations.
Packit ea1746
  // This is slightly pessimistic, since both won't be needed all the time, but
Packit ea1746
  // the amount of excess should not cause problems for the caller.
Packit ea1746
  int num_parameters = NumParameterBlocks();
Packit ea1746
  int scratch_doubles = 1;
Packit ea1746
  for (int i = 0; i < num_parameters; ++i) {
Packit ea1746
    const ParameterBlock* parameter_block = parameter_blocks_[i];
Packit ea1746
    if (!parameter_block->IsConstant() &&
Packit ea1746
        parameter_block->LocalParameterizationJacobian() != NULL) {
Packit ea1746
      scratch_doubles += parameter_block->Size();
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
  scratch_doubles *= NumResiduals();
Packit ea1746
  return scratch_doubles;
Packit ea1746
}
Packit ea1746
Packit ea1746
}  // namespace internal
Packit ea1746
}  // namespace ceres