Files
ceres-solver/internal/ceres/schur_eliminator_benchmark.cc
T
Sameer Agarwal 667062dcc8 Introduce BlockSparseMatrixData
A number of algorithms like the SchurEliminator do not need
access to the full BlockSparseMatrix interface. They only
need read only access to the values array and the block structure.

This change introduces, BlockSparseDataMatrix a struct that carries
these two bits of information and modifies the Schur type algorithms
to use it.

What this change will allow us to do, in a subsequent CL is to
take the values array of a BlockSparseMatrix and pair it with
a different blocks structure for subset preconditioning.

Change-Id: I1808f12531b586c9ff4d6a70b3d390c7b0d9f441
2019-09-24 06:53:30 -07:00

223 lines
8.2 KiB
C++

// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Authors: sameeragarwal@google.com (Sameer Agarwal)
#include "Eigen/Dense"
#include "benchmark/benchmark.h"
#include "ceres/block_random_access_dense_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/random.h"
#include "ceres/schur_eliminator.h"
namespace ceres {
namespace internal {
constexpr int kRowBlockSize = 2;
constexpr int kEBlockSize = 3;
constexpr int kFBlockSize = 6;
class BenchmarkData {
public:
explicit BenchmarkData(const int num_e_blocks) {
CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
bs->cols.resize(num_e_blocks + 1);
int col_pos = 0;
for (int i = 0; i < num_e_blocks; ++i) {
bs->cols[i].position = col_pos;
bs->cols[i].size = kEBlockSize;
col_pos += kEBlockSize;
}
bs->cols.back().position = col_pos;
bs->cols.back().size = kFBlockSize;
bs->rows.resize(2 * num_e_blocks);
int row_pos = 0;
int cell_pos = 0;
for (int i = 0; i < num_e_blocks; ++i) {
{
auto& row = bs->rows[2 * i];
row.block.position = row_pos;
row.block.size = kRowBlockSize;
row_pos += kRowBlockSize;
auto& cells = row.cells;
cells.resize(2);
cells[0].block_id = i;
cells[0].position = cell_pos;
cell_pos += kRowBlockSize * kEBlockSize;
cells[1].block_id = num_e_blocks;
cells[1].position = cell_pos;
cell_pos += kRowBlockSize * kFBlockSize;
}
{
auto& row = bs->rows[2 * i + 1];
row.block.position = row_pos;
row.block.size = kRowBlockSize;
row_pos += kRowBlockSize;
auto& cells = row.cells;
cells.resize(1);
cells[0].block_id = i;
cells[0].position = cell_pos;
cell_pos += kRowBlockSize * kEBlockSize;
}
}
matrix_.reset(new BlockSparseMatrix(bs));
double* values = matrix_->mutable_values();
for (int i = 0; i < matrix_->num_nonzeros(); ++i) {
values[i] = RandNormal();
}
b_.resize(matrix_->num_rows());
b_.setRandom();
std::vector<int> blocks(1, kFBlockSize);
lhs_.reset(new BlockRandomAccessDenseMatrix(blocks));
diagonal_.resize(matrix_->num_cols());
diagonal_.setOnes();
rhs_.resize(kFBlockSize);
y_.resize(num_e_blocks * kEBlockSize);
y_.setZero();
z_.resize(kFBlockSize);
z_.setOnes();
}
const BlockSparseMatrix& matrix() const { return *matrix_; }
const Vector& b() const { return b_; }
const Vector& diagonal() const { return diagonal_; }
BlockRandomAccessDenseMatrix* mutable_lhs() { return lhs_.get(); }
Vector* mutable_rhs() { return &rhs_; }
Vector* mutable_y() { return &y_; }
Vector* mutable_z() { return &z_; }
private:
std::unique_ptr<BlockSparseMatrix> matrix_;
Vector b_;
std::unique_ptr<BlockRandomAccessDenseMatrix> lhs_;
Vector rhs_;
Vector diagonal_;
Vector z_;
Vector y_;
};
void BM_SchurEliminatorEliminate(benchmark::State& state) {
const int num_e_blocks = state.range(0);
BenchmarkData data(num_e_blocks);
ContextImpl context;
LinearSolver::Options linear_solver_options;
linear_solver_options.e_block_size = kEBlockSize;
linear_solver_options.row_block_size = kRowBlockSize;
linear_solver_options.f_block_size = kFBlockSize;
linear_solver_options.context = &context;
std::unique_ptr<SchurEliminatorBase> eliminator(
SchurEliminatorBase::Create(linear_solver_options));
eliminator->Init(num_e_blocks, true, data.matrix().block_structure());
for (auto _ : state) {
eliminator->Eliminate(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_lhs(),
data.mutable_rhs()->data());
}
}
void BM_SchurEliminatorBackSubstitute(benchmark::State& state) {
const int num_e_blocks = state.range(0);
BenchmarkData data(num_e_blocks);
ContextImpl context;
LinearSolver::Options linear_solver_options;
linear_solver_options.e_block_size = kEBlockSize;
linear_solver_options.row_block_size = kRowBlockSize;
linear_solver_options.f_block_size = kFBlockSize;
linear_solver_options.context = &context;
std::unique_ptr<SchurEliminatorBase> eliminator(
SchurEliminatorBase::Create(linear_solver_options));
eliminator->Init(num_e_blocks, true, data.matrix().block_structure());
eliminator->Eliminate(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_lhs(),
data.mutable_rhs()->data());
for (auto _ : state) {
eliminator->BackSubstitute(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_z()->data(),
data.mutable_y()->data());
}
}
void BM_SchurEliminatorForOneFBlockEliminate(benchmark::State& state) {
const int num_e_blocks = state.range(0);
BenchmarkData data(num_e_blocks);
SchurEliminatorForOneFBlock<2, 3, 6> eliminator;
eliminator.Init(num_e_blocks, true, data.matrix().block_structure());
for (auto _ : state) {
eliminator.Eliminate(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_lhs(),
data.mutable_rhs()->data());
}
}
void BM_SchurEliminatorForOneFBlockBackSubstitute(benchmark::State& state) {
const int num_e_blocks = state.range(0);
BenchmarkData data(num_e_blocks);
SchurEliminatorForOneFBlock<2, 3, 6> eliminator;
eliminator.Init(num_e_blocks, true, data.matrix().block_structure());
eliminator.Eliminate(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_lhs(),
data.mutable_rhs()->data());
for (auto _ : state) {
eliminator.BackSubstitute(BlockSparseMatrixData(data.matrix()),
data.b().data(),
data.diagonal().data(),
data.mutable_z()->data(),
data.mutable_y()->data());
}
}
BENCHMARK(BM_SchurEliminatorEliminate)->Range(10, 10000);
BENCHMARK(BM_SchurEliminatorForOneFBlockEliminate)->Range(10, 10000);
BENCHMARK(BM_SchurEliminatorBackSubstitute)->Range(10, 10000);
BENCHMARK(BM_SchurEliminatorForOneFBlockBackSubstitute)->Range(10, 10000);
} // namespace internal
} // namespace ceres
BENCHMARK_MAIN();