Update Ceres to the latest upstream
Summary: This brings up much easier termination type usage, which for us means we might use: ceres::Summary::IsSolutionUsable() instead of doing manual funky enum values check. Reviewers: keir Differential Revision: https://developer.blender.org/D153
This commit is contained in:
parent
71f689843d
commit
5933b2455c
|
@ -332,9 +332,7 @@ int libmv_trackRegion(const libmv_TrackRegionOptions *options,
|
|||
}
|
||||
|
||||
/* TODO(keir): Update the termination string with failure details. */
|
||||
if (track_region_result.termination == libmv::TrackRegionResult::PARAMETER_TOLERANCE ||
|
||||
track_region_result.termination == libmv::TrackRegionResult::FUNCTION_TOLERANCE ||
|
||||
track_region_result.termination == libmv::TrackRegionResult::GRADIENT_TOLERANCE ||
|
||||
if (track_region_result.termination == libmv::TrackRegionResult::CONVERGENCE ||
|
||||
track_region_result.termination == libmv::TrackRegionResult::NO_CONVERGENCE)
|
||||
{
|
||||
tracking_result = true;
|
||||
|
|
|
@ -538,9 +538,7 @@ bool EstimateFundamentalFromCorrespondences(
|
|||
|
||||
LG << "Final refined matrix:\n" << *F;
|
||||
|
||||
return !(summary.termination_type == ceres::DID_NOT_RUN ||
|
||||
summary.termination_type == ceres::NUMERICAL_FAILURE ||
|
||||
summary.termination_type == ceres::USER_ABORT);
|
||||
return summary.IsSolutionUsable();
|
||||
}
|
||||
|
||||
} // namespace libmv
|
||||
|
|
|
@ -330,9 +330,7 @@ bool EstimateHomography2DFromCorrespondences(
|
|||
|
||||
LG << "Final refined matrix:\n" << *H;
|
||||
|
||||
return !(summary.termination_type == ceres::DID_NOT_RUN ||
|
||||
summary.termination_type == ceres::NUMERICAL_FAILURE ||
|
||||
summary.termination_type == ceres::USER_ABORT);
|
||||
return summary.IsSolutionUsable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1331,9 +1331,7 @@ void TemplatedTrackRegion(const FloatImage &image1,
|
|||
|
||||
// Of the things that can happen in the first pass, don't try the brute
|
||||
// pass (and second attempt) if the error is one of the terminations below.
|
||||
if (result->termination == TrackRegionResult::PARAMETER_TOLERANCE ||
|
||||
result->termination == TrackRegionResult::FUNCTION_TOLERANCE ||
|
||||
result->termination == TrackRegionResult::GRADIENT_TOLERANCE ||
|
||||
if (result->termination == TrackRegionResult::CONVERGENCE ||
|
||||
result->termination == TrackRegionResult::SOURCE_OUT_OF_BOUNDS ||
|
||||
result->termination == TrackRegionResult::DESTINATION_OUT_OF_BOUNDS ||
|
||||
result->termination == TrackRegionResult::INSUFFICIENT_PATTERN_AREA) {
|
||||
|
@ -1488,7 +1486,7 @@ void TemplatedTrackRegion(const FloatImage &image1,
|
|||
// TODO(keir): Update the result statistics.
|
||||
// TODO(keir): Add a normalize-cross-correlation variant.
|
||||
|
||||
if (summary.termination_type == ceres::USER_ABORT) {
|
||||
if (summary.termination_type == ceres::USER_FAILURE) {
|
||||
result->termination = TrackRegionResult::FELL_OUT_OF_BOUNDS;
|
||||
return;
|
||||
}
|
||||
|
@ -1500,8 +1498,7 @@ void TemplatedTrackRegion(const FloatImage &image1,
|
|||
}
|
||||
|
||||
// Avoid computing correlation for tracking failures.
|
||||
HANDLE_TERMINATION(DID_NOT_RUN);
|
||||
HANDLE_TERMINATION(NUMERICAL_FAILURE);
|
||||
HANDLE_TERMINATION(FAILURE);
|
||||
|
||||
// Otherwise, run a final correlation check.
|
||||
if (options.minimum_correlation > 0.0) {
|
||||
|
@ -1520,13 +1517,11 @@ void TemplatedTrackRegion(const FloatImage &image1,
|
|||
// than Ceres's parameter tolerance, which operates on the raw parameter
|
||||
// values rather than the pixel shifts of the patch corners.
|
||||
if (summary.termination_type == ceres::USER_SUCCESS) {
|
||||
result->termination = TrackRegionResult::PARAMETER_TOLERANCE;
|
||||
result->termination = TrackRegionResult::CONVERGENCE;
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE_TERMINATION(PARAMETER_TOLERANCE);
|
||||
HANDLE_TERMINATION(FUNCTION_TOLERANCE);
|
||||
HANDLE_TERMINATION(GRADIENT_TOLERANCE);
|
||||
HANDLE_TERMINATION(CONVERGENCE);
|
||||
HANDLE_TERMINATION(NO_CONVERGENCE);
|
||||
#undef HANDLE_TERMINATION
|
||||
};
|
||||
|
|
|
@ -110,12 +110,9 @@ struct TrackRegionOptions {
|
|||
struct TrackRegionResult {
|
||||
enum Termination {
|
||||
// Ceres termination types, duplicated; though, not the int values.
|
||||
PARAMETER_TOLERANCE,
|
||||
FUNCTION_TOLERANCE,
|
||||
GRADIENT_TOLERANCE,
|
||||
CONVERGENCE,
|
||||
NO_CONVERGENCE,
|
||||
DID_NOT_RUN,
|
||||
NUMERICAL_FAILURE,
|
||||
FAILURE,
|
||||
|
||||
// Libmv specific errors.
|
||||
SOURCE_OUT_OF_BOUNDS,
|
||||
|
|
|
@ -1,3 +1,147 @@
|
|||
commit 2b16b0080b6e673eaaf9ed478c9e971d9fcd65de
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Fri Dec 20 15:22:26 2013 -0800
|
||||
|
||||
CompressedRowSparseMatrix::AppendRows and DeleteRows bugfix.
|
||||
|
||||
CompressedRowSparseMatrix can store the row and column block structure
|
||||
but the AppendRows and DeleteRows methods did not pay attention to them.
|
||||
This meant that it was possible to get to a CompressedRowSparseMatrix
|
||||
whose block structure did not match the contents of the matrix.
|
||||
|
||||
This change fixes this problem.
|
||||
|
||||
Change-Id: I1b3c807fc03d8c049ee20511e2bc62806d211b81
|
||||
|
||||
commit 27bb4a8589c47a65b5ea2c01872a903043d0ef74
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Wed Dec 18 13:06:58 2013 -0800
|
||||
|
||||
Handle empty problems consistently.
|
||||
|
||||
Until now Ceres was inconsistent in the way it handled a solve
|
||||
call on an "empty" Problem. If the problem did not contain
|
||||
any residual or parameter blocks, it failed. However, if after
|
||||
constructing the reduced program, the problem was found to not
|
||||
contain any modifiable parameter blocks, it was considered a valid
|
||||
problem which had a constant objective function value.
|
||||
|
||||
When creating problems automatically, it is often the case that
|
||||
an empty problem is a corner case. This change makes handling this
|
||||
corner case consistent with the rest of Ceres logic.
|
||||
|
||||
Change-Id: Ia9da09fbf5d5cd7eae6b39a92c1976b8645db9fe
|
||||
|
||||
commit dcee120bac04911bf01d8365bddca87c74ce2af9
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Sat Dec 7 21:48:56 2013 -0800
|
||||
|
||||
Consolidate SolverTerminationType enum.
|
||||
|
||||
1. Rename SolverTerminationType to TerminationType.
|
||||
2. Consolidate the enum as
|
||||
a. CONVERGENCE - subsumes FUNCTION_TOLERANCE, PARAMETER_TOLERANCE and GRADIENT_TOLERANCE
|
||||
b. NO_CONVERGENCE
|
||||
c. FAILURE - captures all kinds of failures including DID_NOT_RUN.
|
||||
d. USER_SUCCESS
|
||||
e. USER_FAILURE
|
||||
3. Solver::Summary::error is renamed to be Solver::Summary::message, to both
|
||||
reduce confusion as well as capture its true meaning.
|
||||
|
||||
Change-Id: I27a382e66e67f5a4750d0ee914d941f6b53c326d
|
||||
|
||||
commit d1cf320bb4f032cb14b20114a29ce2d867307492
|
||||
Author: Sergey Sharybin <sergey.vfx@gmail.com>
|
||||
Date: Thu Nov 28 23:11:11 2013 +0600
|
||||
|
||||
Made collections port compatible with MSVC2008
|
||||
|
||||
The issue was caused by the fact that in this version
|
||||
of MSVC unordered_map class is defined in <unordered_map>
|
||||
header file, but this file declares the class int std::tr1
|
||||
namespace.
|
||||
|
||||
This confused existing assumption that if there's an
|
||||
existing <unordered_map> file then class is declared
|
||||
in std namespace.
|
||||
|
||||
Added an extra check to CMake which detects whether
|
||||
it's std or std::tr1 which actually contains class
|
||||
of unordered_map.
|
||||
|
||||
Change-Id: Ic5cf41913895a6ce8e791cc7602d7cf5492c34de
|
||||
|
||||
commit 324eccb5f6ce2a1a0061ec9f3c40778a029a2d97
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Tue Dec 3 09:28:14 2013 -0800
|
||||
|
||||
Restore the state of the Problem after a call to Evaluate.
|
||||
|
||||
Calling Problem::Evaluate mutates the state of the parameter blocks.
|
||||
In particular, depending on the set and order of parameter blocks
|
||||
passed to the evaluate call, it will change the internal indexing
|
||||
used by the Program object used by ProblemImpl. This needs to be
|
||||
undone before Evaluate returns, otherwise the Problem object
|
||||
is in an invalid state.
|
||||
|
||||
To help with testing and debugging in the future, a new method
|
||||
Program::IsValid has been added which checks whether the problem
|
||||
has its parameter and residual blocks in the right state.
|
||||
|
||||
Thanks to Stefan Leutenegger for reporting this.
|
||||
|
||||
Change-Id: I209b486a31433f0cbb58b570047649eca6d42b56
|
||||
|
||||
commit 3b1ad31a1fe89fe0bd78e1fffdf22d47d43faaf5
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Mon Dec 2 15:43:20 2013 -0800
|
||||
|
||||
Fix build breakage on old versions of SuiteSparse.
|
||||
|
||||
Change-Id: I2a061615fc374abef2ed323c298359002a6fc5f1
|
||||
|
||||
commit 5fd480692b0a0c87e2af2f5a8754042a14f5f089
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Mon Dec 2 12:16:53 2013 -0800
|
||||
|
||||
Add more documentation to the linear solver enums.
|
||||
|
||||
Change-Id: Id57f76f73fa38043c0b6729972b1de8578ad7ede
|
||||
|
||||
commit d73acd035359886dfa1c5762b01c6f6449edcab8
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Mon Dec 2 12:02:03 2013 -0800
|
||||
|
||||
Lint cleanup from William Rucklidge.
|
||||
|
||||
Change-Id: I8abcfd369f41b895ce746a21a35f250fe05c39d1
|
||||
|
||||
commit 3faac6a28cec4c99c41421d3f585f3786be443b3
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Thu Nov 28 07:13:26 2013 -0800
|
||||
|
||||
More lint cleanups and breakage fixes.
|
||||
|
||||
The previous CL was a premature submit due to lack of coffee.
|
||||
|
||||
Change-Id: Id425d0ef332f569a954f0413e6b1ae6087f40f30
|
||||
|
||||
commit ed92366592a951041bd0367c24006101ef7b6286
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Thu Nov 28 06:50:43 2013 -0800
|
||||
|
||||
Lint cleanup from William Rucklidge.
|
||||
|
||||
Change-Id: I745810f5496a1b93263b20ff140f8883da61995e
|
||||
|
||||
commit 34b6359f39884683f2bbf06c93040afd42ae135d
|
||||
Author: Sergey Sharybin <sergey.vfx@gmail.com>
|
||||
Date: Thu Nov 28 18:51:34 2013 +0600
|
||||
|
||||
Fix compilation error after recent enum rename in 33e01b9
|
||||
|
||||
Change-Id: I920aa4754df6b013e86f0e77c61338d7a80e7f45
|
||||
|
||||
commit 33e01b9c5e1416fe29c55ac0332cdca21c053c83
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Wed Nov 27 10:24:03 2013 -0800
|
||||
|
@ -537,148 +681,3 @@ Date: Sun Oct 27 21:38:13 2013 -0700
|
|||
are not exposed. This would be done in a future change.
|
||||
|
||||
Change-Id: I7ddc36790943f24b19c7f08b10694ae9a822f5c9
|
||||
|
||||
commit 5a161a2b9653489ee9040f054b24df971e6b9bbc
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Tue Oct 29 22:08:15 2013 -0700
|
||||
|
||||
Template specializations for PartitionedMatrixView.
|
||||
|
||||
This speeds up the matrix vector products in the
|
||||
IterativeSchurSolver by upto 40%.
|
||||
|
||||
Change-Id: Ib5e8d77c7269cf5ffdd2d161893734bb6d38215d
|
||||
|
||||
commit e5ce1170bc9993085c81a788e16eb48f1b2fdb97
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Tue Oct 29 07:40:51 2013 -0700
|
||||
|
||||
Minor bug fix to autodiff.h
|
||||
|
||||
Change-Id: Ib41050a2f2ba1898c71ff19d74f8eca2496212c0
|
||||
|
||||
commit 9e9a7d6ca0e75727293f94452d602f02b56d10ba
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Tue Oct 29 06:54:44 2013 -0700
|
||||
|
||||
Documentation update.
|
||||
|
||||
Add documentation for the new methods added to Problem.
|
||||
Fix a bunch of ReST bugs.
|
||||
|
||||
Change-Id: I8a79a84040cfa8a679cc5355baccbe6d69bc9e70
|
||||
|
||||
commit c6bafdd02c33ec0ccb705578d83e4f601ddeedea
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Mon Oct 28 19:38:08 2013 -0700
|
||||
|
||||
Comments from Jim Roseborough.
|
||||
|
||||
1. Fix the tolerance on the rotation matrix conversion test.
|
||||
2. Fix some out of date comments.
|
||||
|
||||
Change-Id: I65e80da1f96d7b4d9ac0630ad8cb708c41739840
|
||||
|
||||
commit fda69b52130955479591e8f03f97b1cfceca369f
|
||||
Author: Keir Mierle <mierle@gmail.com>
|
||||
Date: Thu Oct 10 00:25:24 2013 -0700
|
||||
|
||||
Export the structure of a problem to the public API
|
||||
|
||||
This adds three new public methods to ceres::Problem:
|
||||
|
||||
Problem::GetResidualBlocks()
|
||||
Problem::GetParameterBlocksForResidualBlock()
|
||||
Problem::GetResidualBlocksForParameterBlock()
|
||||
|
||||
These permit access to the underlying graph structure of the problem.
|
||||
|
||||
Change-Id: I55a4c7f0e5f325f140cb4830e7a7070554594650
|
||||
|
||||
commit 63bcdffa7d188b8d8c5309a62c255ba33f061764
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Sun Oct 27 21:34:13 2013 -0700
|
||||
|
||||
Add the 2_d_d SchurEliminator specialization.
|
||||
|
||||
This occurs far too often in bundle adjustment problems to be ignored.
|
||||
|
||||
Change-Id: Ib137f1566acf5fffa63e50a55fe8e78ea9eb1c14
|
||||
|
||||
commit 602096c91363a0b9384f887a15c82e2dac1fb923
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Sun Oct 27 05:09:38 2013 -0700
|
||||
|
||||
Move CERES_HASH_NAMESPACE macros to collections_port.h
|
||||
|
||||
Now that we have a clearer understanding of the naming rules
|
||||
there is no need for these macro definitions to be done in
|
||||
the cmake file.
|
||||
|
||||
This cleans up the compilation command line.
|
||||
|
||||
Change-Id: Idc8fc7a7c9376e021dc4790af66e599105351917
|
||||
|
||||
commit f6b67df54ad6daa7036f5b6619243f722d678892
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Fri Oct 25 06:24:19 2013 -0700
|
||||
|
||||
Fix handling of unordered_map/unordered_set on OSX 10.9.0.
|
||||
|
||||
Depending on the compiler + standard library combination,
|
||||
unordered_map/set may or may not be available. If available
|
||||
they maybe in the std or the std::tr1 namespaces.
|
||||
|
||||
Apple switched to using libc++ with 10.9.0 which places
|
||||
unordered_map in std, breaking our assumptions about the
|
||||
platform.
|
||||
|
||||
This change refactors our logic for dealing with the namespace
|
||||
switching, making it a three state thing rather than two. There
|
||||
are three defines now, CERES_NO_UNORDERED_MAP, CERES_STD_UNORDERED_MAP
|
||||
and CERES_TR1_UNORDERED_MAP. Earlier the first two were conflated
|
||||
into one, leading to the breakage.
|
||||
|
||||
Change-Id: I904fe8c49529169bdefa9f2ee6d629e7eab0b855
|
||||
|
||||
commit 21d6a99fe68e99fa51db32d55f587b42ef9a476c
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Fri Oct 25 10:20:24 2013 -0700
|
||||
|
||||
Fix AngleAxisToRotationMatrix near zero.
|
||||
|
||||
The Taylor series approximation had its sign flipped and the
|
||||
tests did not catch it since we were switching exactly at zero,
|
||||
which was not getting triggered.
|
||||
|
||||
This changes modifies the tolerance, adds a test that triggers
|
||||
and fixes the bug.
|
||||
|
||||
Thanks to Michael Samples for reporting this.
|
||||
|
||||
Change-Id: I6f92f6348e5d4421ffe194fba92c04285449484c
|
||||
|
||||
commit 0e2743e24d013b25109396cfa0d8d0f1e8e84964
|
||||
Author: Sameer Agarwal <sameeragarwal@google.com>
|
||||
Date: Wed Oct 23 14:51:07 2013 -0700
|
||||
|
||||
Add BlockRandomAccessDiagonalMatrix.
|
||||
|
||||
This class is used in the SchurJacobiPreconditioner for
|
||||
storing the preconditioner matrix. Using it speeds up
|
||||
the computation of the preconditioner by ~15% due to
|
||||
the elimination of a hash table lookup.
|
||||
|
||||
Change-Id: Iba2b34aad0d9eb9bcb7f6e6fad16aa416aac0d2a
|
||||
|
||||
commit 6a2bcaa1d55d38bc10d043f1458657caac2be7a7
|
||||
Author: Alex Stewart <alexs.mac@gmail.com>
|
||||
Date: Wed Oct 23 14:06:44 2013 +0100
|
||||
|
||||
Adding explicit link to libm for pure-C curve fitting example.
|
||||
|
||||
- Any pure-C program #including <math.h> will need to link against
|
||||
libm, some compilers will let an indirect link slide (via Ceres in
|
||||
this case) but some won't.
|
||||
|
||||
Change-Id: I6890702fa0d2c3fbb747f0f81fc3fa3631839de4
|
||||
|
|
|
@ -714,14 +714,15 @@ class Solver {
|
|||
// termination.
|
||||
string FullReport() const;
|
||||
|
||||
bool IsSolutionUsable() const;
|
||||
|
||||
// Minimizer summary -------------------------------------------------
|
||||
MinimizerType minimizer_type;
|
||||
|
||||
SolverTerminationType termination_type;
|
||||
TerminationType termination_type;
|
||||
|
||||
// If the solver did not run, or there was a failure, a
|
||||
// description of the error.
|
||||
string error;
|
||||
// Reason why the solver terminated.
|
||||
string message;
|
||||
|
||||
// Cost of the problem (value of the objective function) before
|
||||
// the optimization.
|
||||
|
|
|
@ -301,41 +301,42 @@ enum DoglegType {
|
|||
SUBSPACE_DOGLEG
|
||||
};
|
||||
|
||||
enum SolverTerminationType {
|
||||
// The minimizer did not run at all; usually due to errors in the user's
|
||||
// Problem or the solver options.
|
||||
DID_NOT_RUN,
|
||||
enum TerminationType {
|
||||
// Minimizer terminated because one of the convergence criterion set
|
||||
// by the user was satisfied.
|
||||
//
|
||||
// 1. (new_cost - old_cost) < function_tolerance * old_cost;
|
||||
// 2. max_i |gradient_i| < gradient_tolerance * max_i|initial_gradient_i|
|
||||
// 3. |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
|
||||
//
|
||||
// The user's parameter blocks will be updated with the solution.
|
||||
CONVERGENCE,
|
||||
|
||||
// The solver ran for maximum number of iterations specified by the
|
||||
// user, but none of the convergence criterion specified by the user
|
||||
// were met.
|
||||
// The solver ran for maximum number of iterations or maximum amount
|
||||
// of time specified by the user, but none of the convergence
|
||||
// criterion specified by the user were met. The user's parameter
|
||||
// blocks will be updated with the solution found so far.
|
||||
NO_CONVERGENCE,
|
||||
|
||||
// Minimizer terminated because
|
||||
// (new_cost - old_cost) < function_tolerance * old_cost;
|
||||
FUNCTION_TOLERANCE,
|
||||
|
||||
// Minimizer terminated because
|
||||
// max_i |gradient_i| < gradient_tolerance * max_i|initial_gradient_i|
|
||||
GRADIENT_TOLERANCE,
|
||||
|
||||
// Minimized terminated because
|
||||
// |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
|
||||
PARAMETER_TOLERANCE,
|
||||
|
||||
// The minimizer terminated because it encountered a numerical error
|
||||
// that it could not recover from.
|
||||
NUMERICAL_FAILURE,
|
||||
// The minimizer terminated because of an error. The user's
|
||||
// parameter blocks will not be updated.
|
||||
FAILURE,
|
||||
|
||||
// Using an IterationCallback object, user code can control the
|
||||
// minimizer. The following enums indicate that the user code was
|
||||
// responsible for termination.
|
||||
//
|
||||
// Minimizer terminated successfully because a user
|
||||
// IterationCallback returned SOLVER_TERMINATE_SUCCESSFULLY.
|
||||
//
|
||||
// The user's parameter blocks will be updated with the solution.
|
||||
USER_SUCCESS,
|
||||
|
||||
// User's IterationCallback returned SOLVER_ABORT.
|
||||
USER_ABORT,
|
||||
|
||||
// User's IterationCallback returned SOLVER_TERMINATE_SUCCESSFULLY
|
||||
USER_SUCCESS
|
||||
// Minimizer terminated because because a user IterationCallback
|
||||
// returned SOLVER_ABORT.
|
||||
//
|
||||
// The user's parameter blocks will not be updated.
|
||||
USER_FAILURE
|
||||
};
|
||||
|
||||
// Enums used by the IterationCallback instances to indicate to the
|
||||
|
@ -459,7 +460,7 @@ bool StringToCovarianceAlgorithmType(
|
|||
string value,
|
||||
CovarianceAlgorithmType* type);
|
||||
|
||||
const char* SolverTerminationTypeToString(SolverTerminationType type);
|
||||
const char* TerminationTypeToString(TerminationType type);
|
||||
|
||||
bool IsSchurType(LinearSolverType type);
|
||||
bool IsSparseLinearAlgebraLibraryTypeAvailable(
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "ceres/compressed_row_sparse_matrix.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include "ceres/crs_matrix.h"
|
||||
#include "ceres/internal/port.h"
|
||||
|
@ -215,11 +216,28 @@ void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
|
|||
|
||||
num_rows_ -= delta_rows;
|
||||
rows_.resize(num_rows_ + 1);
|
||||
|
||||
// Walk the list of row blocks untill we reach the new number of
|
||||
// rows and then drop the rest of the row blocks.
|
||||
int num_row_blocks = 0;
|
||||
int num_rows = 0;
|
||||
while (num_row_blocks < row_blocks_.size() && num_rows < num_rows_) {
|
||||
num_rows += row_blocks_[num_row_blocks];
|
||||
++num_row_blocks;
|
||||
}
|
||||
|
||||
row_blocks_.resize(num_row_blocks);
|
||||
}
|
||||
|
||||
void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
|
||||
CHECK_EQ(m.num_cols(), num_cols_);
|
||||
|
||||
CHECK(row_blocks_.size() == 0 || m.row_blocks().size() !=0)
|
||||
<< "Cannot append a matrix with row blocks to one without and vice versa."
|
||||
<< "This matrix has : " << row_blocks_.size() << " row blocks."
|
||||
<< "The matrix being appended has: " << m.row_blocks().size()
|
||||
<< " row blocks.";
|
||||
|
||||
if (cols_.size() < num_nonzeros() + m.num_nonzeros()) {
|
||||
cols_.resize(num_nonzeros() + m.num_nonzeros());
|
||||
values_.resize(num_nonzeros() + m.num_nonzeros());
|
||||
|
@ -239,6 +257,7 @@ void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
|
|||
}
|
||||
|
||||
num_rows_ += m.num_rows();
|
||||
row_blocks_.insert(row_blocks_.end(), m.row_blocks().begin(), m.row_blocks().end());
|
||||
}
|
||||
|
||||
void CompressedRowSparseMatrix::ToTextFile(FILE* file) const {
|
||||
|
|
|
@ -441,23 +441,23 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSparseCholesky() {
|
|||
cholmod_jacobian_view.sorted = 1;
|
||||
cholmod_jacobian_view.packed = 1;
|
||||
|
||||
string status;
|
||||
cholmod_factor* factor = ss.AnalyzeCholesky(&cholmod_jacobian_view, &status);
|
||||
string message;
|
||||
cholmod_factor* factor = ss.AnalyzeCholesky(&cholmod_jacobian_view, &message);
|
||||
event_logger.AddEvent("Symbolic Factorization");
|
||||
if (factor == NULL) {
|
||||
LOG(ERROR) << "Covariance estimation failed. "
|
||||
<< "CHOLMOD symbolic cholesky factorization returned with: "
|
||||
<< status;
|
||||
<< message;
|
||||
return false;
|
||||
}
|
||||
|
||||
LinearSolverTerminationType termination_type =
|
||||
ss.Cholesky(&cholmod_jacobian_view, factor, &status);
|
||||
ss.Cholesky(&cholmod_jacobian_view, factor, &message);
|
||||
event_logger.AddEvent("Numeric Factorization");
|
||||
if (termination_type != LINEAR_SOLVER_SUCCESS) {
|
||||
LOG(ERROR) << "Covariance estimation failed. "
|
||||
<< "CHOLMOD numeric cholesky factorization returned with: "
|
||||
<< status;
|
||||
<< message;
|
||||
ss.Free(factor);
|
||||
return false;
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSparseCholesky() {
|
|||
LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
|
||||
<< "Reciprocal condition number: "
|
||||
<< reciprocal_condition_number << " "
|
||||
<< "min_reciprocal_condition_number : "
|
||||
<< "min_reciprocal_condition_number: "
|
||||
<< options_.min_reciprocal_condition_number;
|
||||
ss.Free(factor);
|
||||
return false;
|
||||
|
@ -506,7 +506,7 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSparseCholesky() {
|
|||
}
|
||||
|
||||
rhs_x[r] = 1.0;
|
||||
cholmod_dense* solution = ss.Solve(factor, rhs);
|
||||
cholmod_dense* solution = ss.Solve(factor, rhs, &message);
|
||||
double* solution_x = reinterpret_cast<double*>(solution->x);
|
||||
for (int idx = row_begin; idx < row_end; ++idx) {
|
||||
const int c = cols[idx];
|
||||
|
@ -822,7 +822,7 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
|
|||
LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
|
||||
<< "Reciprocal condition number: "
|
||||
<< singular_value_ratio * singular_value_ratio << " "
|
||||
<< "min_reciprocal_condition_number : "
|
||||
<< "min_reciprocal_condition_number: "
|
||||
<< options_.min_reciprocal_condition_number;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
|
|||
int num_rows,
|
||||
const double* in_lhs,
|
||||
double* rhs_and_solution,
|
||||
string* status) {
|
||||
string* message) {
|
||||
#ifdef CERES_NO_LAPACK
|
||||
LOG(FATAL) << "Ceres was built without a BLAS library.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
|
@ -91,10 +91,10 @@ LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
|
|||
}
|
||||
|
||||
if (info > 0) {
|
||||
*status =
|
||||
*message =
|
||||
StringPrintf(
|
||||
"LAPACK::dpotrf numerical failure. "
|
||||
"The leading minor of order %d is not positive definite.", info);
|
||||
"The leading minor of order %d is not positive definite.", info);
|
||||
return LINEAR_SOLVER_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
|
|||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
}
|
||||
|
||||
*status = "Success";
|
||||
*message = "Success";
|
||||
return LINEAR_SOLVER_SUCCESS;
|
||||
#endif
|
||||
};
|
||||
|
@ -138,7 +138,7 @@ int LAPACK::EstimateWorkSizeForQR(int num_rows, int num_cols) {
|
|||
LOG(FATAL) << "Congratulations, you found a bug in Ceres."
|
||||
<< "Please report it."
|
||||
<< "LAPACK::dgels fatal error."
|
||||
<< "Argument: " << info << " is invalid.";
|
||||
<< "Argument: " << -info << " is invalid.";
|
||||
}
|
||||
return static_cast<int>(work);
|
||||
#endif
|
||||
|
@ -151,7 +151,7 @@ LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
|
|||
int work_size,
|
||||
double* work,
|
||||
double* rhs_and_solution,
|
||||
string* status) {
|
||||
string* message) {
|
||||
#ifdef CERES_NO_LAPACK
|
||||
LOG(FATAL) << "Ceres was built without a LAPACK library.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
|
@ -184,7 +184,7 @@ LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
|
|||
<< "Argument: " << -info << " is invalid.";
|
||||
}
|
||||
|
||||
*status = "Success.";
|
||||
*message = "Success.";
|
||||
return LINEAR_SOLVER_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -51,14 +51,14 @@ class LAPACK {
|
|||
//
|
||||
// This function uses the LAPACK dpotrf and dpotrs routines.
|
||||
//
|
||||
// The return value and the status string together describe whether
|
||||
// The return value and the message string together describe whether
|
||||
// the solver terminated successfully or not and if so, what was the
|
||||
// reason for failure.
|
||||
static LinearSolverTerminationType SolveInPlaceUsingCholesky(
|
||||
int num_rows,
|
||||
const double* lhs,
|
||||
double* rhs_and_solution,
|
||||
string* status);
|
||||
string* message);
|
||||
|
||||
// The SolveUsingQR function requires a buffer for its temporary
|
||||
// computation. This function given the size of the lhs matrix will
|
||||
|
@ -81,7 +81,7 @@ class LAPACK {
|
|||
//
|
||||
// This function uses the LAPACK dgels routine.
|
||||
//
|
||||
// The return value and the status string together describe whether
|
||||
// The return value and the message string together describe whether
|
||||
// the solver terminated successfully or not and if so, what was the
|
||||
// reason for failure.
|
||||
static LinearSolverTerminationType SolveInPlaceUsingQR(
|
||||
|
@ -91,7 +91,7 @@ class LAPACK {
|
|||
int work_size,
|
||||
double* work,
|
||||
double* rhs_and_solution,
|
||||
string* status);
|
||||
string* message);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
@ -126,9 +126,9 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
|
||||
// Do initial cost and Jacobian evaluation.
|
||||
if (!Evaluate(evaluator, x, ¤t_state)) {
|
||||
summary->error = "Terminating: Cost and gradient evaluation failed.";
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->message = "Terminating: Cost and gradient evaluation failed.";
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -146,14 +146,14 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
options.gradient_tolerance * initial_gradient_max_norm;
|
||||
|
||||
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating: Gradient tolerance reached. "
|
||||
"Relative gradient max norm: %e <= %e",
|
||||
iteration_summary.gradient_max_norm /
|
||||
initial_gradient_max_norm,
|
||||
options.gradient_tolerance);
|
||||
summary->termination_type = GRADIENT_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -198,10 +198,10 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
scoped_ptr<LineSearch>
|
||||
line_search(LineSearch::Create(options.line_search_type,
|
||||
line_search_options,
|
||||
&summary->error));
|
||||
&summary->message));
|
||||
if (line_search.get() == NULL) {
|
||||
summary->termination_type = DID_NOT_RUN;
|
||||
LOG_IF(ERROR, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(ERROR, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -215,18 +215,18 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
|
||||
iteration_start_time = WallTimeInSeconds();
|
||||
if (iteration_summary.iteration >= options.max_num_iterations) {
|
||||
summary->error = "Terminating: Maximum number of iterations reached.";
|
||||
summary->message = "Terminating: Maximum number of iterations reached.";
|
||||
summary->termination_type = NO_CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
break;
|
||||
}
|
||||
|
||||
const double total_solver_time = iteration_start_time - start_time +
|
||||
summary->preprocessor_time_in_seconds;
|
||||
if (total_solver_time >= options.max_solver_time_in_seconds) {
|
||||
summary->error = "Terminating: Maximum solver time reached.";
|
||||
summary->message = "Terminating: Maximum solver time reached.";
|
||||
summary->termination_type = NO_CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -251,12 +251,12 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
// Line search direction failed to generate a new direction, and we
|
||||
// have already reached our specified maximum number of restarts,
|
||||
// terminate optimization.
|
||||
summary->error =
|
||||
StringPrintf("Termination: Line search direction failure: specified "
|
||||
summary->message =
|
||||
StringPrintf("Terminating: Line search direction failure: specified "
|
||||
"max_num_line_search_direction_restarts: %d reached.",
|
||||
options.max_num_line_search_direction_restarts);
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
break;
|
||||
} else if (!line_search_status) {
|
||||
// Restart line search direction with gradient descent on first iteration
|
||||
|
@ -299,14 +299,14 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
// direction in a line search, most likely cause for this being violated
|
||||
// would be a numerical failure in the line search direction calculation.
|
||||
if (initial_step_size < 0.0) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Numerical failure in line search, initial_step_size is "
|
||||
"negative: %.5e, directional_derivative: %.5e, "
|
||||
"(current_cost - previous_cost): %.5e",
|
||||
initial_step_size, current_state.directional_derivative,
|
||||
(current_state.cost - previous_state.cost));
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -315,15 +315,15 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
current_state.directional_derivative,
|
||||
&line_search_summary);
|
||||
if (!line_search_summary.success) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Numerical failure in line search, failed to find "
|
||||
"a valid step size, (did not run out of iterations) "
|
||||
"using initial_step_size: %.5e, initial_cost: %.5e, "
|
||||
"initial_gradient: %.5e.",
|
||||
initial_step_size, current_state.cost,
|
||||
current_state.directional_derivative);
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
summary->termination_type = FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -355,14 +355,14 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
|
||||
|
||||
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating: Gradient tolerance reached. "
|
||||
"Relative gradient max norm: %e <= %e. ",
|
||||
(iteration_summary.gradient_max_norm /
|
||||
initial_gradient_max_norm),
|
||||
options.gradient_tolerance);
|
||||
summary->termination_type = GRADIENT_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -370,14 +370,14 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
|
|||
const double absolute_function_tolerance =
|
||||
options.function_tolerance * previous_state.cost;
|
||||
if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating. Function tolerance reached. "
|
||||
"|cost_change|/cost: %e <= %e",
|
||||
fabs(iteration_summary.cost_change) /
|
||||
previous_state.cost,
|
||||
options.function_tolerance);
|
||||
summary->termination_type = FUNCTION_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,10 @@ enum LinearSolverTerminationType {
|
|||
// the linear system being poorly conditioned.
|
||||
LINEAR_SOLVER_FAILURE,
|
||||
|
||||
// Solver failed with a fatal error that cannot be recovered from.
|
||||
// Solver failed with a fatal error that cannot be recovered from,
|
||||
// e.g. CHOLMOD ran out of memory when computing the symbolic or
|
||||
// numeric factorization or an underlying library was called with
|
||||
// the wrong arguments.
|
||||
LINEAR_SOLVER_FATAL_ERROR
|
||||
};
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ bool Minimizer::RunCallbacks(const vector<IterationCallback*> callbacks,
|
|||
VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
|
||||
return false;
|
||||
case SOLVER_ABORT:
|
||||
summary->termination_type = USER_ABORT;
|
||||
summary->termination_type = USER_FAILURE;
|
||||
VLOG(1) << "Terminating: User callback returned USER_ABORT.";
|
||||
return false;
|
||||
default:
|
||||
|
|
|
@ -638,6 +638,9 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
|
|||
for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
|
||||
variable_parameter_blocks[i]->SetVarying();
|
||||
}
|
||||
|
||||
program_->SetParameterBlockStatePtrsToUserStatePtrs();
|
||||
program_->SetParameterOffsetsAndIndex();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -696,6 +699,8 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
|
|||
}
|
||||
}
|
||||
|
||||
program_->SetParameterBlockStatePtrsToUserStatePtrs();
|
||||
program_->SetParameterOffsetsAndIndex();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,36 @@ void Program::SetParameterOffsetsAndIndex() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Program::IsValid() const {
|
||||
for (int i = 0; i < residual_blocks_.size(); ++i) {
|
||||
const ResidualBlock* residual_block = residual_blocks_[i];
|
||||
if (residual_block->index() != i) {
|
||||
LOG(WARNING) << "Residual block: " << i
|
||||
<< " has incorrect index: " << residual_block->index();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int state_offset = 0;
|
||||
int delta_offset = 0;
|
||||
for (int i = 0; i < parameter_blocks_.size(); ++i) {
|
||||
const ParameterBlock* parameter_block = parameter_blocks_[i];
|
||||
if (parameter_block->index() != i ||
|
||||
parameter_block->state_offset() != state_offset ||
|
||||
parameter_block->delta_offset() != delta_offset) {
|
||||
LOG(WARNING) << "Parameter block: " << i
|
||||
<< "has incorrect indexing information: "
|
||||
<< parameter_block->ToString();
|
||||
return false;
|
||||
}
|
||||
|
||||
state_offset += parameter_blocks_[i]->Size();
|
||||
delta_offset += parameter_blocks_[i]->LocalSize();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Program::NumResidualBlocks() const {
|
||||
return residual_blocks_.size();
|
||||
}
|
||||
|
|
|
@ -99,6 +99,10 @@ class Program {
|
|||
// position of the parameter in the state and delta vector respectively.
|
||||
void SetParameterOffsetsAndIndex();
|
||||
|
||||
// Check if the internal state of the program (the indexing and the
|
||||
// offsets) are correct.
|
||||
bool IsValid() const;
|
||||
|
||||
// See problem.h for what these do.
|
||||
int NumParameterBlocks() const;
|
||||
int NumParameters() const;
|
||||
|
|
|
@ -85,8 +85,8 @@ Solver::Summary::Summary()
|
|||
// Invalid values for most fields, to ensure that we are not
|
||||
// accidentally reporting default values.
|
||||
: minimizer_type(TRUST_REGION),
|
||||
termination_type(DID_NOT_RUN),
|
||||
error("ceres::Solve was not called."),
|
||||
termination_type(FAILURE),
|
||||
message("ceres::Solve was not called."),
|
||||
initial_cost(-1.0),
|
||||
final_cost(-1.0),
|
||||
fixed_cost(-1.0),
|
||||
|
@ -131,64 +131,40 @@ Solver::Summary::Summary()
|
|||
max_lbfgs_rank(-1) {
|
||||
}
|
||||
|
||||
string Solver::Summary::BriefReport() const {
|
||||
string report = "Ceres Solver Report: ";
|
||||
if (termination_type == DID_NOT_RUN) {
|
||||
return report + "Termination: DID_NOT_RUN, because " + error;
|
||||
}
|
||||
|
||||
internal::StringAppendF(&report, "Iterations: %d",
|
||||
num_successful_steps + num_unsuccessful_steps);
|
||||
internal::StringAppendF(&report, ", Initial cost: %e", initial_cost);
|
||||
|
||||
// If the solver failed or was aborted, then the final_cost has no
|
||||
// meaning.
|
||||
if (termination_type != NUMERICAL_FAILURE &&
|
||||
termination_type != USER_ABORT) {
|
||||
internal::StringAppendF(&report, ", Final cost: %e", final_cost);
|
||||
}
|
||||
|
||||
internal::StringAppendF(&report, ", Termination: %s.",
|
||||
SolverTerminationTypeToString(termination_type));
|
||||
return report;
|
||||
};
|
||||
|
||||
using internal::StringAppendF;
|
||||
using internal::StringPrintf;
|
||||
|
||||
string Solver::Summary::BriefReport() const {
|
||||
return StringPrintf("Ceres Solver Report: "
|
||||
"Iterations: %d, "
|
||||
"Initial cost: %e, "
|
||||
"Final cost: %e, "
|
||||
"Termination: %s",
|
||||
num_successful_steps + num_unsuccessful_steps,
|
||||
initial_cost,
|
||||
final_cost,
|
||||
TerminationTypeToString(termination_type));
|
||||
};
|
||||
|
||||
string Solver::Summary::FullReport() const {
|
||||
string report =
|
||||
"\n"
|
||||
"Ceres Solver Report\n"
|
||||
"-------------------\n";
|
||||
|
||||
if (termination_type == DID_NOT_RUN) {
|
||||
StringAppendF(&report, " Original\n");
|
||||
StringAppendF(&report, "Parameter blocks % 10d\n", num_parameter_blocks);
|
||||
StringAppendF(&report, "Parameters % 10d\n", num_parameters);
|
||||
if (num_effective_parameters != num_parameters) {
|
||||
StringAppendF(&report, "Effective parameters% 10d\n", num_parameters);
|
||||
}
|
||||
|
||||
StringAppendF(&report, "Residual blocks % 10d\n",
|
||||
num_residual_blocks);
|
||||
StringAppendF(&report, "Residuals % 10d\n\n",
|
||||
num_residuals);
|
||||
} else {
|
||||
StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
|
||||
StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
|
||||
num_parameter_blocks, num_parameter_blocks_reduced);
|
||||
StringAppendF(&report, "Parameters % 25d% 25d\n",
|
||||
num_parameters, num_parameters_reduced);
|
||||
if (num_effective_parameters_reduced != num_parameters_reduced) {
|
||||
StringAppendF(&report, "Effective parameters% 25d% 25d\n",
|
||||
num_effective_parameters, num_effective_parameters_reduced);
|
||||
}
|
||||
StringAppendF(&report, "Residual blocks % 25d% 25d\n",
|
||||
num_residual_blocks, num_residual_blocks_reduced);
|
||||
StringAppendF(&report, "Residual % 25d% 25d\n",
|
||||
num_residuals, num_residuals_reduced);
|
||||
StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
|
||||
StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
|
||||
num_parameter_blocks, num_parameter_blocks_reduced);
|
||||
StringAppendF(&report, "Parameters % 25d% 25d\n",
|
||||
num_parameters, num_parameters_reduced);
|
||||
if (num_effective_parameters_reduced != num_parameters_reduced) {
|
||||
StringAppendF(&report, "Effective parameters% 25d% 25d\n",
|
||||
num_effective_parameters, num_effective_parameters_reduced);
|
||||
}
|
||||
StringAppendF(&report, "Residual blocks % 25d% 25d\n",
|
||||
num_residual_blocks, num_residual_blocks_reduced);
|
||||
StringAppendF(&report, "Residual % 25d% 25d\n",
|
||||
num_residuals, num_residuals_reduced);
|
||||
|
||||
if (minimizer_type == TRUST_REGION) {
|
||||
// TRUST_SEARCH HEADER
|
||||
|
@ -314,17 +290,10 @@ string Solver::Summary::FullReport() const {
|
|||
num_threads_given, num_threads_used);
|
||||
}
|
||||
|
||||
if (termination_type == DID_NOT_RUN) {
|
||||
StringAppendF(&report, "Termination: %20s\n",
|
||||
"DID_NOT_RUN");
|
||||
StringAppendF(&report, "Reason: %s\n", error.c_str());
|
||||
return report;
|
||||
}
|
||||
|
||||
StringAppendF(&report, "\nCost:\n");
|
||||
StringAppendF(&report, "Initial % 30e\n", initial_cost);
|
||||
if (termination_type != NUMERICAL_FAILURE &&
|
||||
termination_type != USER_ABORT) {
|
||||
if (termination_type != FAILURE &&
|
||||
termination_type != USER_FAILURE) {
|
||||
StringAppendF(&report, "Final % 30e\n", final_cost);
|
||||
StringAppendF(&report, "Change % 30e\n",
|
||||
initial_cost - final_cost);
|
||||
|
@ -376,8 +345,14 @@ string Solver::Summary::FullReport() const {
|
|||
total_time_in_seconds);
|
||||
|
||||
StringAppendF(&report, "Termination: %25s\n",
|
||||
SolverTerminationTypeToString(termination_type));
|
||||
TerminationTypeToString(termination_type));
|
||||
return report;
|
||||
};
|
||||
|
||||
bool Solver::Summary::IsSolutionUsable() const {
|
||||
return (termination_type == CONVERGENCE ||
|
||||
termination_type == NO_CONVERGENCE ||
|
||||
termination_type == USER_SUCCESS);
|
||||
}
|
||||
|
||||
} // namespace ceres
|
||||
|
|
|
@ -208,6 +208,22 @@ void SummarizeOrdering(ParameterBlockOrdering* ordering,
|
|||
}
|
||||
}
|
||||
|
||||
void SummarizeGivenProgram(const Program& program, Solver::Summary* summary) {
|
||||
summary->num_parameter_blocks = program.NumParameterBlocks();
|
||||
summary->num_parameters = program.NumParameters();
|
||||
summary->num_effective_parameters = program.NumEffectiveParameters();
|
||||
summary->num_residual_blocks = program.NumResidualBlocks();
|
||||
summary->num_residuals = program.NumResiduals();
|
||||
}
|
||||
|
||||
void SummarizeReducedProgram(const Program& program, Solver::Summary* summary) {
|
||||
summary->num_parameter_blocks_reduced = program.NumParameterBlocks();
|
||||
summary->num_parameters_reduced = program.NumParameters();
|
||||
summary->num_effective_parameters_reduced = program.NumEffectiveParameters();
|
||||
summary->num_residual_blocks_reduced = program.NumResidualBlocks();
|
||||
summary->num_residuals_reduced = program.NumResiduals();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SolverImpl::TrustRegionMinimize(
|
||||
|
@ -351,29 +367,10 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
*CHECK_NOTNULL(summary) = Solver::Summary();
|
||||
|
||||
summary->minimizer_type = TRUST_REGION;
|
||||
summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
|
||||
summary->num_parameters = problem_impl->NumParameters();
|
||||
summary->num_effective_parameters =
|
||||
original_program->NumEffectiveParameters();
|
||||
summary->num_residual_blocks = problem_impl->NumResidualBlocks();
|
||||
summary->num_residuals = problem_impl->NumResiduals();
|
||||
|
||||
// Empty programs are usually a user error.
|
||||
if (summary->num_parameter_blocks == 0) {
|
||||
summary->error = "Problem contains no parameter blocks.";
|
||||
LOG(ERROR) << summary->error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (summary->num_residual_blocks == 0) {
|
||||
summary->error = "Problem contains no residual blocks.";
|
||||
LOG(ERROR) << summary->error;
|
||||
return;
|
||||
}
|
||||
|
||||
SummarizeGivenProgram(*original_program, summary);
|
||||
SummarizeOrdering(original_options.linear_solver_ordering,
|
||||
&(summary->linear_solver_ordering_given));
|
||||
|
||||
SummarizeOrdering(original_options.inner_iteration_ordering,
|
||||
&(summary->inner_iteration_ordering_given));
|
||||
|
||||
|
@ -404,9 +401,9 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
|
||||
options.trust_region_problem_dump_format_type != CONSOLE &&
|
||||
options.trust_region_problem_dump_directory.empty()) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
"Solver::Options::trust_region_problem_dump_directory is empty.";
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -434,8 +431,8 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
}
|
||||
|
||||
if (original_options.linear_solver_ordering != NULL) {
|
||||
if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
|
||||
LOG(ERROR) << summary->error;
|
||||
if (!IsOrderingValid(original_options, problem_impl, &summary->message)) {
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
event_logger.AddEvent("CheckOrdering");
|
||||
|
@ -466,7 +463,7 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
|
||||
problem_impl,
|
||||
&summary->fixed_cost,
|
||||
&summary->error));
|
||||
&summary->message));
|
||||
|
||||
event_logger.AddEvent("CreateReducedProgram");
|
||||
if (reduced_program == NULL) {
|
||||
|
@ -475,30 +472,23 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
|
||||
SummarizeOrdering(options.linear_solver_ordering,
|
||||
&(summary->linear_solver_ordering_used));
|
||||
|
||||
summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
|
||||
summary->num_parameters_reduced = reduced_program->NumParameters();
|
||||
summary->num_effective_parameters_reduced =
|
||||
reduced_program->NumEffectiveParameters();
|
||||
summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
|
||||
summary->num_residuals_reduced = reduced_program->NumResiduals();
|
||||
SummarizeReducedProgram(*reduced_program, summary);
|
||||
|
||||
if (summary->num_parameter_blocks_reduced == 0) {
|
||||
summary->preprocessor_time_in_seconds =
|
||||
WallTimeInSeconds() - solver_start_time;
|
||||
|
||||
double post_process_start_time = WallTimeInSeconds();
|
||||
LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
|
||||
<< "No non-constant parameter blocks found.";
|
||||
|
||||
summary->message =
|
||||
"Terminating: Function tolerance reached. "
|
||||
"No non-constant parameter blocks found.";
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG(1) << summary->message;
|
||||
|
||||
summary->initial_cost = summary->fixed_cost;
|
||||
summary->final_cost = summary->fixed_cost;
|
||||
|
||||
// FUNCTION_TOLERANCE is the right convergence here, as we know
|
||||
// that the objective function is constant and cannot be changed
|
||||
// any further.
|
||||
summary->termination_type = FUNCTION_TOLERANCE;
|
||||
|
||||
// Ensure the program state is set to the user parameters on the way out.
|
||||
original_program->SetParameterBlockStatePtrsToUserStatePtrs();
|
||||
original_program->SetParameterOffsetsAndIndex();
|
||||
|
@ -509,7 +499,7 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
}
|
||||
|
||||
scoped_ptr<LinearSolver>
|
||||
linear_solver(CreateLinearSolver(&options, &summary->error));
|
||||
linear_solver(CreateLinearSolver(&options, &summary->message));
|
||||
event_logger.AddEvent("CreateLinearSolver");
|
||||
if (linear_solver == NULL) {
|
||||
return;
|
||||
|
@ -536,7 +526,7 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
|
||||
problem_impl->parameter_map(),
|
||||
reduced_program.get(),
|
||||
&summary->error));
|
||||
&summary->message));
|
||||
|
||||
event_logger.AddEvent("CreateEvaluator");
|
||||
|
||||
|
@ -556,7 +546,7 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
problem_impl->parameter_map(),
|
||||
summary));
|
||||
if (inner_iteration_minimizer == NULL) {
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -590,8 +580,8 @@ void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
|
|||
// If the user aborted mid-optimization or the optimization
|
||||
// terminated because of a numerical failure, then return without
|
||||
// updating user state.
|
||||
if (summary->termination_type == USER_ABORT ||
|
||||
summary->termination_type == NUMERICAL_FAILURE) {
|
||||
if (summary->termination_type == USER_FAILURE ||
|
||||
summary->termination_type == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -642,6 +632,8 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
*CHECK_NOTNULL(summary) = Solver::Summary();
|
||||
|
||||
summary->minimizer_type = LINE_SEARCH;
|
||||
SummarizeGivenProgram(*original_program, summary);
|
||||
|
||||
summary->line_search_direction_type =
|
||||
original_options.line_search_direction_type;
|
||||
summary->max_lbfgs_rank = original_options.max_lbfgs_rank;
|
||||
|
@ -651,56 +643,50 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
summary->nonlinear_conjugate_gradient_type =
|
||||
original_options.nonlinear_conjugate_gradient_type;
|
||||
|
||||
summary->num_parameter_blocks = original_program->NumParameterBlocks();
|
||||
summary->num_parameters = original_program->NumParameters();
|
||||
summary->num_residual_blocks = original_program->NumResidualBlocks();
|
||||
summary->num_residuals = original_program->NumResiduals();
|
||||
summary->num_effective_parameters =
|
||||
original_program->NumEffectiveParameters();
|
||||
|
||||
// Validate values for configuration parameters supplied by user.
|
||||
if ((original_options.line_search_direction_type == ceres::BFGS ||
|
||||
original_options.line_search_direction_type == ceres::LBFGS) &&
|
||||
original_options.line_search_type != ceres::WOLFE) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
string("Invalid configuration: require line_search_type == "
|
||||
"ceres::WOLFE when using (L)BFGS to ensure that underlying "
|
||||
"assumptions are guaranteed to be satisfied.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.max_lbfgs_rank <= 0) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
string("Invalid configuration: require max_lbfgs_rank > 0");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.min_line_search_step_size <= 0.0) {
|
||||
summary->error = "Invalid configuration: min_line_search_step_size <= 0.0.";
|
||||
LOG(ERROR) << summary->error;
|
||||
summary->message =
|
||||
"Invalid configuration: min_line_search_step_size <= 0.0.";
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.line_search_sufficient_function_decrease <= 0.0) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
string("Invalid configuration: require ") +
|
||||
string("line_search_sufficient_function_decrease <= 0.0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.max_line_search_step_contraction <= 0.0 ||
|
||||
original_options.max_line_search_step_contraction >= 1.0) {
|
||||
summary->error = string("Invalid configuration: require ") +
|
||||
summary->message = string("Invalid configuration: require ") +
|
||||
string("0.0 < max_line_search_step_contraction < 1.0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.min_line_search_step_contraction <=
|
||||
original_options.max_line_search_step_contraction ||
|
||||
original_options.min_line_search_step_contraction > 1.0) {
|
||||
summary->error = string("Invalid configuration: require ") +
|
||||
summary->message = string("Invalid configuration: require ") +
|
||||
string("max_line_search_step_contraction < ") +
|
||||
string("min_line_search_step_contraction <= 1.0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
// Warn user if they have requested BISECTION interpolation, but constraints
|
||||
|
@ -718,37 +704,24 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
<< original_options.min_line_search_step_contraction
|
||||
<< ", prevent bisection (0.5) scaling, continuing with solve regardless.";
|
||||
if (original_options.max_num_line_search_step_size_iterations <= 0) {
|
||||
summary->error = string("Invalid configuration: require ") +
|
||||
summary->message = string("Invalid configuration: require ") +
|
||||
string("max_num_line_search_step_size_iterations > 0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.line_search_sufficient_curvature_decrease <=
|
||||
original_options.line_search_sufficient_function_decrease ||
|
||||
original_options.line_search_sufficient_curvature_decrease > 1.0) {
|
||||
summary->error = string("Invalid configuration: require ") +
|
||||
summary->message = string("Invalid configuration: require ") +
|
||||
string("line_search_sufficient_function_decrease < ") +
|
||||
string("line_search_sufficient_curvature_decrease < 1.0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
if (original_options.max_line_search_step_expansion <= 1.0) {
|
||||
summary->error = string("Invalid configuration: require ") +
|
||||
summary->message = string("Invalid configuration: require ") +
|
||||
string("max_line_search_step_expansion > 1.0.");
|
||||
LOG(ERROR) << summary->error;
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty programs are usually a user error.
|
||||
if (summary->num_parameter_blocks == 0) {
|
||||
summary->error = "Problem contains no parameter blocks.";
|
||||
LOG(ERROR) << summary->error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (summary->num_residual_blocks == 0) {
|
||||
summary->error = "Problem contains no residual blocks.";
|
||||
LOG(ERROR) << summary->error;
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -759,7 +732,6 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
// refactored to deal with the various bits of cleanups related to
|
||||
// line search.
|
||||
options.linear_solver_type = CGNR;
|
||||
|
||||
options.linear_solver_ordering = NULL;
|
||||
options.inner_iteration_ordering = NULL;
|
||||
|
||||
|
@ -777,8 +749,8 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
summary->num_threads_used = options.num_threads;
|
||||
|
||||
if (original_options.linear_solver_ordering != NULL) {
|
||||
if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
|
||||
LOG(ERROR) << summary->error;
|
||||
if (!IsOrderingValid(original_options, problem_impl, &summary->message)) {
|
||||
LOG(ERROR) << summary->message;
|
||||
return;
|
||||
}
|
||||
options.linear_solver_ordering =
|
||||
|
@ -819,32 +791,23 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
|
||||
problem_impl,
|
||||
&summary->fixed_cost,
|
||||
&summary->error));
|
||||
&summary->message));
|
||||
if (reduced_program == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
|
||||
summary->num_parameters_reduced = reduced_program->NumParameters();
|
||||
summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
|
||||
summary->num_effective_parameters_reduced =
|
||||
reduced_program->NumEffectiveParameters();
|
||||
summary->num_residuals_reduced = reduced_program->NumResiduals();
|
||||
|
||||
SummarizeReducedProgram(*reduced_program, summary);
|
||||
if (summary->num_parameter_blocks_reduced == 0) {
|
||||
summary->preprocessor_time_in_seconds =
|
||||
WallTimeInSeconds() - solver_start_time;
|
||||
|
||||
LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
|
||||
<< "No non-constant parameter blocks found.";
|
||||
|
||||
// FUNCTION_TOLERANCE is the right convergence here, as we know
|
||||
// that the objective function is constant and cannot be changed
|
||||
// any further.
|
||||
summary->termination_type = FUNCTION_TOLERANCE;
|
||||
summary->message =
|
||||
"Terminating: Function tolerance reached. "
|
||||
"No non-constant parameter blocks found.";
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG(1) << summary->message;
|
||||
|
||||
const double post_process_start_time = WallTimeInSeconds();
|
||||
|
||||
SetSummaryFinalCost(summary);
|
||||
|
||||
// Ensure the program state is set to the user parameters on the way out.
|
||||
|
@ -859,7 +822,7 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
|
||||
problem_impl->parameter_map(),
|
||||
reduced_program.get(),
|
||||
&summary->error));
|
||||
&summary->message));
|
||||
if (evaluator == NULL) {
|
||||
return;
|
||||
}
|
||||
|
@ -886,8 +849,8 @@ void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
|
|||
// If the user aborted mid-optimization or the optimization
|
||||
// terminated because of a numerical failure, then return without
|
||||
// updating user state.
|
||||
if (summary->termination_type == USER_ABORT ||
|
||||
summary->termination_type == NUMERICAL_FAILURE) {
|
||||
if (summary->termination_type == USER_FAILURE ||
|
||||
summary->termination_type == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1456,7 +1419,7 @@ CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer(
|
|||
for ( ; it != group_to_elements.end(); ++it) {
|
||||
if (!IsParameterBlockSetIndependent(it->second,
|
||||
program.residual_blocks())) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("The user-provided "
|
||||
"parameter_blocks_for_inner_iterations does not "
|
||||
"form an independent set. Group Id: %d", it->first);
|
||||
|
@ -1469,7 +1432,7 @@ CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer(
|
|||
if (!inner_iteration_minimizer->Init(program,
|
||||
parameter_map,
|
||||
*ordering_ptr,
|
||||
&summary->error)) {
|
||||
&summary->message)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ class SolverImpl {
|
|||
static Program* CreateReducedProgram(Solver::Options* options,
|
||||
ProblemImpl* problem_impl,
|
||||
double* fixed_cost,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Create the appropriate linear solver, taking into account any
|
||||
// config changes decided by CreateTransformedProgram(). The
|
||||
|
@ -101,7 +101,7 @@ class SolverImpl {
|
|||
// selected; consider the case that the remaining elimininated
|
||||
// blocks is zero after removing fixed blocks.
|
||||
static LinearSolver* CreateLinearSolver(Solver::Options* options,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Reorder the residuals for program, if necessary, so that the
|
||||
// residuals involving e block (i.e., the first num_eliminate_block
|
||||
|
@ -110,14 +110,14 @@ class SolverImpl {
|
|||
static bool LexicographicallyOrderResidualBlocks(
|
||||
const int num_eliminate_blocks,
|
||||
Program* program,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Create the appropriate evaluator for the transformed program.
|
||||
static Evaluator* CreateEvaluator(
|
||||
const Solver::Options& options,
|
||||
const ProblemImpl::ParameterMap& parameter_map,
|
||||
Program* program,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Remove the fixed or unused parameter blocks and residuals
|
||||
// depending only on fixed parameters from the program.
|
||||
|
@ -131,17 +131,17 @@ class SolverImpl {
|
|||
// fixed_cost.
|
||||
//
|
||||
// If a failure is encountered, the function returns false with a
|
||||
// description of the failure in error.
|
||||
// description of the failure in message.
|
||||
static bool RemoveFixedBlocksFromProgram(
|
||||
Program* program,
|
||||
ParameterBlockOrdering* linear_solver_ordering,
|
||||
ParameterBlockOrdering* inner_iteration_ordering,
|
||||
double* fixed_cost,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
static bool IsOrderingValid(const Solver::Options& options,
|
||||
const ProblemImpl* problem_impl,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
static bool IsParameterBlockSetIndependent(
|
||||
const set<double*>& parameter_block_ptrs,
|
||||
|
@ -176,7 +176,7 @@ class SolverImpl {
|
|||
const ProblemImpl::ParameterMap& parameter_map,
|
||||
const ParameterBlockOrdering* parameter_block_ordering,
|
||||
Program* program,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Sparse cholesky factorization routines when doing the sparse
|
||||
// cholesky factorization of the Jacobian matrix, reorders its
|
||||
|
@ -192,7 +192,7 @@ class SolverImpl {
|
|||
const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
|
||||
const ParameterBlockOrdering* parameter_block_ordering,
|
||||
Program* program,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// Schur type solvers require that all parameter blocks eliminated
|
||||
// by the Schur eliminator occur before others and the residuals be
|
||||
|
@ -216,7 +216,7 @@ class SolverImpl {
|
|||
const ProblemImpl::ParameterMap& parameter_map,
|
||||
ParameterBlockOrdering* parameter_block_ordering,
|
||||
Program* program,
|
||||
string* error);
|
||||
string* message);
|
||||
|
||||
// array contains a list of (possibly repeating) non-negative
|
||||
// integers. Let us assume that we have constructed another array
|
||||
|
|
|
@ -112,8 +112,15 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
|
|||
if (per_solve_options.D != NULL) {
|
||||
// Temporarily append a diagonal block to the A matrix, but undo
|
||||
// it before returning the matrix to the user.
|
||||
CompressedRowSparseMatrix D(per_solve_options.D, num_cols);
|
||||
A->AppendRows(D);
|
||||
scoped_ptr<CompressedRowSparseMatrix> regularizer;
|
||||
if (A->col_blocks().size() > 0) {
|
||||
regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
|
||||
per_solve_options.D, A->col_blocks()));
|
||||
} else {
|
||||
regularizer.reset(new CompressedRowSparseMatrix(
|
||||
per_solve_options.D, num_cols));
|
||||
}
|
||||
A->AppendRows(*regularizer);
|
||||
}
|
||||
|
||||
VectorRef(x, num_cols).setZero();
|
||||
|
@ -196,8 +203,15 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
|
|||
if (per_solve_options.D != NULL) {
|
||||
// Temporarily append a diagonal block to the A matrix, but undo
|
||||
// it before returning the matrix to the user.
|
||||
CompressedRowSparseMatrix D(per_solve_options.D, num_cols);
|
||||
A->AppendRows(D);
|
||||
scoped_ptr<CompressedRowSparseMatrix> regularizer;
|
||||
if (A->col_blocks().size() > 0) {
|
||||
regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
|
||||
per_solve_options.D, A->col_blocks()));
|
||||
} else {
|
||||
regularizer.reset(new CompressedRowSparseMatrix(
|
||||
per_solve_options.D, num_cols));
|
||||
}
|
||||
A->AppendRows(*regularizer);
|
||||
}
|
||||
|
||||
VectorRef(x, num_cols).setZero();
|
||||
|
|
|
@ -122,7 +122,7 @@ cholmod_dense* SuiteSparse::CreateDenseVector(const double* x,
|
|||
}
|
||||
|
||||
cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
|
||||
string* status) {
|
||||
string* message) {
|
||||
// Cholmod can try multiple re-ordering strategies to find a fill
|
||||
// reducing ordering. Here we just tell it use AMD with automatic
|
||||
// matrix dependence choice of supernodal versus simplicial
|
||||
|
@ -137,8 +137,8 @@ cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
|
|||
}
|
||||
|
||||
if (cc_.status != CHOLMOD_OK) {
|
||||
*status = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
*message = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -149,18 +149,18 @@ cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(
|
|||
cholmod_sparse* A,
|
||||
const vector<int>& row_blocks,
|
||||
const vector<int>& col_blocks,
|
||||
string* status) {
|
||||
string* message) {
|
||||
vector<int> ordering;
|
||||
if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) {
|
||||
return NULL;
|
||||
}
|
||||
return AnalyzeCholeskyWithUserOrdering(A, ordering, status);
|
||||
return AnalyzeCholeskyWithUserOrdering(A, ordering, message);
|
||||
}
|
||||
|
||||
cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
|
||||
cholmod_sparse* A,
|
||||
const vector<int>& ordering,
|
||||
string* status) {
|
||||
string* message) {
|
||||
CHECK_EQ(ordering.size(), A->nrow);
|
||||
|
||||
cc_.nmethods = 1;
|
||||
|
@ -172,8 +172,8 @@ cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
|
|||
cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
|
||||
}
|
||||
if (cc_.status != CHOLMOD_OK) {
|
||||
*status = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
*message = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
|
|||
|
||||
cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
|
||||
cholmod_sparse* A,
|
||||
string* status) {
|
||||
string* message) {
|
||||
cc_.nmethods = 1;
|
||||
cc_.method[0].ordering = CHOLMOD_NATURAL;
|
||||
cc_.postorder = 0;
|
||||
|
@ -192,8 +192,8 @@ cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
|
|||
cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
|
||||
}
|
||||
if (cc_.status != CHOLMOD_OK) {
|
||||
*status = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
*message = StringPrintf("cholmod_analyze failed. error code: %d",
|
||||
cc_.status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A,
|
|||
|
||||
LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
|
||||
cholmod_factor* L,
|
||||
string* status) {
|
||||
string* message) {
|
||||
CHECK_NOTNULL(A);
|
||||
CHECK_NOTNULL(L);
|
||||
|
||||
|
@ -268,22 +268,22 @@ LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
|
|||
// (e.g. out of memory).
|
||||
switch (cc_.status) {
|
||||
case CHOLMOD_NOT_INSTALLED:
|
||||
*status = "CHOLMOD failure: Method not installed.";
|
||||
*message = "CHOLMOD failure: Method not installed.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
case CHOLMOD_OUT_OF_MEMORY:
|
||||
*status = "CHOLMOD failure: Out of memory.";
|
||||
*message = "CHOLMOD failure: Out of memory.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
case CHOLMOD_TOO_LARGE:
|
||||
*status = "CHOLMOD failure: Integer overflow occured.";
|
||||
*message = "CHOLMOD failure: Integer overflow occured.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
case CHOLMOD_INVALID:
|
||||
*status = "CHOLMOD failure: Invalid input.";
|
||||
*message = "CHOLMOD failure: Invalid input.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
case CHOLMOD_NOT_POSDEF:
|
||||
*status = "CHOLMOD warning: Matrix not positive definite.";
|
||||
*message = "CHOLMOD warning: Matrix not positive definite.";
|
||||
return LINEAR_SOLVER_FAILURE;
|
||||
case CHOLMOD_DSMALL:
|
||||
*status = "CHOLMOD warning: D for LDL' or diag(L) or "
|
||||
*message = "CHOLMOD warning: D for LDL' or diag(L) or "
|
||||
"LL' has tiny absolute value.";
|
||||
return LINEAR_SOLVER_FAILURE;
|
||||
case CHOLMOD_OK:
|
||||
|
@ -291,12 +291,12 @@ LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
|
|||
return LINEAR_SOLVER_SUCCESS;
|
||||
}
|
||||
|
||||
*status = "CHOLMOD failure: cholmod_factorize returned false "
|
||||
"but cholmod_common::status is CHOLMOD_OK."
|
||||
"Please report this to ceres-solver@googlegroups.com.";
|
||||
*message = "CHOLMOD failure: cholmod_factorize returned false "
|
||||
"but cholmod_common::status is CHOLMOD_OK."
|
||||
"Please report this to ceres-solver@googlegroups.com.";
|
||||
return LINEAR_SOLVER_FATAL_ERROR;
|
||||
default:
|
||||
*status =
|
||||
*message =
|
||||
StringPrintf("Unknown cholmod return code: %d. "
|
||||
"Please report this to ceres-solver@googlegroups.com.",
|
||||
cc_.status);
|
||||
|
@ -308,9 +308,9 @@ LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
|
|||
|
||||
cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
|
||||
cholmod_dense* b,
|
||||
string* status) {
|
||||
string* message) {
|
||||
if (cc_.status != CHOLMOD_OK) {
|
||||
*status = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
|
||||
*message = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -139,15 +139,15 @@ class SuiteSparse {
|
|||
// A is not modified, only the pattern of non-zeros of A is used,
|
||||
// the actual numerical values in A are of no consequence.
|
||||
//
|
||||
// status contains an explanation of the failures if any.
|
||||
// message contains an explanation of the failures if any.
|
||||
//
|
||||
// Caller owns the result.
|
||||
cholmod_factor* AnalyzeCholesky(cholmod_sparse* A, string* status);
|
||||
cholmod_factor* AnalyzeCholesky(cholmod_sparse* A, string* message);
|
||||
|
||||
cholmod_factor* BlockAnalyzeCholesky(cholmod_sparse* A,
|
||||
const vector<int>& row_blocks,
|
||||
const vector<int>& col_blocks,
|
||||
string* status);
|
||||
string* message);
|
||||
|
||||
// If A is symmetric, then compute the symbolic Cholesky
|
||||
// factorization of A(ordering, ordering). If A is unsymmetric, then
|
||||
|
@ -157,38 +157,38 @@ class SuiteSparse {
|
|||
// A is not modified, only the pattern of non-zeros of A is used,
|
||||
// the actual numerical values in A are of no consequence.
|
||||
//
|
||||
// status contains an explanation of the failures if any.
|
||||
// message contains an explanation of the failures if any.
|
||||
//
|
||||
// Caller owns the result.
|
||||
cholmod_factor* AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A,
|
||||
const vector<int>& ordering,
|
||||
string* status);
|
||||
string* message);
|
||||
|
||||
// Perform a symbolic factorization of A without re-ordering A. No
|
||||
// postordering of the elimination tree is performed. This ensures
|
||||
// that the symbolic factor does not introduce an extra permutation
|
||||
// on the matrix. See the documentation for CHOLMOD for more details.
|
||||
//
|
||||
// status contains an explanation of the failures if any.
|
||||
// message contains an explanation of the failures if any.
|
||||
cholmod_factor* AnalyzeCholeskyWithNaturalOrdering(cholmod_sparse* A,
|
||||
string* status);
|
||||
string* message);
|
||||
|
||||
// Use the symbolic factorization in L, to find the numerical
|
||||
// factorization for the matrix A or AA^T. Return true if
|
||||
// successful, false otherwise. L contains the numeric factorization
|
||||
// on return.
|
||||
//
|
||||
// status contains an explanation of the failures if any.
|
||||
// message contains an explanation of the failures if any.
|
||||
LinearSolverTerminationType Cholesky(cholmod_sparse* A,
|
||||
cholmod_factor* L,
|
||||
string* status);
|
||||
string* message);
|
||||
|
||||
// Given a Cholesky factorization of a matrix A = LL^T, solve the
|
||||
// linear system Ax = b, and return the result. If the Solve fails
|
||||
// NULL is returned. Caller owns the result.
|
||||
//
|
||||
// status contains an explanation of the failures if any.
|
||||
cholmod_dense* Solve(cholmod_factor* L, cholmod_dense* b, string* solve);
|
||||
// message contains an explanation of the failures if any.
|
||||
cholmod_dense* Solve(cholmod_factor* L, cholmod_dense* b, string* message);
|
||||
|
||||
// By virtue of the modeling layer in Ceres being block oriented,
|
||||
// all the matrices used by Ceres are also block oriented. When
|
||||
|
|
|
@ -128,9 +128,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
residuals.data(),
|
||||
gradient.data(),
|
||||
jacobian)) {
|
||||
summary->error = "Terminating: Residual and Jacobian evaluation failed.";
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->message = "Terminating: Residual and Jacobian evaluation failed.";
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -154,13 +154,13 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
options_.gradient_tolerance * initial_gradient_max_norm;
|
||||
|
||||
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
|
||||
summary->error = StringPrintf("Terminating: Gradient tolerance reached. "
|
||||
"Relative gradient max norm: %e <= %e",
|
||||
(iteration_summary.gradient_max_norm /
|
||||
initial_gradient_max_norm),
|
||||
options_.gradient_tolerance);
|
||||
summary->termination_type = GRADIENT_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->message = StringPrintf("Terminating: Gradient tolerance reached. "
|
||||
"Relative gradient max norm: %e <= %e",
|
||||
(iteration_summary.gradient_max_norm /
|
||||
initial_gradient_max_norm),
|
||||
options_.gradient_tolerance);
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -188,18 +188,18 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
|
||||
iteration_start_time = WallTimeInSeconds();
|
||||
if (iteration_summary.iteration >= options_.max_num_iterations) {
|
||||
summary->error = "Terminating: Maximum number of iterations reached.";
|
||||
summary->message = "Terminating: Maximum number of iterations reached.";
|
||||
summary->termination_type = NO_CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
const double total_solver_time = iteration_start_time - start_time +
|
||||
summary->preprocessor_time_in_seconds;
|
||||
if (total_solver_time >= options_.max_solver_time_in_seconds) {
|
||||
summary->error = "Terminating: Maximum solver time reached.";
|
||||
summary->message = "Terminating: Maximum solver time reached.";
|
||||
summary->termination_type = NO_CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -228,11 +228,11 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
trust_region_step.data());
|
||||
|
||||
if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
"Terminating. Linear solver failed due to unrecoverable "
|
||||
"non-numeric causes. Please see the error log for clues. ";
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -245,15 +245,6 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
iteration_summary.step_is_valid = false;
|
||||
iteration_summary.step_is_successful = false;
|
||||
|
||||
if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
|
||||
summary->error =
|
||||
"Terminating. Linear solver failed due to unrecoverable "
|
||||
"non-numeric causes. Please see the error log for clues. ";
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
return;
|
||||
}
|
||||
|
||||
double model_cost_change = 0.0;
|
||||
if (strategy_summary.termination_type != LINEAR_SOLVER_FAILURE) {
|
||||
// new_model_cost
|
||||
|
@ -281,15 +272,15 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
if (!iteration_summary.step_is_valid) {
|
||||
// Invalid steps can happen due to a number of reasons, and we
|
||||
// allow a limited number of successive failures, and return with
|
||||
// NUMERICAL_FAILURE if this limit is exceeded.
|
||||
// FAILURE if this limit is exceeded.
|
||||
if (++num_consecutive_invalid_steps >=
|
||||
options_.max_num_consecutive_invalid_steps) {
|
||||
summary->error = StringPrintf(
|
||||
summary->message = StringPrintf(
|
||||
"Terminating. Number of successive invalid steps more "
|
||||
"than Solver::Options::max_num_consecutive_invalid_steps: %d",
|
||||
options_.max_num_consecutive_invalid_steps);
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -376,14 +367,14 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
const double step_size_tolerance = options_.parameter_tolerance *
|
||||
(x_norm + options_.parameter_tolerance);
|
||||
if (iteration_summary.step_norm <= step_size_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating. Parameter tolerance reached. "
|
||||
"relative step_norm: %e <= %e.",
|
||||
(iteration_summary.step_norm /
|
||||
(x_norm + options_.parameter_tolerance)),
|
||||
options_.parameter_tolerance);
|
||||
summary->termination_type = PARAMETER_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -391,13 +382,13 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
const double absolute_function_tolerance =
|
||||
options_.function_tolerance * cost;
|
||||
if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating. Function tolerance reached. "
|
||||
"|cost_change|/cost: %e <= %e",
|
||||
fabs(iteration_summary.cost_change) / cost,
|
||||
options_.function_tolerance);
|
||||
summary->termination_type = FUNCTION_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -494,10 +485,10 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
residuals.data(),
|
||||
gradient.data(),
|
||||
jacobian)) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
"Terminating: Residual and Jacobian evaluation failed.";
|
||||
summary->termination_type = NUMERICAL_FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->error;
|
||||
summary->termination_type = FAILURE;
|
||||
LOG_IF(WARNING, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -505,14 +496,14 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
iteration_summary.gradient_norm = gradient.norm();
|
||||
|
||||
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
|
||||
summary->error =
|
||||
summary->message =
|
||||
StringPrintf("Terminating: Gradient tolerance reached. "
|
||||
"Relative gradient max norm: %e <= %e",
|
||||
(iteration_summary.gradient_max_norm /
|
||||
initial_gradient_max_norm),
|
||||
options_.gradient_tolerance);
|
||||
summary->termination_type = GRADIENT_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -575,9 +566,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
|
|||
iteration_summary.trust_region_radius = strategy->Radius();
|
||||
if (iteration_summary.trust_region_radius <
|
||||
options_.min_trust_region_radius) {
|
||||
summary->error = "Termination. Minimum trust region radius reached.";
|
||||
summary->termination_type = PARAMETER_TOLERANCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->error;
|
||||
summary->message = "Termination. Minimum trust region radius reached.";
|
||||
summary->termination_type = CONVERGENCE;
|
||||
VLOG_IF(1, is_not_silent) << summary->message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -297,16 +297,13 @@ bool StringToVisibilityClusteringType(
|
|||
return false;
|
||||
}
|
||||
|
||||
const char* SolverTerminationTypeToString(SolverTerminationType type) {
|
||||
const char* TerminationTypeToString(TerminationType type) {
|
||||
switch (type) {
|
||||
CASESTR(CONVERGENCE);
|
||||
CASESTR(NO_CONVERGENCE);
|
||||
CASESTR(FUNCTION_TOLERANCE);
|
||||
CASESTR(GRADIENT_TOLERANCE);
|
||||
CASESTR(PARAMETER_TOLERANCE);
|
||||
CASESTR(NUMERICAL_FAILURE);
|
||||
CASESTR(USER_ABORT);
|
||||
CASESTR(FAILURE);
|
||||
CASESTR(USER_SUCCESS);
|
||||
CASESTR(DID_NOT_RUN);
|
||||
CASESTR(USER_FAILURE);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue