mirror of
https://github.com/ceres-solver/ceres-solver.git
synced 2026-08-29 16:40:38 +08:00
8549c88d7c
The bundle adjustment test is extremely slow to run (especially in debug or fastbuild), and since it is in one binary, there is no way to get CMake or Bazel to parallelize the test execution. This change divides the test into a single binary for each configuration, making parallelized execution possible. In this patch, only the Bazel build is updated to use the new test. The old test still exists to retain parity with the CMake build. A followup change will complete the process of adding equivalent test execution to the CMake build. Example build output: % bazel test -c opt :all INFO: Analysed 123 targets (15 packages loaded). INFO: Found 2 targets and 121 test targets... INFO: From Compiling external/com_github_google_glog/src/logging.cc: external/com_github_google_glog/src/logging.cc: In static member function 'static void google::LogMessage::Fail()': external/com_github_google_glog/src/logging.cc:1518:1: warning: 'noreturn' function does return } ^ INFO: Elapsed time: 98.056s, Critical Path: 23.80s INFO: Build completed successfully, 976 total actions //:array_utils_test PASSED in 0.1s //:autodiff_cost_function_test PASSED in 0.2s //:autodiff_local_parameterization_test PASSED in 0.2s //:autodiff_test PASSED in 0.1s //:ba_denseschur_auto_test PASSED in 5.3s //:ba_denseschur_auto_threads_test PASSED in 0.1s //:ba_denseschur_user_test PASSED in 5.3s //:ba_denseschur_user_threads_test PASSED in 0.1s //:ba_iterschur_jacobi_auto_test PASSED in 6.2s //:ba_iterschur_jacobi_auto_threads_test PASSED in 0.1s //:ba_iterschur_jacobi_user_test PASSED in 6.0s //:ba_iterschur_jacobi_user_threads_test PASSED in 0.2s //:ba_iterschur_schurjacobi_auto_test PASSED in 6.1s //:ba_iterschur_schurjacobi_auto_threads_test PASSED in 0.2s //:ba_iterschur_schurjacobi_user_test PASSED in 5.7s //:ba_iterschur_schurjacobi_user_threads_test PASSED in 0.1s //:ba_iterschur_suitesparse_clustjacobi_auto_test PASSED in 0.1s //:ba_iterschur_suitesparse_clustjacobi_auto_threads_test PASSED in 0.1s //:ba_iterschur_suitesparse_clustjacobi_user_test PASSED in 0.1s //:ba_iterschur_suitesparse_clustjacobi_user_threads_test PASSED in 0.1s //:ba_iterschur_suitesparse_clusttri_auto_test PASSED in 0.1s //:ba_iterschur_suitesparse_clusttri_auto_threads_test PASSED in 0.1s //:ba_iterschur_suitesparse_clusttri_user_test PASSED in 0.1s //:ba_iterschur_suitesparse_clusttri_user_threads_test PASSED in 0.1s //:ba_sparsecholesky_cxsparse_auto_test PASSED in 0.2s //:ba_sparsecholesky_cxsparse_auto_threads_test PASSED in 0.2s //:ba_sparsecholesky_cxsparse_user_test PASSED in 0.1s //:ba_sparsecholesky_cxsparse_user_threads_test PASSED in 0.1s //:ba_sparsecholesky_eigensparse_auto_test PASSED in 0.1s //:ba_sparsecholesky_eigensparse_auto_threads_test PASSED in 0.1s //:ba_sparsecholesky_eigensparse_user_test PASSED in 0.2s //:ba_sparsecholesky_eigensparse_user_threads_test PASSED in 0.1s //:ba_sparsecholesky_suitesparse_auto_test PASSED in 0.1s //:ba_sparsecholesky_suitesparse_auto_threads_test PASSED in 0.3s //:ba_sparsecholesky_suitesparse_user_test PASSED in 0.1s //:ba_sparsecholesky_suitesparse_user_threads_test PASSED in 0.2s //:ba_sparseschur_cxsparse_auto_test PASSED in 0.1s //:ba_sparseschur_cxsparse_auto_threads_test PASSED in 0.2s //:ba_sparseschur_cxsparse_user_test PASSED in 0.1s //:ba_sparseschur_cxsparse_user_threads_test PASSED in 0.2s //:ba_sparseschur_eigensparse_auto_test PASSED in 0.2s //:ba_sparseschur_eigensparse_auto_threads_test PASSED in 0.2s //:ba_sparseschur_eigensparse_user_test PASSED in 0.1s //:ba_sparseschur_eigensparse_user_threads_test PASSED in 0.2s //:ba_sparseschur_suitesparse_auto_test PASSED in 0.3s //:ba_sparseschur_suitesparse_auto_threads_test PASSED in 0.2s //:ba_sparseschur_suitesparse_user_test PASSED in 0.2s //:ba_sparseschur_suitesparse_user_threads_test PASSED in 0.2s //:block_jacobi_preconditioner_test PASSED in 0.1s //:block_random_access_dense_matrix_test PASSED in 0.2s //:block_random_access_diagonal_matrix_test PASSED in 0.4s //:block_random_access_sparse_matrix_test PASSED in 0.2s //:block_sparse_matrix_test PASSED in 0.2s //:c_api_test PASSED in 0.2s //:canonical_views_clustering_test PASSED in 0.4s //:compressed_col_sparse_matrix_utils_test PASSED in 0.3s //:compressed_row_sparse_matrix_test PASSED in 0.3s //:conditioned_cost_function_test PASSED in 0.2s //:conjugate_gradients_solver_test PASSED in 0.2s //:corrector_test PASSED in 0.2s //:cost_function_to_functor_test PASSED in 0.1s //:covariance_test PASSED in 0.1s //:cubic_interpolation_test PASSED in 0.2s //:dense_linear_solver_test PASSED in 0.1s //:dense_sparse_matrix_test PASSED in 0.4s //:detect_structure_test PASSED in 0.3s //:dogleg_strategy_test PASSED in 0.4s //:dynamic_autodiff_cost_function_test PASSED in 0.2s //:dynamic_compressed_row_sparse_matrix_test PASSED in 0.2s //:dynamic_numeric_diff_cost_function_test PASSED in 0.1s //:dynamic_sparse_normal_cholesky_solver_test PASSED in 0.4s //:dynamic_sparsity_test PASSED in 0.3s //:evaluator_test PASSED in 0.2s //:gradient_checker_test PASSED in 0.2s //:gradient_checking_cost_function_test PASSED in 0.2s //:gradient_problem_solver_test PASSED in 0.2s //:gradient_problem_test PASSED in 0.4s //:graph_algorithms_test PASSED in 0.4s //:graph_test PASSED in 0.2s //:householder_vector_test PASSED in 0.2s //:implicit_schur_complement_test PASSED in 0.2s //:inner_product_computer_test PASSED in 0.3s //:invert_psd_matrix_test PASSED in 0.1s //:is_close_test PASSED in 0.4s //:iterative_schur_complement_solver_test PASSED in 0.3s //:jet_test PASSED in 0.3s //:levenberg_marquardt_strategy_test PASSED in 0.2s //:line_search_minimizer_test PASSED in 0.2s //:line_search_preprocessor_test PASSED in 0.1s //:local_parameterization_test PASSED in 0.1s //:loss_function_test PASSED in 0.1s //:minimizer_test PASSED in 0.2s //:normal_prior_test PASSED in 0.3s //:numeric_diff_cost_function_test PASSED in 0.2s //:ordered_groups_test PASSED in 0.2s //:parameter_block_ordering_test PASSED in 0.2s //:parameter_block_test PASSED in 0.1s //:partitioned_matrix_view_test PASSED in 0.1s //:polynomial_test PASSED in 0.1s //:problem_test PASSED in 0.1s //:program_test PASSED in 0.2s //:reorder_program_test PASSED in 0.2s //:residual_block_test PASSED in 0.2s //:residual_block_utils_test PASSED in 0.2s //:rotation_test PASSED in 7.1s //:schur_complement_solver_test PASSED in 0.2s //:schur_eliminator_test PASSED in 0.2s //:single_linkage_clustering_test PASSED in 0.2s //:small_blas_test PASSED in 0.2s //:solver_test PASSED in 0.2s //:sparse_cholesky_test PASSED in 0.2s //:sparse_normal_cholesky_solver_test PASSED in 0.2s //:system_test PASSED in 0.1s //:tiny_solver_autodiff_function_test PASSED in 0.2s //:tiny_solver_cost_function_adapter_test PASSED in 0.1s //:tiny_solver_test PASSED in 0.1s //:triplet_sparse_matrix_test PASSED in 0.2s //:trust_region_minimizer_test PASSED in 0.2s //:trust_region_preprocessor_test PASSED in 0.2s //:visibility_based_preconditioner_test PASSED in 0.1s //:visibility_test PASSED in 0.2s Executed 121 out of 121 tests: 121 tests pass. There were tests whose specified size is too big. Use the --test_verbose_timeout_warnings command line option to see which ones these are. Change-Id: I32825f1e6278ba69dc296bb2dc05fb8ebda26592
189 lines
7.2 KiB
C++
189 lines
7.2 KiB
C++
// Ceres Solver - A fast non-linear least squares minimizer
|
|
// Copyright 2015 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.
|
|
//
|
|
// Author: keir@google.com (Keir Mierle)
|
|
|
|
#ifndef CERES_INTERNAL_TEST_UTIL_H_
|
|
#define CERES_INTERNAL_TEST_UTIL_H_
|
|
|
|
#include <string>
|
|
#include "ceres/internal/port.h"
|
|
#include "ceres/problem.h"
|
|
#include "ceres/solver.h"
|
|
#include "ceres/stringprintf.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace ceres {
|
|
namespace internal {
|
|
|
|
// Expects that x and y have a relative difference of no more than
|
|
// max_abs_relative_difference. If either x or y is zero, then the relative
|
|
// difference is interpreted as an absolute difference.
|
|
bool ExpectClose(double x, double y, double max_abs_relative_difference);
|
|
|
|
// Expects that for all i = 1,.., n - 1
|
|
//
|
|
// |p[i] - q[i]| / max(|p[i]|, |q[i]|) < tolerance
|
|
void ExpectArraysClose(int n,
|
|
const double* p,
|
|
const double* q,
|
|
double tolerance);
|
|
|
|
// Expects that for all i = 1,.., n - 1
|
|
//
|
|
// |p[i] / max_norm_p - q[i] / max_norm_q| < tolerance
|
|
//
|
|
// where max_norm_p and max_norm_q are the max norms of the arrays p
|
|
// and q respectively.
|
|
void ExpectArraysCloseUptoScale(int n,
|
|
const double* p,
|
|
const double* q,
|
|
double tolerance);
|
|
|
|
// Construct a fully qualified path for the test file depending on the
|
|
// local build/testing environment.
|
|
std::string TestFileAbsolutePath(const std::string& filename);
|
|
|
|
// Struct used for configuring the solver. Used by end-to-end tests.
|
|
struct SolverConfig {
|
|
SolverConfig(
|
|
LinearSolverType linear_solver_type,
|
|
SparseLinearAlgebraLibraryType
|
|
sparse_linear_algebra_library_type = NO_SPARSE,
|
|
bool use_automatic_ordering = true,
|
|
PreconditionerType preconditioner_type = IDENTITY,
|
|
int num_threads = 1)
|
|
: linear_solver_type(linear_solver_type),
|
|
sparse_linear_algebra_library_type(sparse_linear_algebra_library_type),
|
|
use_automatic_ordering(use_automatic_ordering),
|
|
preconditioner_type(preconditioner_type),
|
|
num_threads(num_threads) {
|
|
}
|
|
|
|
std::string ToString() const {
|
|
return StringPrintf(
|
|
"(%s, %s, %s, %s, %d)",
|
|
LinearSolverTypeToString(linear_solver_type),
|
|
SparseLinearAlgebraLibraryTypeToString(
|
|
sparse_linear_algebra_library_type),
|
|
use_automatic_ordering ? "AUTOMATIC" : "USER",
|
|
PreconditionerTypeToString(preconditioner_type),
|
|
num_threads);
|
|
}
|
|
|
|
void UpdateOptions(Solver::Options* options) const {
|
|
options->linear_solver_type = linear_solver_type;
|
|
options->sparse_linear_algebra_library_type =
|
|
sparse_linear_algebra_library_type;
|
|
options->preconditioner_type = preconditioner_type;
|
|
options->num_threads = num_threads;
|
|
options->num_linear_solver_threads = num_threads;
|
|
|
|
if (use_automatic_ordering) {
|
|
options->linear_solver_ordering.reset();
|
|
}
|
|
}
|
|
|
|
LinearSolverType linear_solver_type;
|
|
SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
|
|
bool use_automatic_ordering;
|
|
PreconditionerType preconditioner_type;
|
|
int num_threads;
|
|
};
|
|
|
|
SolverConfig ThreadedSolverConfig(
|
|
LinearSolverType linear_solver_type,
|
|
SparseLinearAlgebraLibraryType
|
|
sparse_linear_algebra_library_type = NO_SPARSE,
|
|
bool use_automatic_ordering = true,
|
|
PreconditionerType preconditioner_type = IDENTITY);
|
|
|
|
// A templated test fixture, that is used for testing Ceres end to end
|
|
// by computing a solution to the problem for a given solver
|
|
// configuration and comparing it to a reference solver configuration.
|
|
//
|
|
// It is assumed that the SystemTestProblem has an Solver::Options
|
|
// struct that contains the reference Solver configuration.
|
|
template <class SystemTestProblem>
|
|
class SystemTest : public::testing::Test {
|
|
protected:
|
|
virtual void SetUp() {
|
|
SystemTestProblem system_test_problem;
|
|
SolveAndEvaluateFinalResiduals(
|
|
*system_test_problem.mutable_solver_options(),
|
|
system_test_problem.mutable_problem(),
|
|
&expected_final_residuals_);
|
|
}
|
|
|
|
void RunSolverForConfigAndExpectResidualsMatch(const SolverConfig& config) {
|
|
LOG(INFO) << "Running solver configuration: "
|
|
<< config.ToString();
|
|
|
|
SystemTestProblem system_test_problem;
|
|
config.UpdateOptions(system_test_problem.mutable_solver_options());
|
|
std::vector<double> final_residuals;
|
|
SolveAndEvaluateFinalResiduals(
|
|
*system_test_problem.mutable_solver_options(),
|
|
system_test_problem.mutable_problem(),
|
|
&final_residuals);
|
|
|
|
// We compare solutions by comparing their residual vectors. We do
|
|
// not compare parameter vectors because it is much more brittle
|
|
// and error prone to do so, since the same problem can have
|
|
// nearly the same residuals at two completely different positions
|
|
// in parameter space.
|
|
CHECK_EQ(expected_final_residuals_.size(), final_residuals.size());
|
|
for (int i = 0; i < final_residuals.size(); ++i) {
|
|
EXPECT_NEAR(final_residuals[i],
|
|
expected_final_residuals_[i],
|
|
SystemTestProblem::kResidualTolerance)
|
|
<< "Not close enough residual:" << i;
|
|
}
|
|
}
|
|
|
|
void SolveAndEvaluateFinalResiduals(const Solver::Options& options,
|
|
Problem* problem,
|
|
std::vector<double>* final_residuals) {
|
|
Solver::Summary summary;
|
|
Solve(options, problem, &summary);
|
|
CHECK_NE(summary.termination_type, ceres::FAILURE);
|
|
problem->Evaluate(Problem::EvaluateOptions(),
|
|
NULL,
|
|
final_residuals,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
std::vector<double> expected_final_residuals_;
|
|
};
|
|
|
|
} // namespace internal
|
|
} // namespace ceres
|
|
|
|
#endif // CERES_INTERNAL_TEST_UTIL_H_
|