Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testMatrixDeterminant.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test various determinant computation methods.
32 */
33
38
39#include <visp3/core/vpMatrix.h>
40#include <visp3/core/vpTime.h>
41#include <visp3/io/vpParseArgv.h>
42
43// List of allowed command line options
44#define GETOPTARGS "cdn:i:pf:R:C:vh"
45
46#ifdef ENABLE_VISP_NAMESPACE
47using namespace VISP_NAMESPACE_NAME;
48#endif
49
50void usage(const char *name, const char *badparam);
51bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
52 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose);
53vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols);
54void create_bench(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
55 std::vector<vpMatrix> &bench);
56void test_det_default(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result);
57void save_time(const std::string &method, bool verbose, bool use_plot_file, std::ofstream &of, double time);
58#if defined(VISP_HAVE_EIGEN3)
59void test_det_eigen3(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result);
60#endif
61#if defined(VISP_HAVE_LAPACK)
62void test_det_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result);
63#endif
64#if defined(VISP_HAVE_OPENCV)
65void test_det_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result);
66#endif
67
74void usage(const char *name, const char *badparam)
75{
76 fprintf(stdout, "\n\
77Test matrix inversions\n\
78using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\
79Outputs a comparison of these methods.\n\
80\n\
81SYNOPSIS\n\
82 %s [-n <number of matrices>] [-f <plot filename>]\n\
83 [-R <number of rows>] [-C <number of columns>]\n\
84 [-i <number of iterations>] [-p] [-h]\n",
85 name);
86
87 fprintf(stdout, "\n\
88OPTIONS: Default\n\
89 -n <number of matrices> \n\
90 Number of matrices inverted during each test loop.\n\
91\n\
92 -i <number of iterations> \n\
93 Number of iterations of the test.\n\
94\n\
95 -f <plot filename> \n\
96 Set output path for plot output.\n\
97 The plot logs the times of \n\
98 the different inversion methods: \n\
99 QR,LU,Cholesky and Pseudo-inverse.\n\
100\n\
101 -R <number of rows>\n\
102 Number of rows of the automatically generated matrices \n\
103 we test on.\n\
104\n\
105 -C <number of columns>\n\
106 Number of colums of the automatically generated matrices \n\
107 we test on.\n\
108\n\
109 -p \n\
110 Plot into filename in the gnuplot format. \n\
111 If this option is used, tests results will be logged \n\
112 into a filename specified with -f.\n\
113\n\
114 -h\n\
115 Print the help.\n\n");
116
117 if (badparam) {
118 fprintf(stderr, "ERROR: \n");
119 fprintf(stderr, "\nBad parameter [%s]\n", badparam);
120 }
121}
122
130bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
131 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose)
132{
133 const char *optarg_;
134 int c;
135 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
136
137 switch (c) {
138 case 'h':
139 usage(argv[0], nullptr);
140 return false;
141 case 'n':
142 nb_matrices = static_cast<unsigned int>(atoi(optarg_));
143 break;
144 case 'i':
145 nb_iterations = static_cast<unsigned int>(atoi(optarg_));
146 break;
147 case 'f':
148 plotfile = optarg_;
149 use_plot_file = true;
150 break;
151 case 'p':
152 use_plot_file = true;
153 break;
154 case 'R':
155 nbrows = static_cast<unsigned int>(atoi(optarg_));
156 break;
157 case 'C':
158 nbcols = static_cast<unsigned int>(atoi(optarg_));
159 break;
160 case 'v':
161 verbose = true;
162 break;
163 // add default options -c -d
164 case 'c':
165 break;
166 case 'd':
167 break;
168 default:
169 usage(argv[0], optarg_);
170 return false;
171 }
172 }
173
174 if ((c == 1) || (c == -1)) {
175 // standalone param or error
176 usage(argv[0], nullptr);
177 std::cerr << "ERROR: " << std::endl;
178 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
179 return false;
180 }
181
182 return true;
183}
184
185vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols)
186{
187 vpMatrix A;
188 A.resize(nbrows, nbcols);
189
190 for (unsigned int i = 0; i < A.getRows(); i++)
191 for (unsigned int j = 0; j < A.getCols(); j++)
192 A[i][j] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
193 return A;
194}
195
196void create_bench(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
197 std::vector<vpMatrix> &bench)
198{
199 if (verbose)
200 std::cout << "Create a bench of " << nb_matrices << " " << nb_rows << " by " << nb_cols << " matrices" << std::endl;
201 bench.clear();
202 for (unsigned int i = 0; i < nb_matrices; i++) {
203 vpMatrix M = make_random_matrix(nb_rows, nb_cols);
204 bench.push_back(M);
205 }
206}
207
208void test_det_default(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result)
209{
210 if (verbose)
211 std::cout << "Test determinant using default method" << std::endl;
212 // Compute inverse
213 if (verbose)
214 std::cout << " Matrix size: " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols() << std::endl;
215
216 result.resize(bench.size());
217 double t = vpTime::measureTimeMs();
218 for (unsigned int i = 0; i < bench.size(); i++) {
219 result[i] = bench[i].AtA().det();
220 }
221 time = vpTime::measureTimeMs() - t;
222}
223
224#if defined(VISP_HAVE_EIGEN3)
225void test_det_eigen3(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result)
226{
227 if (verbose)
228 std::cout << "Test determinant using Eigen3 3rd party" << std::endl;
229 // Compute inverse
230 if (verbose)
231 std::cout << " Matrix size: " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols() << std::endl;
232
233 result.resize(bench.size());
234 double t = vpTime::measureTimeMs();
235 for (unsigned int i = 0; i < bench.size(); i++) {
236 result[i] = bench[i].AtA().detByLUEigen3();
237 }
238 time = vpTime::measureTimeMs() - t;
239}
240#endif
241
242#if defined(VISP_HAVE_LAPACK)
243void test_det_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result)
244{
245 if (verbose)
246 std::cout << "Test determinant using Lapack 3rd party" << std::endl;
247 // Compute inverse
248 if (verbose)
249 std::cout << " Matrix size: " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols() << std::endl;
250
251 result.resize(bench.size());
252 double t = vpTime::measureTimeMs();
253 for (unsigned int i = 0; i < bench.size(); i++) {
254 result[i] = bench[i].AtA().detByLULapack();
255 }
256 time = vpTime::measureTimeMs() - t;
257}
258#endif
259
260#if defined(VISP_HAVE_OPENCV)
261void test_det_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time, std::vector<double> &result)
262{
263 if (verbose)
264 std::cout << "Test determinant using OpenCV 3rd party" << std::endl;
265 // Compute inverse
266 if (verbose)
267 std::cout << " Matrix size: " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols() << std::endl;
268
269 result.resize(bench.size());
270 double t = vpTime::measureTimeMs();
271 for (unsigned int i = 0; i < bench.size(); i++) {
272 result[i] = bench[i].AtA().detByLUOpenCV();
273 }
274 time = vpTime::measureTimeMs() - t;
275}
276#endif
277
278void save_time(const std::string &method, bool verbose, bool use_plot_file, std::ofstream &of, double time)
279{
280 if (use_plot_file)
281 of << time << "\t";
282 if (verbose || !use_plot_file) {
283 std::cout << method << time << std::endl;
284 }
285}
286
287int main(int argc, const char *argv[])
288{
289 try {
290#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
291 unsigned int nb_matrices = 1000;
292 unsigned int nb_iterations = 10;
293 unsigned int nb_rows = 6;
294 unsigned int nb_cols = 6;
295 bool verbose = false;
296 std::string plotfile("plot-det.csv");
297 bool use_plot_file = false;
298 std::ofstream of;
299
300 // Read the command line options
301 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
302 false) {
303 return EXIT_FAILURE;
304 }
305
306 if (use_plot_file) {
307 of.open(plotfile.c_str());
308 of << "iter"
309 << "\t";
310
311 of << "\"Determinant default\""
312 << "\t";
313
314#if defined(VISP_HAVE_LAPACK)
315 of << "\"Determinant Lapack\""
316 << "\t";
317#endif
318#if defined(VISP_HAVE_EIGEN3)
319 of << "\"Determinant Eigen3\""
320 << "\t";
321#endif
322#if defined(VISP_HAVE_OPENCV)
323 of << "\"Determinant OpenCV\""
324 << "\t";
325#endif
326 of << std::endl;
327 }
328
329 int ret = EXIT_SUCCESS;
330 for (unsigned int iter = 0; iter < nb_iterations; iter++) {
331 std::vector<vpMatrix> bench;
332 create_bench(nb_matrices, nb_rows, nb_cols, verbose, bench);
333
334 if (use_plot_file)
335 of << iter << "\t";
336
337 double time;
338
339 std::vector<double> result_default;
340 test_det_default(verbose, bench, time, result_default);
341 save_time("Determinant default: ", verbose, use_plot_file, of, time);
342
343#if defined(VISP_HAVE_LAPACK)
344 std::vector<double> result_lapack;
345 test_det_lapack(verbose, bench, time, result_lapack);
346 save_time("Determinant by Lapack: ", verbose, use_plot_file, of, time);
347#endif
348
349#if defined(VISP_HAVE_EIGEN3)
350 std::vector<double> result_eigen3;
351 test_det_eigen3(verbose, bench, time, result_eigen3);
352 save_time("Determinant by Eigen3: ", verbose, use_plot_file, of, time);
353#endif
354
355#if defined(VISP_HAVE_OPENCV)
356 std::vector<double> result_opencv;
357 test_det_opencv(verbose, bench, time, result_opencv);
358 save_time("Determinant by OpenCV: ", verbose, use_plot_file, of, time);
359#endif
360
361 if (use_plot_file)
362 of << std::endl;
363
364#if defined(VISP_HAVE_LAPACK) && defined(VISP_HAVE_OPENCV)
365 // Compare results
366 for (unsigned int i = 0; i < bench.size(); i++) {
367 if (std::fabs(result_lapack[i] - result_opencv[i]) > 1e-6) {
368 std::cout << "Determinant differ between Lapack and OpenCV: " << result_lapack[i] << " " << result_opencv[i]
369 << std::endl;
370 ret = EXIT_FAILURE;
371 }
372 }
373#endif
374#if defined(VISP_HAVE_EIGEN3) && defined(VISP_HAVE_OPENCV)
375 // Compare results
376 for (unsigned int i = 0; i < bench.size(); i++) {
377 if (std::fabs(result_eigen3[i] - result_opencv[i]) > 1e-6) {
378 std::cout << "Determinant differ between Eigen3 and OpenCV: " << result_eigen3[i] << " " << result_opencv[i]
379 << std::endl;
380 ret = EXIT_FAILURE;
381 }
382 }
383#endif
384#if defined(VISP_HAVE_EIGEN3) && defined(VISP_HAVE_LAPACK)
385 // Compare results
386 for (unsigned int i = 0; i < bench.size(); i++) {
387 if (std::fabs(result_eigen3[i] - result_lapack[i]) > 1e-6) {
388 std::cout << "Determinant differ between Eigen3 and Lapack: " << result_eigen3[i] << " " << result_lapack[i]
389 << std::endl;
390 ret = EXIT_FAILURE;
391 }
392 }
393#endif
394 }
395 if (use_plot_file) {
396 of.close();
397 std::cout << "Result saved in " << plotfile << std::endl;
398 }
399
400 if (ret == EXIT_SUCCESS) {
401 std::cout << "Test succeed" << std::endl;
402 }
403 else {
404 std::cout << "Test failed" << std::endl;
405 }
406
407 return ret;
408#else
409 (void)argc;
410 (void)argv;
411 std::cout << "Test does nothing since you dont't have Lapack, Eigen3 or OpenCV 3rd party" << std::endl;
412 return EXIT_SUCCESS;
413#endif
414 }
415 catch (const vpException &e) {
416 std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
417 return EXIT_FAILURE;
418 }
419}
unsigned int getCols() const
Definition vpArray2D.h:423
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
unsigned int getRows() const
Definition vpArray2D.h:433
error that can be emitted by ViSP classes.
Definition vpException.h:60
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
void clear()
Definition vpMatrix.h:247
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()