blob: d8d16465328130344475e0ebed03e765ce8d4203 [file] [log] [blame]
Keir Mierle8549c882018-02-08 19:06:49 -08001# Ceres Solver - A fast non-linear least squares minimizer
Sameer Agarwal5a30cae2023-09-19 15:29:34 -07002# Copyright 2023 Google Inc. All rights reserved.
Keir Mierle8549c882018-02-08 19:06:49 -08003# http://ceres-solver.org/
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are met:
7#
8# * Redistributions of source code must retain the above copyright notice,
9# this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above copyright notice,
11# this list of conditions and the following disclaimer in the documentation
12# and/or other materials provided with the distribution.
13# * Neither the name of Google Inc. nor the names of its contributors may be
14# used to endorse or promote products derived from this software without
15# specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29# Author: keir@google.com (Keir Mierle)
30#
31# Generate bundle adjustment tests as separate binaries. Since the bundle
32# adjustment tests are fairly processing intensive, serializing them makes the
33# tests take forever to run. Splitting them into separate binaries makes it
Kuang Fangjun189f0c22018-09-23 10:56:34 +080034# easier to parallelize in continuous integration systems, and makes local
Keir Mierle8549c882018-02-08 19:06:49 -080035# processing on multi-core workstations much faster.
36
37# Product of ORDERINGS, THREAD_CONFIGS, and SOLVER_CONFIGS is the full set of
38# tests to generate.
39ORDERINGS = ["kAutomaticOrdering", "kUserOrdering"]
Sameer Agarwal4556eb92018-04-13 23:29:37 -070040SINGLE_THREADED = "1"
41MULTI_THREADED = "4"
42THREAD_CONFIGS = [SINGLE_THREADED, MULTI_THREADED]
Keir Mierle8549c882018-02-08 19:06:49 -080043
Sameer Agarwal15348ab2022-02-15 11:01:32 -080044DENSE_SOLVER_CONFIGS = [
45 # Linear solver Dense backend
46 ('DENSE_SCHUR', 'EIGEN'),
47 ('DENSE_SCHUR', 'LAPACK'),
48 ('DENSE_SCHUR', 'CUDA'),
49]
50
51SPARSE_SOLVER_CONFIGS = [
52 # Linear solver Sparse backend
53 ('SPARSE_NORMAL_CHOLESKY', 'SUITE_SPARSE'),
54 ('SPARSE_NORMAL_CHOLESKY', 'EIGEN_SPARSE'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080055 ('SPARSE_NORMAL_CHOLESKY', 'ACCELERATE_SPARSE'),
Mark Shachkov6fb3dae2024-05-01 11:00:58 +020056 ('SPARSE_NORMAL_CHOLESKY', 'CUDA_SPARSE'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080057 ('SPARSE_SCHUR', 'SUITE_SPARSE'),
58 ('SPARSE_SCHUR', 'EIGEN_SPARSE'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080059 ('SPARSE_SCHUR', 'ACCELERATE_SPARSE'),
Mark Shachkov6fb3dae2024-05-01 11:00:58 +020060 ('SPARSE_SCHUR', 'CUDA_SPARSE')
Sameer Agarwal15348ab2022-02-15 11:01:32 -080061]
62
63ITERATIVE_SOLVER_CONFIGS = [
64 # Linear solver Sparse backend Preconditioner
65 ('ITERATIVE_SCHUR', 'NO_SPARSE', 'JACOBI'),
66 ('ITERATIVE_SCHUR', 'NO_SPARSE', 'SCHUR_JACOBI'),
Sameer Agarwal41672df2023-09-28 09:49:03 -070067 ('ITERATIVE_SCHUR', 'NO_SPARSE', 'SCHUR_POWER_SERIES_EXPANSION'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080068 ('ITERATIVE_SCHUR', 'SUITE_SPARSE', 'CLUSTER_JACOBI'),
69 ('ITERATIVE_SCHUR', 'EIGEN_SPARSE', 'CLUSTER_JACOBI'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080070 ('ITERATIVE_SCHUR', 'ACCELERATE_SPARSE','CLUSTER_JACOBI'),
Mark Shachkov6fb3dae2024-05-01 11:00:58 +020071 ('ITERATIVE_SCHUR', 'CUDA_SPARSE', 'CLUSTER_JACOBI'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080072 ('ITERATIVE_SCHUR', 'SUITE_SPARSE', 'CLUSTER_TRIDIAGONAL'),
73 ('ITERATIVE_SCHUR', 'EIGEN_SPARSE', 'CLUSTER_TRIDIAGONAL'),
Sameer Agarwal15348ab2022-02-15 11:01:32 -080074 ('ITERATIVE_SCHUR', 'ACCELERATE_SPARSE','CLUSTER_TRIDIAGONAL'),
Mark Shachkov6fb3dae2024-05-01 11:00:58 +020075 ('ITERATIVE_SCHUR', 'CUDA_SPARSE', 'CLUSTER_TRIDIAGONAL'),
Keir Mierle8549c882018-02-08 19:06:49 -080076]
77
78FILENAME_SHORTENING_MAP = dict(
79 DENSE_SCHUR='denseschur',
80 ITERATIVE_SCHUR='iterschur',
81 SPARSE_NORMAL_CHOLESKY='sparsecholesky',
82 SPARSE_SCHUR='sparseschur',
Sameer Agarwal15348ab2022-02-15 11:01:32 -080083 EIGEN='eigen',
84 LAPACK='lapack',
85 CUDA='cuda',
Keir Mierle8549c882018-02-08 19:06:49 -080086 NO_SPARSE='', # Omit sparse reference entirely for dense tests.
87 SUITE_SPARSE='suitesparse',
88 EIGEN_SPARSE='eigensparse',
Alex Stewart8f41ca62018-06-23 20:17:34 +010089 ACCELERATE_SPARSE='acceleratesparse',
Mark Shachkov6fb3dae2024-05-01 11:00:58 +020090 CUDA_SPARSE='cudasparse',
Keir Mierle8549c882018-02-08 19:06:49 -080091 IDENTITY='identity',
92 JACOBI='jacobi',
93 SCHUR_JACOBI='schurjacobi',
94 CLUSTER_JACOBI='clustjacobi',
95 CLUSTER_TRIDIAGONAL='clusttri',
Sameer Agarwal41672df2023-09-28 09:49:03 -070096 SCHUR_POWER_SERIES_EXPANSION='spse',
Keir Mierle8549c882018-02-08 19:06:49 -080097 kAutomaticOrdering='auto',
98 kUserOrdering='user',
Keir Mierle8549c882018-02-08 19:06:49 -080099)
100
Keir Mierle0a301172018-03-01 13:55:43 -0800101COPYRIGHT_HEADER = (
Keir Mierle8549c882018-02-08 19:06:49 -0800102"""// Ceres Solver - A fast non-linear least squares minimizer
Sameer Agarwal5a30cae2023-09-19 15:29:34 -0700103// Copyright 2023 Google Inc. All rights reserved.
Keir Mierle8549c882018-02-08 19:06:49 -0800104// http://ceres-solver.org/
105//
106// Redistribution and use in source and binary forms, with or without
107// modification, are permitted provided that the following conditions are met:
108//
109// * Redistributions of source code must retain the above copyright notice,
110// this list of conditions and the following disclaimer.
111// * Redistributions in binary form must reproduce the above copyright notice,
112// this list of conditions and the following disclaimer in the documentation
113// and/or other materials provided with the distribution.
114// * Neither the name of Google Inc. nor the names of its contributors may be
115// used to endorse or promote products derived from this software without
116// specific prior written permission.
117//
118// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
119// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
120// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
121// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
122// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
123// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
124// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
125// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
126// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
127// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
128// POSSIBILITY OF SUCH DAMAGE.
129//
130// ========================================
131// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
132// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
133// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
134// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
Keir Mierle0a301172018-03-01 13:55:43 -0800135// ========================================
Keir Mierle8549c882018-02-08 19:06:49 -0800136//
Keir Mierle0a301172018-03-01 13:55:43 -0800137// This file is generated using generate_bundle_adjustment_tests.py.""")
138
139BUNDLE_ADJUSTMENT_TEST_TEMPLATE = (COPYRIGHT_HEADER + """
Keir Mierle8549c882018-02-08 19:06:49 -0800140
Sameer Agarwal399395c2023-10-03 11:52:09 -0700141#include "ceres/bundle_adjustment_test_util.h"
Sameer Agarwal47051592022-03-12 15:22:19 -0800142#include "ceres/internal/config.h"
Sameer Agarwal6b9a6902024-07-21 14:55:46 -0700143#include "ceres/problem.h"
144#include "ceres/solver.h"
145#include "ceres/types.h"
Sameer Agarwal399395c2023-10-03 11:52:09 -0700146#include "gtest/gtest.h"
Sameer Agarwal6b9a6902024-07-21 14:55:46 -0700147
Keir Mierle8549c882018-02-08 19:06:49 -0800148%(preprocessor_conditions_begin)s
Sameer Agarwalcaf614a2022-04-21 17:41:10 -0700149namespace ceres::internal {
Keir Mierle8549c882018-02-08 19:06:49 -0800150
151TEST_F(BundleAdjustmentTest,
152 %(test_class_name)s) { // NOLINT
Nikolaus Demmeld3f66d72020-09-28 02:01:43 +0200153 BundleAdjustmentProblem bundle_adjustment_problem;
154 Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
Sameer Agarwal41672df2023-09-28 09:49:03 -0700155 options->eta = 0.01;
Nikolaus Demmeld3f66d72020-09-28 02:01:43 +0200156 options->num_threads = %(num_threads)s;
157 options->linear_solver_type = %(linear_solver)s;
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800158 options->dense_linear_algebra_library_type = %(dense_backend)s;
Nikolaus Demmeld3f66d72020-09-28 02:01:43 +0200159 options->sparse_linear_algebra_library_type = %(sparse_backend)s;
160 options->preconditioner_type = %(preconditioner)s;
161 if (%(ordering)s) {
Sameer Agarwalae652192022-02-02 13:17:29 -0800162 options->linear_solver_ordering = nullptr;
Nikolaus Demmeld3f66d72020-09-28 02:01:43 +0200163 }
164 Problem* problem = bundle_adjustment_problem.mutable_problem();
165 RunSolverForConfigAndExpectResidualsMatch(*options, problem);
Keir Mierle8549c882018-02-08 19:06:49 -0800166}
167
Sameer Agarwalcaf614a2022-04-21 17:41:10 -0700168} // namespace ceres::internal
Nikolaus Demmeld3f66d72020-09-28 02:01:43 +0200169%(preprocessor_conditions_end)s""")
Keir Mierle8549c882018-02-08 19:06:49 -0800170
Keir Mierle8549c882018-02-08 19:06:49 -0800171def camelcasify(token):
172 """Convert capitalized underscore tokens to camel case"""
173 return ''.join([x.lower().capitalize() for x in token.split('_')])
174
175
176def generate_bundle_test(linear_solver,
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800177 dense_backend,
Keir Mierle8549c882018-02-08 19:06:49 -0800178 sparse_backend,
179 preconditioner,
180 ordering,
181 thread_config):
182 """Generate a bundle adjustment test executable configured appropriately"""
183
184 # Preconditioner only makes sense for iterative schur; drop it otherwise.
185 preconditioner_tag = preconditioner
186 if linear_solver != 'ITERATIVE_SCHUR':
187 preconditioner_tag = ''
188
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800189 dense_backend_tag = dense_backend
190 if linear_solver != 'DENSE_SCHUR':
191 dense_backend_tag=''
192
Keir Mierle8549c882018-02-08 19:06:49 -0800193 # Omit references to the sparse backend when one is not in use.
194 sparse_backend_tag = sparse_backend
195 if sparse_backend == 'NO_SPARSE':
196 sparse_backend_tag = ''
197
198 # Use a double underscore; otherwise the names are harder to understand.
199 test_class_name = '_'.join(filter(lambda x: x, [
200 camelcasify(linear_solver),
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800201 camelcasify(dense_backend_tag),
Keir Mierle8549c882018-02-08 19:06:49 -0800202 camelcasify(sparse_backend_tag),
203 camelcasify(preconditioner_tag),
204 ordering[1:], # Strip 'k'
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700205 'Threads' if thread_config == MULTI_THREADED else '']))
Keir Mierle8549c882018-02-08 19:06:49 -0800206
207 # Initial template parameters (augmented more below).
208 template_parameters = dict(
209 linear_solver=linear_solver,
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800210 dense_backend=dense_backend,
Keir Mierle8549c882018-02-08 19:06:49 -0800211 sparse_backend=sparse_backend,
212 preconditioner=preconditioner,
213 ordering=ordering,
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700214 num_threads=thread_config,
Keir Mierle8549c882018-02-08 19:06:49 -0800215 test_class_name=test_class_name)
216
217 # Accumulate appropriate #ifdef/#ifndefs for the solver's sparse backend.
218 preprocessor_conditions_begin = []
219 preprocessor_conditions_end = []
220 if sparse_backend == 'SUITE_SPARSE':
221 preprocessor_conditions_begin.append('#ifndef CERES_NO_SUITESPARSE')
222 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_SUITESPARSE')
Alex Stewart8f41ca62018-06-23 20:17:34 +0100223 elif sparse_backend == 'ACCELERATE_SPARSE':
224 preprocessor_conditions_begin.append('#ifndef CERES_NO_ACCELERATE_SPARSE')
225 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_ACCELERATE_SPARSE')
Keir Mierle8549c882018-02-08 19:06:49 -0800226 elif sparse_backend == 'EIGEN_SPARSE':
227 preprocessor_conditions_begin.append('#ifdef CERES_USE_EIGEN_SPARSE')
228 preprocessor_conditions_end.insert(0, '#endif // CERES_USE_EIGEN_SPARSE')
Mark Shachkov6fb3dae2024-05-01 11:00:58 +0200229 elif sparse_backend == 'CUDA_SPARSE':
230 preprocessor_conditions_begin.append('#ifndef CERES_NO_CUDA')
231 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_CUDA')
232 if linear_solver == 'SPARSE_SCHUR' or linear_solver == 'SPARSE_NORMAL_CHOLESKY' or (
233 linear_solver == 'ITERATIVE_SCHUR' and (
234 preconditioner == 'CLUSTER_JACOBI' or preconditioner == 'CLUSTER_TRIDIAGONAL')):
235 preprocessor_conditions_begin.append('#ifndef CERES_NO_CUDSS')
236 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_CUDSS')
Keir Mierle8549c882018-02-08 19:06:49 -0800237
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800238 if dense_backend == "LAPACK":
239 preprocessor_conditions_begin.append('#ifndef CERES_NO_LAPACK')
240 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_LAPACK')
241 elif dense_backend == "CUDA":
242 preprocessor_conditions_begin.append('#ifndef CERES_NO_CUDA')
243 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_CUDA')
244
Keir Mierle8549c882018-02-08 19:06:49 -0800245 # If there are #ifdefs, put newlines around them.
246 if preprocessor_conditions_begin:
247 preprocessor_conditions_begin.insert(0, '')
248 preprocessor_conditions_begin.append('')
249 preprocessor_conditions_end.insert(0, '')
250 preprocessor_conditions_end.append('')
251
252 # Put #ifdef/#ifndef stacks into the template parameters.
253 template_parameters['preprocessor_conditions_begin'] = '\n'.join(
254 preprocessor_conditions_begin)
255 template_parameters['preprocessor_conditions_end'] = '\n'.join(
256 preprocessor_conditions_end)
257
258 # Substitute variables into the test template, and write the result to a file.
259 filename_tag = '_'.join(FILENAME_SHORTENING_MAP.get(x) for x in [
260 linear_solver,
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800261 dense_backend_tag,
Keir Mierle8549c882018-02-08 19:06:49 -0800262 sparse_backend_tag,
263 preconditioner_tag,
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700264 ordering]
Keir Mierle8549c882018-02-08 19:06:49 -0800265 if FILENAME_SHORTENING_MAP.get(x))
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800266
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700267 if (thread_config == MULTI_THREADED):
268 filename_tag += '_threads'
269
Keir Mierle8549c882018-02-08 19:06:49 -0800270 filename = ('generated_bundle_adjustment_tests/ba_%s_test.cc' %
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700271 filename_tag.lower())
Keir Mierle8549c882018-02-08 19:06:49 -0800272 with open(filename, 'w') as fd:
273 fd.write(BUNDLE_ADJUSTMENT_TEST_TEMPLATE % template_parameters)
274
275 # All done.
Sameer Agarwalcaf614a2022-04-21 17:41:10 -0700276 print('Generated', filename)
Keir Mierle8549c882018-02-08 19:06:49 -0800277
Keir Mierle0a301172018-03-01 13:55:43 -0800278 return filename
279
Keir Mierle8549c882018-02-08 19:06:49 -0800280
281if __name__ == '__main__':
282 # Iterate over all the possible configurations and generate the tests.
Keir Mierle0a301172018-03-01 13:55:43 -0800283 generated_files = []
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800284
285 for ordering in ORDERINGS:
286 for thread_config in THREAD_CONFIGS:
287 for linear_solver, dense_backend in DENSE_SOLVER_CONFIGS:
Keir Mierle0a301172018-03-01 13:55:43 -0800288 generated_files.append(
289 generate_bundle_test(linear_solver,
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800290 dense_backend,
291 'NO_SPARSE',
292 'IDENTITY',
293 ordering,
294 thread_config))
295
296 for linear_solver, sparse_backend, in SPARSE_SOLVER_CONFIGS:
297 generated_files.append(
298 generate_bundle_test(linear_solver,
299 'EIGEN',
300 sparse_backend,
301 'IDENTITY',
302 ordering,
303 thread_config))
304
305 for linear_solver, sparse_backend, preconditioner, in ITERATIVE_SOLVER_CONFIGS:
306 generated_files.append(
307 generate_bundle_test(linear_solver,
308 'EIGEN',
Keir Mierle0a301172018-03-01 13:55:43 -0800309 sparse_backend,
310 preconditioner,
311 ordering,
312 thread_config))
313
Sameer Agarwal15348ab2022-02-15 11:01:32 -0800314
Keir Mierle0a301172018-03-01 13:55:43 -0800315 # Generate the CMakeLists.txt as well.
316 with open('generated_bundle_adjustment_tests/CMakeLists.txt', 'w') as fd:
317 fd.write(COPYRIGHT_HEADER.replace('//', '#').replace('http:#', 'http://'))
318 fd.write('\n')
319 fd.write('\n')
320 for generated_file in generated_files:
321 fd.write('ceres_test(%s)\n' %
322 generated_file.split('/')[1].replace('_test.cc', ''))