mirror of
https://github.com/ceres-solver/ceres-solver.git
synced 2026-08-30 00:50:37 +08:00
Program::RemoveFixedBlocks -> Program::CreateReducedProgram.
CreateReducedProgram is a safer API, reduces the possibility of memory leaks and produces valid programs. Change-Id: I094d53d207fced970a4d9ea0b66cdb09ce5f0657
This commit is contained in:
@@ -261,6 +261,24 @@ bool Program::IsFeasible(string* message) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
Program* Program::CreateReducedProgram(vector<double*>* removed_parameter_blocks,
|
||||
double* fixed_cost,
|
||||
string* error) const {
|
||||
CHECK_NOTNULL(removed_parameter_blocks);
|
||||
CHECK_NOTNULL(fixed_cost);
|
||||
CHECK_NOTNULL(error);
|
||||
|
||||
scoped_ptr<Program> reduced_program(new Program(*this));
|
||||
if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
|
||||
fixed_cost,
|
||||
error)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reduced_program->SetParameterOffsetsAndIndex();
|
||||
return reduced_program.release();
|
||||
}
|
||||
|
||||
bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
|
||||
double* fixed_cost,
|
||||
string* error) {
|
||||
|
||||
@@ -129,16 +129,22 @@ class Program {
|
||||
// Caller owns the result.
|
||||
TripletSparseMatrix* CreateJacobianBlockSparsityTranspose() const;
|
||||
|
||||
// Removes constant parameter blocks and residual blocks with no
|
||||
// varying parameter blocks while preserving order.
|
||||
// Create a copy of this program and removes constant parameter
|
||||
// blocks and residual blocks with no varying parameter blocks while
|
||||
// preserving their relative order.
|
||||
//
|
||||
// WARNING: It is the caller's responsibility to track ownership of
|
||||
// the parameter and residual blocks removed from the
|
||||
// program. Generally speaking this method should only be called on
|
||||
// a copy of an existing program.
|
||||
bool RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
|
||||
double* fixed_cost,
|
||||
string* message);
|
||||
// removed_parameter_blocks on exit will contain the list of
|
||||
// parameter blocks that were removed.
|
||||
//
|
||||
// fixed_cost will be equal to the sum of the costs of the residual
|
||||
// blocks that were removed.
|
||||
//
|
||||
// If there was a problem, then the function will return a NULL
|
||||
// pointer and error will contain a human readable description of
|
||||
// the problem.
|
||||
Program* CreateReducedProgram(vector<double*>* removed_parameter_blocks,
|
||||
double* fixed_cost,
|
||||
string* error) const;
|
||||
|
||||
// See problem.h for what these do.
|
||||
int NumParameterBlocks() const;
|
||||
@@ -157,6 +163,21 @@ class Program {
|
||||
string ToString() const;
|
||||
|
||||
private:
|
||||
// Remove constant parameter blocks and residual blocks with no
|
||||
// varying parameter blocks while preserving their relative order.
|
||||
//
|
||||
// removed_parameter_blocks on exit will contain the list of
|
||||
// parameter blocks that were removed.
|
||||
//
|
||||
// fixed_cost will be equal to the sum of the costs of the residual
|
||||
// blocks that were removed.
|
||||
//
|
||||
// If there was a problem, then the function will return false and
|
||||
// error will contain a human readable description of the problem.
|
||||
bool RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
|
||||
double* fixed_cost,
|
||||
string* message);
|
||||
|
||||
// The Program does not own the ParameterBlock or ResidualBlock objects.
|
||||
vector<ParameterBlock*> parameter_blocks_;
|
||||
vector<ResidualBlock*> residual_blocks_;
|
||||
|
||||
@@ -88,15 +88,18 @@ TEST(Program, RemoveFixedBlocksNothingConstant) {
|
||||
problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &y);
|
||||
problem.AddResidualBlock(new TernaryCostFunction(), NULL, &x, &y, &z);
|
||||
|
||||
Program program(problem.program());
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 3);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 3);
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 3);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 3);
|
||||
EXPECT_EQ(removed_parameter_blocks.size(), 0);
|
||||
EXPECT_EQ(fixed_cost, 0.0);
|
||||
}
|
||||
@@ -109,15 +112,17 @@ TEST(Program, RemoveFixedBlocksAllParameterBlocksConstant) {
|
||||
problem.AddResidualBlock(new UnaryCostFunction(), NULL, &x);
|
||||
problem.SetParameterBlockConstant(&x);
|
||||
|
||||
Program program(problem.program());
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 0);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 0);
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 0);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 0);
|
||||
EXPECT_EQ(removed_parameter_blocks.size(), 1);
|
||||
EXPECT_EQ(removed_parameter_blocks[0], &x);
|
||||
EXPECT_EQ(fixed_cost, 9.0);
|
||||
@@ -134,15 +139,17 @@ TEST(Program, RemoveFixedBlocksNoResidualBlocks) {
|
||||
problem.AddParameterBlock(&y, 1);
|
||||
problem.AddParameterBlock(&z, 1);
|
||||
|
||||
Program program(problem.program());
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 0);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 0);
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 0);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 0);
|
||||
EXPECT_EQ(removed_parameter_blocks.size(), 3);
|
||||
EXPECT_EQ(fixed_cost, 0.0);
|
||||
}
|
||||
@@ -161,15 +168,17 @@ TEST(Program, RemoveFixedBlocksOneParameterBlockConstant) {
|
||||
problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &y);
|
||||
problem.SetParameterBlockConstant(&x);
|
||||
|
||||
Program program(problem.program());
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 1);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 1);
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 1);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 1);
|
||||
}
|
||||
|
||||
TEST(Program, RemoveFixedBlocksNumEliminateBlocks) {
|
||||
@@ -186,15 +195,17 @@ TEST(Program, RemoveFixedBlocksNumEliminateBlocks) {
|
||||
problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &y);
|
||||
problem.SetParameterBlockConstant(&x);
|
||||
|
||||
Program program(problem.program());
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 2);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 2);
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 2);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 2);
|
||||
}
|
||||
|
||||
TEST(Program, RemoveFixedBlocksFixedCost) {
|
||||
@@ -211,27 +222,29 @@ TEST(Program, RemoveFixedBlocksFixedCost) {
|
||||
problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &y);
|
||||
problem.SetParameterBlockConstant(&x);
|
||||
|
||||
Program program(problem.program());
|
||||
|
||||
double expected_fixed_cost;
|
||||
ResidualBlock *expected_removed_block = program.residual_blocks()[0];
|
||||
ResidualBlock *expected_removed_block = problem.program().residual_blocks()[0];
|
||||
scoped_array<double> scratch(
|
||||
new double[expected_removed_block->NumScratchDoublesForEvaluate()]);
|
||||
double expected_fixed_cost;
|
||||
expected_removed_block->Evaluate(true,
|
||||
&expected_fixed_cost,
|
||||
NULL,
|
||||
NULL,
|
||||
scratch.get());
|
||||
|
||||
|
||||
vector<double*> removed_parameter_blocks;
|
||||
double fixed_cost = 0.0;
|
||||
string message;
|
||||
EXPECT_TRUE(program.RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message));
|
||||
scoped_ptr<Program> reduced_program(
|
||||
CHECK_NOTNULL(problem
|
||||
.program()
|
||||
.CreateReducedProgram(&removed_parameter_blocks,
|
||||
&fixed_cost,
|
||||
&message)));
|
||||
|
||||
EXPECT_EQ(program.NumParameterBlocks(), 2);
|
||||
EXPECT_EQ(program.NumResidualBlocks(), 2);
|
||||
EXPECT_EQ(reduced_program->NumParameterBlocks(), 2);
|
||||
EXPECT_EQ(reduced_program->NumResidualBlocks(), 2);
|
||||
EXPECT_DOUBLE_EQ(fixed_cost, expected_fixed_cost);
|
||||
}
|
||||
|
||||
|
||||
@@ -664,42 +664,44 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
|
||||
string* error) {
|
||||
CHECK_NOTNULL(options->linear_solver_ordering.get());
|
||||
Program* original_program = problem_impl->mutable_program();
|
||||
scoped_ptr<Program> transformed_program(new Program(*original_program));
|
||||
|
||||
vector<double*> removed_parameter_blocks;
|
||||
scoped_ptr<Program> reduced_program(
|
||||
original_program->CreateReducedProgram(&removed_parameter_blocks,
|
||||
fixed_cost,
|
||||
error));
|
||||
if (reduced_program.get() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VLOG(2) << "Reduced problem: "
|
||||
<< reduced_program->NumParameterBlocks()
|
||||
<< " parameter blocks, "
|
||||
<< reduced_program->NumParameters()
|
||||
<< " parameters, "
|
||||
<< reduced_program->NumResidualBlocks()
|
||||
<< " residual blocks, "
|
||||
<< reduced_program->NumResiduals()
|
||||
<< " residuals.";
|
||||
|
||||
if (reduced_program->NumParameterBlocks() == 0) {
|
||||
LOG(WARNING) << "No varying parameter blocks to optimize; "
|
||||
<< "bailing early.";
|
||||
return reduced_program.release();
|
||||
}
|
||||
|
||||
ParameterBlockOrdering* linear_solver_ordering =
|
||||
options->linear_solver_ordering.get();
|
||||
const int min_group_id =
|
||||
linear_solver_ordering->group_to_elements().begin()->first;
|
||||
vector<double*> removed_parameter_blocks;
|
||||
if (!transformed_program->RemoveFixedBlocks(&removed_parameter_blocks,
|
||||
fixed_cost,
|
||||
error)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linear_solver_ordering->Remove(removed_parameter_blocks);
|
||||
|
||||
ParameterBlockOrdering* inner_iteration_ordering =
|
||||
options->inner_iteration_ordering.get();
|
||||
if (inner_iteration_ordering != NULL) {
|
||||
inner_iteration_ordering->Remove(removed_parameter_blocks);
|
||||
}
|
||||
|
||||
VLOG(2) << "Reduced problem: "
|
||||
<< transformed_program->NumParameterBlocks()
|
||||
<< " parameter blocks, "
|
||||
<< transformed_program->NumParameters()
|
||||
<< " parameters, "
|
||||
<< transformed_program->NumResidualBlocks()
|
||||
<< " residual blocks, "
|
||||
<< transformed_program->NumResiduals()
|
||||
<< " residuals.";
|
||||
|
||||
if (transformed_program->NumParameterBlocks() == 0) {
|
||||
LOG(WARNING) << "No varying parameter blocks to optimize; "
|
||||
<< "bailing early.";
|
||||
return transformed_program.release();
|
||||
}
|
||||
|
||||
if (IsSchurType(options->linear_solver_type) &&
|
||||
linear_solver_ordering->GroupSize(min_group_id) == 0) {
|
||||
// If the user requested the use of a Schur type solver, and
|
||||
@@ -730,11 +732,11 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
|
||||
options->sparse_linear_algebra_library_type,
|
||||
problem_impl->parameter_map(),
|
||||
linear_solver_ordering,
|
||||
transformed_program.get(),
|
||||
reduced_program.get(),
|
||||
error)) {
|
||||
return NULL;
|
||||
}
|
||||
return transformed_program.release();
|
||||
return reduced_program.release();
|
||||
}
|
||||
|
||||
if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
|
||||
@@ -742,16 +744,16 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
|
||||
if (!ReorderProgramForSparseNormalCholesky(
|
||||
options->sparse_linear_algebra_library_type,
|
||||
linear_solver_ordering,
|
||||
transformed_program.get(),
|
||||
reduced_program.get(),
|
||||
error)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return transformed_program.release();
|
||||
return reduced_program.release();
|
||||
}
|
||||
|
||||
transformed_program->SetParameterOffsetsAndIndex();
|
||||
return transformed_program.release();
|
||||
reduced_program->SetParameterOffsetsAndIndex();
|
||||
return reduced_program.release();
|
||||
}
|
||||
|
||||
LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
|
||||
|
||||
Reference in New Issue
Block a user