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