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/program.h" 32 33#include <map> 34#include <vector> 35#include "ceres/array_utils.h" 36#include "ceres/casts.h" 37#include "ceres/compressed_row_sparse_matrix.h" 38#include "ceres/cost_function.h" 39#include "ceres/evaluator.h" 40#include "ceres/internal/port.h" 41#include "ceres/local_parameterization.h" 42#include "ceres/loss_function.h" 43#include "ceres/map_util.h" 44#include "ceres/parameter_block.h" 45#include "ceres/problem.h" 46#include "ceres/residual_block.h" 47#include "ceres/stl_util.h" 48#include "ceres/triplet_sparse_matrix.h" 49 50namespace ceres { 51namespace internal { 52 53Program::Program() {} 54 55Program::Program(const Program& program) 56 : parameter_blocks_(program.parameter_blocks_), 57 residual_blocks_(program.residual_blocks_) { 58} 59 60const vector<ParameterBlock*>& Program::parameter_blocks() const { 61 return parameter_blocks_; 62} 63 64const vector<ResidualBlock*>& Program::residual_blocks() const { 65 return residual_blocks_; 66} 67 68vector<ParameterBlock*>* Program::mutable_parameter_blocks() { 69 return ¶meter_blocks_; 70} 71 72vector<ResidualBlock*>* Program::mutable_residual_blocks() { 73 return &residual_blocks_; 74} 75 76bool Program::StateVectorToParameterBlocks(const double *state) { 77 for (int i = 0; i < parameter_blocks_.size(); ++i) { 78 if (!parameter_blocks_[i]->IsConstant() && 79 !parameter_blocks_[i]->SetState(state)) { 80 return false; 81 } 82 state += parameter_blocks_[i]->Size(); 83 } 84 return true; 85} 86 87void Program::ParameterBlocksToStateVector(double *state) const { 88 for (int i = 0; i < parameter_blocks_.size(); ++i) { 89 parameter_blocks_[i]->GetState(state); 90 state += parameter_blocks_[i]->Size(); 91 } 92} 93 94void Program::CopyParameterBlockStateToUserState() { 95 for (int i = 0; i < parameter_blocks_.size(); ++i) { 96 parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state()); 97 } 98} 99 100bool Program::SetParameterBlockStatePtrsToUserStatePtrs() { 101 for (int i = 0; i < parameter_blocks_.size(); ++i) { 102 if (!parameter_blocks_[i]->IsConstant() && 103 !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) { 104 return false; 105 } 106 } 107 return true; 108} 109 110bool Program::Plus(const double* state, 111 const double* delta, 112 double* state_plus_delta) const { 113 for (int i = 0; i < parameter_blocks_.size(); ++i) { 114 if (!parameter_blocks_[i]->Plus(state, delta, state_plus_delta)) { 115 return false; 116 } 117 state += parameter_blocks_[i]->Size(); 118 delta += parameter_blocks_[i]->LocalSize(); 119 state_plus_delta += parameter_blocks_[i]->Size(); 120 } 121 return true; 122} 123 124void Program::SetParameterOffsetsAndIndex() { 125 // Set positions for all parameters appearing as arguments to residuals to one 126 // past the end of the parameter block array. 127 for (int i = 0; i < residual_blocks_.size(); ++i) { 128 ResidualBlock* residual_block = residual_blocks_[i]; 129 for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) { 130 residual_block->parameter_blocks()[j]->set_index(-1); 131 } 132 } 133 // For parameters that appear in the program, set their position and offset. 134 int state_offset = 0; 135 int delta_offset = 0; 136 for (int i = 0; i < parameter_blocks_.size(); ++i) { 137 parameter_blocks_[i]->set_index(i); 138 parameter_blocks_[i]->set_state_offset(state_offset); 139 parameter_blocks_[i]->set_delta_offset(delta_offset); 140 state_offset += parameter_blocks_[i]->Size(); 141 delta_offset += parameter_blocks_[i]->LocalSize(); 142 } 143} 144 145bool Program::IsValid() const { 146 for (int i = 0; i < residual_blocks_.size(); ++i) { 147 const ResidualBlock* residual_block = residual_blocks_[i]; 148 if (residual_block->index() != i) { 149 LOG(WARNING) << "Residual block: " << i 150 << " has incorrect index: " << residual_block->index(); 151 return false; 152 } 153 } 154 155 int state_offset = 0; 156 int delta_offset = 0; 157 for (int i = 0; i < parameter_blocks_.size(); ++i) { 158 const ParameterBlock* parameter_block = parameter_blocks_[i]; 159 if (parameter_block->index() != i || 160 parameter_block->state_offset() != state_offset || 161 parameter_block->delta_offset() != delta_offset) { 162 LOG(WARNING) << "Parameter block: " << i 163 << "has incorrect indexing information: " 164 << parameter_block->ToString(); 165 return false; 166 } 167 168 state_offset += parameter_blocks_[i]->Size(); 169 delta_offset += parameter_blocks_[i]->LocalSize(); 170 } 171 172 return true; 173} 174 175bool Program::ParameterBlocksAreFinite(string* message) const { 176 CHECK_NOTNULL(message); 177 for (int i = 0; i < parameter_blocks_.size(); ++i) { 178 const ParameterBlock* parameter_block = parameter_blocks_[i]; 179 const double* array = parameter_block->user_state(); 180 const int size = parameter_block->Size(); 181 const int invalid_index = FindInvalidValue(size, array); 182 if (invalid_index != size) { 183 *message = StringPrintf( 184 "ParameterBlock: %p with size %d has at least one invalid value.\n" 185 "First invalid value is at index: %d.\n" 186 "Parameter block values: ", 187 array, size, invalid_index); 188 AppendArrayToString(size, array, message); 189 return false; 190 } 191 } 192 return true; 193} 194 195bool Program::IsBoundsConstrained() const { 196 for (int i = 0; i < parameter_blocks_.size(); ++i) { 197 const ParameterBlock* parameter_block = parameter_blocks_[i]; 198 if (parameter_block->IsConstant()) { 199 continue; 200 } 201 const int size = parameter_block->Size(); 202 for (int j = 0; j < size; ++j) { 203 const double lower_bound = parameter_block->LowerBoundForParameter(j); 204 const double upper_bound = parameter_block->UpperBoundForParameter(j); 205 if (lower_bound > -std::numeric_limits<double>::max() || 206 upper_bound < std::numeric_limits<double>::max()) { 207 return true; 208 } 209 } 210 } 211 return false; 212} 213 214bool Program::IsFeasible(string* message) const { 215 CHECK_NOTNULL(message); 216 for (int i = 0; i < parameter_blocks_.size(); ++i) { 217 const ParameterBlock* parameter_block = parameter_blocks_[i]; 218 const double* parameters = parameter_block->user_state(); 219 const int size = parameter_block->Size(); 220 if (parameter_block->IsConstant()) { 221 // Constant parameter blocks must start in the feasible region 222 // to ultimately produce a feasible solution, since Ceres cannot 223 // change them. 224 for (int j = 0; j < size; ++j) { 225 const double lower_bound = parameter_block->LowerBoundForParameter(j); 226 const double upper_bound = parameter_block->UpperBoundForParameter(j); 227 if (parameters[j] < lower_bound || parameters[j] > upper_bound) { 228 *message = StringPrintf( 229 "ParameterBlock: %p with size %d has at least one infeasible " 230 "value." 231 "\nFirst infeasible value is at index: %d." 232 "\nLower bound: %e, value: %e, upper bound: %e" 233 "\nParameter block values: ", 234 parameters, size, j, lower_bound, parameters[j], upper_bound); 235 AppendArrayToString(size, parameters, message); 236 return false; 237 } 238 } 239 } else { 240 // Variable parameter blocks must have non-empty feasible 241 // regions, otherwise there is no way to produce a feasible 242 // solution. 243 for (int j = 0; j < size; ++j) { 244 const double lower_bound = parameter_block->LowerBoundForParameter(j); 245 const double upper_bound = parameter_block->UpperBoundForParameter(j); 246 if (lower_bound >= upper_bound) { 247 *message = StringPrintf( 248 "ParameterBlock: %p with size %d has at least one infeasible " 249 "bound." 250 "\nFirst infeasible bound is at index: %d." 251 "\nLower bound: %e, upper bound: %e" 252 "\nParameter block values: ", 253 parameters, size, j, lower_bound, upper_bound); 254 AppendArrayToString(size, parameters, message); 255 return false; 256 } 257 } 258 } 259 } 260 261 return true; 262} 263 264Program* Program::CreateReducedProgram(vector<double*>* removed_parameter_blocks, 265 double* fixed_cost, 266 string* error) const { 267 CHECK_NOTNULL(removed_parameter_blocks); 268 CHECK_NOTNULL(fixed_cost); 269 CHECK_NOTNULL(error); 270 271 scoped_ptr<Program> reduced_program(new Program(*this)); 272 if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks, 273 fixed_cost, 274 error)) { 275 return NULL; 276 } 277 278 reduced_program->SetParameterOffsetsAndIndex(); 279 return reduced_program.release(); 280} 281 282bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks, 283 double* fixed_cost, 284 string* error) { 285 CHECK_NOTNULL(removed_parameter_blocks); 286 CHECK_NOTNULL(fixed_cost); 287 CHECK_NOTNULL(error); 288 289 scoped_array<double> residual_block_evaluate_scratch; 290 residual_block_evaluate_scratch.reset( 291 new double[MaxScratchDoublesNeededForEvaluate()]); 292 *fixed_cost = 0.0; 293 294 // Mark all the parameters as unused. Abuse the index member of the 295 // parameter blocks for the marking. 296 for (int i = 0; i < parameter_blocks_.size(); ++i) { 297 parameter_blocks_[i]->set_index(-1); 298 } 299 300 // Filter out residual that have all-constant parameters, and mark 301 // all the parameter blocks that appear in residuals. 302 int num_active_residual_blocks = 0; 303 for (int i = 0; i < residual_blocks_.size(); ++i) { 304 ResidualBlock* residual_block = residual_blocks_[i]; 305 int num_parameter_blocks = residual_block->NumParameterBlocks(); 306 307 // Determine if the residual block is fixed, and also mark varying 308 // parameters that appear in the residual block. 309 bool all_constant = true; 310 for (int k = 0; k < num_parameter_blocks; k++) { 311 ParameterBlock* parameter_block = residual_block->parameter_blocks()[k]; 312 if (!parameter_block->IsConstant()) { 313 all_constant = false; 314 parameter_block->set_index(1); 315 } 316 } 317 318 if (!all_constant) { 319 residual_blocks_[num_active_residual_blocks++] = residual_block; 320 continue; 321 } 322 323 // The residual is constant and will be removed, so its cost is 324 // added to the variable fixed_cost. 325 double cost = 0.0; 326 if (!residual_block->Evaluate(true, 327 &cost, 328 NULL, 329 NULL, 330 residual_block_evaluate_scratch.get())) { 331 *error = StringPrintf("Evaluation of the residual %d failed during " 332 "removal of fixed residual blocks.", i); 333 return false; 334 } 335 *fixed_cost += cost; 336 } 337 residual_blocks_.resize(num_active_residual_blocks); 338 339 // Filter out unused or fixed parameter blocks. 340 int num_active_parameter_blocks = 0; 341 removed_parameter_blocks->clear(); 342 for (int i = 0; i < parameter_blocks_.size(); ++i) { 343 ParameterBlock* parameter_block = parameter_blocks_[i]; 344 if (parameter_block->index() == -1) { 345 removed_parameter_blocks->push_back(parameter_block->mutable_user_state()); 346 } else { 347 parameter_blocks_[num_active_parameter_blocks++] = parameter_block; 348 } 349 } 350 parameter_blocks_.resize(num_active_parameter_blocks); 351 352 if (!(((NumResidualBlocks() == 0) && 353 (NumParameterBlocks() == 0)) || 354 ((NumResidualBlocks() != 0) && 355 (NumParameterBlocks() != 0)))) { 356 *error = "Congratulations, you found a bug in Ceres. Please report it."; 357 return false; 358 } 359 360 return true; 361} 362 363bool Program::IsParameterBlockSetIndependent(const set<double*>& independent_set) const { 364 // Loop over each residual block and ensure that no two parameter 365 // blocks in the same residual block are part of 366 // parameter_block_ptrs as that would violate the assumption that it 367 // is an independent set in the Hessian matrix. 368 for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin(); 369 it != residual_blocks_.end(); 370 ++it) { 371 ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks(); 372 const int num_parameter_blocks = (*it)->NumParameterBlocks(); 373 int count = 0; 374 for (int i = 0; i < num_parameter_blocks; ++i) { 375 count += independent_set.count( 376 parameter_blocks[i]->mutable_user_state()); 377 } 378 if (count > 1) { 379 return false; 380 } 381 } 382 return true; 383} 384 385TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const { 386 // Matrix to store the block sparsity structure of the Jacobian. 387 TripletSparseMatrix* tsm = 388 new TripletSparseMatrix(NumParameterBlocks(), 389 NumResidualBlocks(), 390 10 * NumResidualBlocks()); 391 int num_nonzeros = 0; 392 int* rows = tsm->mutable_rows(); 393 int* cols = tsm->mutable_cols(); 394 double* values = tsm->mutable_values(); 395 396 for (int c = 0; c < residual_blocks_.size(); ++c) { 397 const ResidualBlock* residual_block = residual_blocks_[c]; 398 const int num_parameter_blocks = residual_block->NumParameterBlocks(); 399 ParameterBlock* const* parameter_blocks = 400 residual_block->parameter_blocks(); 401 402 for (int j = 0; j < num_parameter_blocks; ++j) { 403 if (parameter_blocks[j]->IsConstant()) { 404 continue; 405 } 406 407 // Re-size the matrix if needed. 408 if (num_nonzeros >= tsm->max_num_nonzeros()) { 409 tsm->set_num_nonzeros(num_nonzeros); 410 tsm->Reserve(2 * num_nonzeros); 411 rows = tsm->mutable_rows(); 412 cols = tsm->mutable_cols(); 413 values = tsm->mutable_values(); 414 } 415 416 const int r = parameter_blocks[j]->index(); 417 rows[num_nonzeros] = r; 418 cols[num_nonzeros] = c; 419 values[num_nonzeros] = 1.0; 420 ++num_nonzeros; 421 } 422 } 423 424 tsm->set_num_nonzeros(num_nonzeros); 425 return tsm; 426} 427 428int Program::NumResidualBlocks() const { 429 return residual_blocks_.size(); 430} 431 432int Program::NumParameterBlocks() const { 433 return parameter_blocks_.size(); 434} 435 436int Program::NumResiduals() const { 437 int num_residuals = 0; 438 for (int i = 0; i < residual_blocks_.size(); ++i) { 439 num_residuals += residual_blocks_[i]->NumResiduals(); 440 } 441 return num_residuals; 442} 443 444int Program::NumParameters() const { 445 int num_parameters = 0; 446 for (int i = 0; i < parameter_blocks_.size(); ++i) { 447 num_parameters += parameter_blocks_[i]->Size(); 448 } 449 return num_parameters; 450} 451 452int Program::NumEffectiveParameters() const { 453 int num_parameters = 0; 454 for (int i = 0; i < parameter_blocks_.size(); ++i) { 455 num_parameters += parameter_blocks_[i]->LocalSize(); 456 } 457 return num_parameters; 458} 459 460int Program::MaxScratchDoublesNeededForEvaluate() const { 461 // Compute the scratch space needed for evaluate. 462 int max_scratch_bytes_for_evaluate = 0; 463 for (int i = 0; i < residual_blocks_.size(); ++i) { 464 max_scratch_bytes_for_evaluate = 465 max(max_scratch_bytes_for_evaluate, 466 residual_blocks_[i]->NumScratchDoublesForEvaluate()); 467 } 468 return max_scratch_bytes_for_evaluate; 469} 470 471int Program::MaxDerivativesPerResidualBlock() const { 472 int max_derivatives = 0; 473 for (int i = 0; i < residual_blocks_.size(); ++i) { 474 int derivatives = 0; 475 ResidualBlock* residual_block = residual_blocks_[i]; 476 int num_parameters = residual_block->NumParameterBlocks(); 477 for (int j = 0; j < num_parameters; ++j) { 478 derivatives += residual_block->NumResiduals() * 479 residual_block->parameter_blocks()[j]->LocalSize(); 480 } 481 max_derivatives = max(max_derivatives, derivatives); 482 } 483 return max_derivatives; 484} 485 486int Program::MaxParametersPerResidualBlock() const { 487 int max_parameters = 0; 488 for (int i = 0; i < residual_blocks_.size(); ++i) { 489 max_parameters = max(max_parameters, 490 residual_blocks_[i]->NumParameterBlocks()); 491 } 492 return max_parameters; 493} 494 495int Program::MaxResidualsPerResidualBlock() const { 496 int max_residuals = 0; 497 for (int i = 0; i < residual_blocks_.size(); ++i) { 498 max_residuals = max(max_residuals, 499 residual_blocks_[i]->NumResiduals()); 500 } 501 return max_residuals; 502} 503 504string Program::ToString() const { 505 string ret = "Program dump\n"; 506 ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks()); 507 ret += StringPrintf("Number of parameters: %d\n", NumParameters()); 508 ret += "Parameters:\n"; 509 for (int i = 0; i < parameter_blocks_.size(); ++i) { 510 ret += StringPrintf("%d: %s\n", 511 i, parameter_blocks_[i]->ToString().c_str()); 512 } 513 return ret; 514} 515 516} // namespace internal 517} // namespace ceres 518