blob: 2f3375ac99ee6a01cc8e3c5fd9d714c8cc8c2402 [file] [log] [blame]
Keir Mierle8549c882018-02-08 19:06:49 -08001# Ceres Solver - A fast non-linear least squares minimizer
2# Copyright 2018 Google Inc. All rights reserved.
3# 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
34# easier to parallelize in continous integration systems, and makes local
35# 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
44SOLVER_CONFIGS = [
45 # Linear solver Sparse backend Preconditioner
46 ('DENSE_SCHUR', 'NO_SPARSE', 'IDENTITY'),
47 ('ITERATIVE_SCHUR', 'NO_SPARSE', 'JACOBI'),
48 ('ITERATIVE_SCHUR', 'NO_SPARSE', 'SCHUR_JACOBI'),
49 ('ITERATIVE_SCHUR', 'SUITE_SPARSE', 'CLUSTER_JACOBI'),
Sameer Agarwale9397ad2018-05-08 13:20:17 -070050 ('ITERATIVE_SCHUR', 'EIGEN_SPARSE', 'CLUSTER_JACOBI'),
51 ('ITERATIVE_SCHUR', 'CX_SPARSE', 'CLUSTER_JACOBI'),
Alex Stewart8f41ca62018-06-23 20:17:34 +010052 ('ITERATIVE_SCHUR', 'ACCELERATE_SPARSE','CLUSTER_JACOBI'),
Keir Mierle8549c882018-02-08 19:06:49 -080053 ('ITERATIVE_SCHUR', 'SUITE_SPARSE', 'CLUSTER_TRIDIAGONAL'),
Sameer Agarwale9397ad2018-05-08 13:20:17 -070054 ('ITERATIVE_SCHUR', 'EIGEN_SPARSE', 'CLUSTER_TRIDIAGONAL'),
55 ('ITERATIVE_SCHUR', 'CX_SPARSE', 'CLUSTER_TRIDIAGONAL'),
Alex Stewart8f41ca62018-06-23 20:17:34 +010056 ('ITERATIVE_SCHUR', 'ACCELERATE_SPARSE','CLUSTER_TRIDIAGONAL'),
Keir Mierle8549c882018-02-08 19:06:49 -080057 ('SPARSE_NORMAL_CHOLESKY', 'SUITE_SPARSE', 'IDENTITY'),
58 ('SPARSE_NORMAL_CHOLESKY', 'EIGEN_SPARSE', 'IDENTITY'),
59 ('SPARSE_NORMAL_CHOLESKY', 'CX_SPARSE', 'IDENTITY'),
Alex Stewart8f41ca62018-06-23 20:17:34 +010060 ('SPARSE_NORMAL_CHOLESKY', 'ACCELERATE_SPARSE','IDENTITY'),
Keir Mierle8549c882018-02-08 19:06:49 -080061 ('SPARSE_SCHUR', 'SUITE_SPARSE', 'IDENTITY'),
62 ('SPARSE_SCHUR', 'EIGEN_SPARSE', 'IDENTITY'),
63 ('SPARSE_SCHUR', 'CX_SPARSE', 'IDENTITY'),
Alex Stewart8f41ca62018-06-23 20:17:34 +010064 ('SPARSE_SCHUR', 'ACCELERATE_SPARSE','IDENTITY'),
Keir Mierle8549c882018-02-08 19:06:49 -080065]
66
67FILENAME_SHORTENING_MAP = dict(
68 DENSE_SCHUR='denseschur',
69 ITERATIVE_SCHUR='iterschur',
70 SPARSE_NORMAL_CHOLESKY='sparsecholesky',
71 SPARSE_SCHUR='sparseschur',
72 NO_SPARSE='', # Omit sparse reference entirely for dense tests.
73 SUITE_SPARSE='suitesparse',
74 EIGEN_SPARSE='eigensparse',
75 CX_SPARSE='cxsparse',
Alex Stewart8f41ca62018-06-23 20:17:34 +010076 ACCELERATE_SPARSE='acceleratesparse',
Keir Mierle8549c882018-02-08 19:06:49 -080077 IDENTITY='identity',
78 JACOBI='jacobi',
79 SCHUR_JACOBI='schurjacobi',
80 CLUSTER_JACOBI='clustjacobi',
81 CLUSTER_TRIDIAGONAL='clusttri',
82 kAutomaticOrdering='auto',
83 kUserOrdering='user',
Keir Mierle8549c882018-02-08 19:06:49 -080084)
85
Keir Mierle0a301172018-03-01 13:55:43 -080086COPYRIGHT_HEADER = (
Keir Mierle8549c882018-02-08 19:06:49 -080087"""// Ceres Solver - A fast non-linear least squares minimizer
88// Copyright 2018 Google Inc. All rights reserved.
89// http://ceres-solver.org/
90//
91// Redistribution and use in source and binary forms, with or without
92// modification, are permitted provided that the following conditions are met:
93//
94// * Redistributions of source code must retain the above copyright notice,
95// this list of conditions and the following disclaimer.
96// * Redistributions in binary form must reproduce the above copyright notice,
97// this list of conditions and the following disclaimer in the documentation
98// and/or other materials provided with the distribution.
99// * Neither the name of Google Inc. nor the names of its contributors may be
100// used to endorse or promote products derived from this software without
101// specific prior written permission.
102//
103// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
104// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
105// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
106// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
107// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
108// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
109// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
110// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
111// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
112// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
113// POSSIBILITY OF SUCH DAMAGE.
114//
115// ========================================
116// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
117// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
118// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
119// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
Keir Mierle0a301172018-03-01 13:55:43 -0800120// ========================================
Keir Mierle8549c882018-02-08 19:06:49 -0800121//
Keir Mierle0a301172018-03-01 13:55:43 -0800122// This file is generated using generate_bundle_adjustment_tests.py.""")
123
124BUNDLE_ADJUSTMENT_TEST_TEMPLATE = (COPYRIGHT_HEADER + """
Keir Mierle8549c882018-02-08 19:06:49 -0800125
126#include "bundle_adjustment_test_util.h"
127%(preprocessor_conditions_begin)s
128namespace ceres {
129namespace internal {
130
131TEST_F(BundleAdjustmentTest,
132 %(test_class_name)s) { // NOLINT
Sameer Agarwal86595282018-04-20 11:02:48 -0700133 BundleAdjustmentProblem bundle_adjustment_problem;
Sameer Agarwale9397ad2018-05-08 13:20:17 -0700134 Solver::Options* options =
135 bundle_adjustment_problem.mutable_solver_options();
Sameer Agarwal86595282018-04-20 11:02:48 -0700136 options->num_threads = %(num_threads)s;
137 options->linear_solver_type = %(linear_solver)s;
138 options->sparse_linear_algebra_library_type = %(sparse_backend)s;
139 options->preconditioner_type = %(preconditioner)s;
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700140 if (%(ordering)s) {
Sameer Agarwale9397ad2018-05-08 13:20:17 -0700141 options->linear_solver_ordering.reset();
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700142 }
Sameer Agarwal86595282018-04-20 11:02:48 -0700143 Problem* problem = bundle_adjustment_problem.mutable_problem();
144 RunSolverForConfigAndExpectResidualsMatch(*options, problem);
Keir Mierle8549c882018-02-08 19:06:49 -0800145}
146
147} // namespace internal
148} // namespace ceres
149%(preprocessor_conditions_end)s
150""")
151
Keir Mierle8549c882018-02-08 19:06:49 -0800152def camelcasify(token):
153 """Convert capitalized underscore tokens to camel case"""
154 return ''.join([x.lower().capitalize() for x in token.split('_')])
155
156
157def generate_bundle_test(linear_solver,
158 sparse_backend,
159 preconditioner,
160 ordering,
161 thread_config):
162 """Generate a bundle adjustment test executable configured appropriately"""
163
164 # Preconditioner only makes sense for iterative schur; drop it otherwise.
165 preconditioner_tag = preconditioner
166 if linear_solver != 'ITERATIVE_SCHUR':
167 preconditioner_tag = ''
168
169 # Omit references to the sparse backend when one is not in use.
170 sparse_backend_tag = sparse_backend
171 if sparse_backend == 'NO_SPARSE':
172 sparse_backend_tag = ''
173
174 # Use a double underscore; otherwise the names are harder to understand.
175 test_class_name = '_'.join(filter(lambda x: x, [
176 camelcasify(linear_solver),
177 camelcasify(sparse_backend_tag),
178 camelcasify(preconditioner_tag),
179 ordering[1:], # Strip 'k'
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700180 'Threads' if thread_config == MULTI_THREADED else '']))
Keir Mierle8549c882018-02-08 19:06:49 -0800181
182 # Initial template parameters (augmented more below).
183 template_parameters = dict(
184 linear_solver=linear_solver,
185 sparse_backend=sparse_backend,
186 preconditioner=preconditioner,
187 ordering=ordering,
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700188 num_threads=thread_config,
Keir Mierle8549c882018-02-08 19:06:49 -0800189 test_class_name=test_class_name)
190
191 # Accumulate appropriate #ifdef/#ifndefs for the solver's sparse backend.
192 preprocessor_conditions_begin = []
193 preprocessor_conditions_end = []
194 if sparse_backend == 'SUITE_SPARSE':
195 preprocessor_conditions_begin.append('#ifndef CERES_NO_SUITESPARSE')
196 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_SUITESPARSE')
197 elif sparse_backend == 'CX_SPARSE':
198 preprocessor_conditions_begin.append('#ifndef CERES_NO_CXSPARSE')
199 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_CXSPARSE')
Alex Stewart8f41ca62018-06-23 20:17:34 +0100200 elif sparse_backend == 'ACCELERATE_SPARSE':
201 preprocessor_conditions_begin.append('#ifndef CERES_NO_ACCELERATE_SPARSE')
202 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_ACCELERATE_SPARSE')
Keir Mierle8549c882018-02-08 19:06:49 -0800203 elif sparse_backend == 'EIGEN_SPARSE':
204 preprocessor_conditions_begin.append('#ifdef CERES_USE_EIGEN_SPARSE')
205 preprocessor_conditions_end.insert(0, '#endif // CERES_USE_EIGEN_SPARSE')
206
207 # Accumulate appropriate #ifdef/#ifndefs for threading conditions.
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700208 if thread_config == MULTI_THREADED:
Keir Mierle8549c882018-02-08 19:06:49 -0800209 preprocessor_conditions_begin.append('#ifndef CERES_NO_THREADS')
210 preprocessor_conditions_end.insert(0, '#endif // CERES_NO_THREADS')
211
212 # If there are #ifdefs, put newlines around them.
213 if preprocessor_conditions_begin:
214 preprocessor_conditions_begin.insert(0, '')
215 preprocessor_conditions_begin.append('')
216 preprocessor_conditions_end.insert(0, '')
217 preprocessor_conditions_end.append('')
218
219 # Put #ifdef/#ifndef stacks into the template parameters.
220 template_parameters['preprocessor_conditions_begin'] = '\n'.join(
221 preprocessor_conditions_begin)
222 template_parameters['preprocessor_conditions_end'] = '\n'.join(
223 preprocessor_conditions_end)
224
225 # Substitute variables into the test template, and write the result to a file.
226 filename_tag = '_'.join(FILENAME_SHORTENING_MAP.get(x) for x in [
227 linear_solver,
228 sparse_backend_tag,
229 preconditioner_tag,
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700230 ordering]
Keir Mierle8549c882018-02-08 19:06:49 -0800231 if FILENAME_SHORTENING_MAP.get(x))
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700232 if (thread_config == MULTI_THREADED):
233 filename_tag += '_threads'
234
Keir Mierle8549c882018-02-08 19:06:49 -0800235 filename = ('generated_bundle_adjustment_tests/ba_%s_test.cc' %
Sameer Agarwal4556eb92018-04-13 23:29:37 -0700236 filename_tag.lower())
Keir Mierle8549c882018-02-08 19:06:49 -0800237 with open(filename, 'w') as fd:
238 fd.write(BUNDLE_ADJUSTMENT_TEST_TEMPLATE % template_parameters)
239
240 # All done.
241 print 'Generated', filename
242
Keir Mierle0a301172018-03-01 13:55:43 -0800243 return filename
244
Keir Mierle8549c882018-02-08 19:06:49 -0800245
246if __name__ == '__main__':
247 # Iterate over all the possible configurations and generate the tests.
Keir Mierle0a301172018-03-01 13:55:43 -0800248 generated_files = []
Keir Mierle8549c882018-02-08 19:06:49 -0800249 for linear_solver, sparse_backend, preconditioner in SOLVER_CONFIGS:
250 for ordering in ORDERINGS:
251 for thread_config in THREAD_CONFIGS:
Keir Mierle0a301172018-03-01 13:55:43 -0800252 generated_files.append(
253 generate_bundle_test(linear_solver,
254 sparse_backend,
255 preconditioner,
256 ordering,
257 thread_config))
258
259 # Generate the CMakeLists.txt as well.
260 with open('generated_bundle_adjustment_tests/CMakeLists.txt', 'w') as fd:
261 fd.write(COPYRIGHT_HEADER.replace('//', '#').replace('http:#', 'http://'))
262 fd.write('\n')
263 fd.write('\n')
264 for generated_file in generated_files:
265 fd.write('ceres_test(%s)\n' %
266 generated_file.split('/')[1].replace('_test.cc', ''))