38
38
#endif // CERES_NO_CXSPARSE
40
40
#include "Eigen/Dense"
41
#include "glog/logging.h"
42
41
#include "ceres/block_random_access_dense_matrix.h"
43
42
#include "ceres/block_random_access_matrix.h"
44
43
#include "ceres/block_random_access_sparse_matrix.h"
45
44
#include "ceres/block_sparse_matrix.h"
46
45
#include "ceres/block_structure.h"
47
46
#include "ceres/detect_structure.h"
47
#include "ceres/internal/eigen.h"
48
#include "ceres/internal/port.h"
49
#include "ceres/internal/scoped_ptr.h"
48
50
#include "ceres/linear_solver.h"
49
51
#include "ceres/schur_complement_solver.h"
50
52
#include "ceres/suitesparse.h"
51
53
#include "ceres/triplet_sparse_matrix.h"
52
#include "ceres/internal/eigen.h"
53
#include "ceres/internal/port.h"
54
#include "ceres/internal/scoped_ptr.h"
55
54
#include "ceres/types.h"
55
#include "ceres/wall_time.h"
59
58
namespace internal {
64
63
const LinearSolver::PerSolveOptions& per_solve_options,
66
const time_t start_time = time(NULL);
65
EventLogger event_logger("SchurComplementSolver::Solve");
67
67
if (eliminator_.get() == NULL) {
68
68
InitStorage(A->block_structure());
69
69
DetectStructure(*A->block_structure(),
70
options_.num_eliminate_blocks,
70
options_.elimination_groups[0],
71
71
&options_.row_block_size,
72
72
&options_.e_block_size,
73
73
&options_.f_block_size);
74
74
eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
75
eliminator_->Init(options_.num_eliminate_blocks, A->block_structure());
75
eliminator_->Init(options_.elimination_groups[0], A->block_structure());
77
const time_t init_time = time(NULL);
78
77
fill(x, x + A->num_cols(), 0.0);
78
event_logger.AddEvent("Setup");
80
80
LinearSolver::Summary summary;
81
81
summary.num_iterations = 1;
82
82
summary.termination_type = FAILURE;
83
83
eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
84
const time_t eliminate_time = time(NULL);
84
event_logger.AddEvent("Eliminate");
86
86
double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
87
87
const bool status = SolveReducedLinearSystem(reduced_solution);
88
const time_t solve_time = time(NULL);
88
event_logger.AddEvent("ReducedSolve");
94
94
eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
95
const time_t backsubstitute_time = time(NULL);
96
95
summary.termination_type = TOLERANCE;
98
VLOG(2) << "time (sec) total: " << (backsubstitute_time - start_time)
99
<< " init: " << (init_time - start_time)
100
<< " eliminate: " << (eliminate_time - init_time)
101
<< " solve: " << (solve_time - eliminate_time)
102
<< " backsubstitute: " << (backsubstitute_time - solve_time);
97
event_logger.AddEvent("BackSubstitute");
108
103
void DenseSchurComplementSolver::InitStorage(
109
104
const CompressedRowBlockStructure* bs) {
110
const int num_eliminate_blocks = options().num_eliminate_blocks;
105
const int num_eliminate_blocks = options().elimination_groups[0];
111
106
const int num_col_blocks = bs->cols.size();
113
108
vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
179
175
// initialize a BlockRandomAccessSparseMatrix object.
180
176
void SparseSchurComplementSolver::InitStorage(
181
177
const CompressedRowBlockStructure* bs) {
182
const int num_eliminate_blocks = options().num_eliminate_blocks;
178
const int num_eliminate_blocks = options().elimination_groups[0];
183
179
const int num_col_blocks = bs->cols.size();
184
180
const int num_row_blocks = bs->rows.size();
268
264
// CHOLMOD's sparse cholesky factorization routines.
269
265
bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
270
266
double* solution) {
271
const time_t start_time = time(NULL);
273
267
TripletSparseMatrix* tsm =
274
268
const_cast<TripletSparseMatrix*>(
275
269
down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
286
280
// The matrix is symmetric, and the upper triangular part of the
287
281
// matrix contains the values.
288
282
cholmod_lhs->stype = 1;
289
const time_t lhs_time = time(NULL);
291
284
cholmod_dense* cholmod_rhs =
292
285
ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
293
const time_t rhs_time = time(NULL);
295
287
// Symbolic factorization is computed if we don't already have one handy.
296
288
if (factor_ == NULL) {
297
if (options().use_block_amd) {
298
factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs, blocks_, blocks_);
300
factor_ = ss_.AnalyzeCholesky(cholmod_lhs);
304
cholmod_print_common("Symbolic Analysis", ss_.mutable_cc());
289
factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs, blocks_, blocks_);
308
CHECK_NOTNULL(factor_);
310
const time_t symbolic_time = time(NULL);
311
292
cholmod_dense* cholmod_solution =
312
293
ss_.SolveCholesky(cholmod_lhs, factor_, cholmod_rhs);
314
const time_t solve_time = time(NULL);
316
295
ss_.Free(cholmod_lhs);
317
296
cholmod_lhs = NULL;
318
297
ss_.Free(cholmod_rhs);
319
298
cholmod_rhs = NULL;
321
300
if (cholmod_solution == NULL) {
322
LOG(ERROR) << "CHOLMOD solve failed.";
301
LOG(WARNING) << "CHOLMOD solve failed.";
326
305
VectorRef(solution, num_rows)
327
306
= VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
328
307
ss_.Free(cholmod_solution);
329
const time_t final_time = time(NULL);
330
VLOG(2) << "time: " << (final_time - start_time)
331
<< " lhs : " << (lhs_time - start_time)
332
<< " rhs: " << (rhs_time - lhs_time)
333
<< " analyze: " << (symbolic_time - rhs_time)
334
<< " factor_and_solve: " << (solve_time - symbolic_time)
335
<< " cleanup: " << (final_time - solve_time);