diff --git a/modules/core/include/visp3/core/vpColVector.h b/modules/core/include/visp3/core/vpColVector.h index 3c734daf6c..d35ee41b40 100644 --- a/modules/core/include/visp3/core/vpColVector.h +++ b/modules/core/include/visp3/core/vpColVector.h @@ -1,6 +1,6 @@ /* * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2025 by Inria. All rights reserved. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -195,24 +195,24 @@ class VISP_EXPORT vpColVector : public vpArray2D /*! * Basic constructor that creates an empty 0-size column vector. */ - vpColVector() : vpArray2D() { } + vpColVector() : vpArray2D() {} /*! * Construct a column vector of size n. * \warning Elements are not initialized. If you want to set an initial value use * vpColVector(unsigned int, double). */ - VP_EXPLICIT vpColVector(unsigned int n) : vpArray2D(n, 1) { } + VP_EXPLICIT vpColVector(unsigned int n) : vpArray2D(n, 1) {} /*! * Construct a column vector of size n. Each element is set to \e val. */ - vpColVector(unsigned int n, double val) : vpArray2D(n, 1, val) { } + vpColVector(unsigned int n, double val) : vpArray2D(n, 1, val) {} /*! * Copy constructor that allows to construct a column vector from an other one. */ - vpColVector(const vpColVector &v) : vpArray2D(v) { } + vpColVector(const vpColVector &v) : vpArray2D(v) {} /*! * Construct a column vector from a part of an input column vector \e v. @@ -904,27 +904,51 @@ class VISP_EXPORT vpColVector : public vpArray2D vpTranslationVector operator+(const vpTranslationVector &t) const; /*! - * Operator that allows to add two column vectors. + * In-place addition of a column vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e v. + * + * \param v The vector to add. + * \return A reference to the current vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ vpColVector &operator+=(const vpColVector &v); /*! - * Operator that allows to add a 3-dim translation vector to a 3-dim column vector. + * In-place addition of a translation vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e t. + * + * \param t The 3-dim translation vector to add. + * \return A reference to the current vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ vpColVector &operator+=(const vpTranslationVector &t); /*! - * Operator subtraction of two vectors this = this - v + * Subtraction of two vectors: result = this - v. + * + * \param v The vector to subtract. + * \return A new vector containing the result of the subtraction. + * \exception vpException::dimensionError If the dimensions do not match. */ vpColVector operator-(const vpColVector &v) const; /*! - * Operator that allows to subtract two column vectors. + * In-place subtraction of a column vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e v. + * + * \param v The vector to subtract. + * \return A reference to the current vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ vpColVector &operator-=(const vpColVector &v); /*! - * Operator that allows to subtract a 3-dim translation vector to a 3-dim column vector. + * In-place subtraction of a translation vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e t. + * + * \param t The 3-dim translation vector to suntract. + * \return A reference to the current vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ vpColVector &operator-=(const vpTranslationVector &t); @@ -1467,7 +1491,7 @@ class VISP_EXPORT vpColVector : public vpArray2D * \deprecated Provided only for compat with previous releases. * This function does nothing. */ - VP_DEPRECATED void init() { } + VP_DEPRECATED void init() {} /*! * \deprecated Provided only for compat with previous releases. Use rather diff --git a/modules/core/include/visp3/core/vpRowVector.h b/modules/core/include/visp3/core/vpRowVector.h index d8af6e545d..a8a41f2336 100644 --- a/modules/core/include/visp3/core/vpRowVector.h +++ b/modules/core/include/visp3/core/vpRowVector.h @@ -1,6 +1,6 @@ /* * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2025 by Inria. All rights reserved. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -124,15 +124,15 @@ class VISP_EXPORT vpRowVector : public vpArray2D { public: //! Basic constructor that creates an empty 0-size row vector. - vpRowVector() : vpArray2D() { } + vpRowVector() : vpArray2D() {} //! Construct a row vector of size n. All the elements are initialized to //! zero. - VP_EXPLICIT vpRowVector(unsigned int n) : vpArray2D(1, n) { } + VP_EXPLICIT vpRowVector(unsigned int n) : vpArray2D(1, n) {} //! Construct a row vector of size n. Each element is set to \e val. - vpRowVector(unsigned int n, double val) : vpArray2D(1, n, val) { } + vpRowVector(unsigned int n, double val) : vpArray2D(1, n, val) {} //! Copy constructor that allows to construct a row vector from an other //! one. - vpRowVector(const vpRowVector &v) : vpArray2D(v) { } + vpRowVector(const vpRowVector &v) : vpArray2D(v) {} vpRowVector(const vpRowVector &v, unsigned int c, unsigned int ncols); VP_EXPLICIT vpRowVector(const vpMatrix &M); vpRowVector(const vpMatrix &M, unsigned int i); @@ -140,7 +140,7 @@ class VISP_EXPORT vpRowVector : public vpArray2D VP_EXPLICIT vpRowVector(const std::vector &v); #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) vpRowVector(vpRowVector &&v); - VP_EXPLICIT vpRowVector(const std::initializer_list &list) : vpArray2D(list) { } + VP_EXPLICIT vpRowVector(const std::initializer_list &list) : vpArray2D(list) {} #endif static vpRowVector view(double *raw_data, unsigned int ncols); @@ -259,10 +259,10 @@ class VISP_EXPORT vpRowVector : public vpArray2D vpRowVector &operator/=(double x); vpRowVector operator+(const vpRowVector &v) const; - vpRowVector &operator+=(vpRowVector v); + vpRowVector &operator+=(const vpRowVector &v); vpRowVector operator-(const vpRowVector &v) const; - vpRowVector &operator-=(vpRowVector v); + vpRowVector &operator-=(const vpRowVector &v); vpRowVector operator-() const; vpRowVector &operator<<(const vpRowVector &v); @@ -337,7 +337,7 @@ class VISP_EXPORT vpRowVector : public vpArray2D \deprecated Provided only for compat with previous releases. This function does nothing. */ - VP_DEPRECATED void init() { } + VP_DEPRECATED void init() {} /*! \deprecated You should rather use stack(const vpRowVector &) */ diff --git a/modules/core/src/math/matrix/vpColVector.cpp b/modules/core/src/math/matrix/vpColVector.cpp index c6da2c97b3..b64c46f2bd 100644 --- a/modules/core/src/math/matrix/vpColVector.cpp +++ b/modules/core/src/math/matrix/vpColVector.cpp @@ -1,6 +1,6 @@ /* * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2025 by Inria. All rights reserved. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -89,7 +89,10 @@ vpTranslationVector vpColVector::operator+(const vpTranslationVector &t) const vpColVector &vpColVector::operator+=(const vpColVector &v) { - if (getRows() != v.getRows()) { + if (getRows() == 0) { + resize(v.getRows(), true); + } + else if (getRows() != v.getRows()) { throw(vpException(vpException::dimensionError, "Cannot add (%dx1) column vector to (%dx1) column vector", getRows(), v.getRows())); } @@ -102,7 +105,10 @@ vpColVector &vpColVector::operator+=(const vpColVector &v) vpColVector &vpColVector::operator+=(const vpTranslationVector &t) { - if (getRows() != t.getRows()) { + if (getRows() == 0) { + resize(t.getRows(), true); + } + else if (getRows() != t.getRows()) { throw(vpException(vpException::dimensionError, "Cannot add (%dx1) translation vector to (%dx1) column vector", getRows(), t.getRows())); } @@ -115,7 +121,10 @@ vpColVector &vpColVector::operator+=(const vpTranslationVector &t) vpColVector &vpColVector::operator-=(const vpColVector &v) { - if (getRows() != v.getRows()) { + if (getRows() == 0) { + resize(v.getRows(), true); + } + else if (getRows() != v.getRows()) { throw(vpException(vpException::dimensionError, "Cannot subtract (%dx1) column vector to (%dx1) column vector", getRows(), v.getRows())); } @@ -128,7 +137,10 @@ vpColVector &vpColVector::operator-=(const vpColVector &v) vpColVector &vpColVector::operator-=(const vpTranslationVector &t) { - if (getRows() != t.getRows()) { + if (getRows() == 0) { + resize(t.getRows(), true); + } + else if (getRows() != t.getRows()) { throw(vpException(vpException::dimensionError, "Cannot subtract (%dx1) translation vector to (%dx1) column vector", getRows(), t.getRows())); } diff --git a/modules/core/src/math/matrix/vpRowVector.cpp b/modules/core/src/math/matrix/vpRowVector.cpp index a4b0b80065..3ff60f9d9d 100644 --- a/modules/core/src/math/matrix/vpRowVector.cpp +++ b/modules/core/src/math/matrix/vpRowVector.cpp @@ -1,6 +1,6 @@ /* * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2025 by Inria. All rights reserved. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -448,13 +448,19 @@ vpRowVector vpRowVector::operator+(const vpRowVector &v) const } /*! - Operator that allows to add two row vectors that have the same size. - \exception vpException::dimensionError If the size of the two vectors - differ. + * In-place addition of a row vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e v. + * + * \param v The row vector to add. + * \return A reference to the current row vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ -vpRowVector &vpRowVector::operator+=(vpRowVector v) +vpRowVector &vpRowVector::operator+=(const vpRowVector &v) { - if (getCols() != v.getCols()) { + if (getCols() == 0) { + resize(v.getCols(), true); + } + else if (getCols() != v.getCols()) { throw(vpException(vpException::dimensionError, "Cannot add (1x%d) row vector to (1x%d) row vector", getCols(), v.getCols())); } @@ -466,13 +472,19 @@ vpRowVector &vpRowVector::operator+=(vpRowVector v) } /*! - Operator that allows to subtract two row vectors that have the same size. - \exception vpException::dimensionError If the size of the two vectors - differ. + * In-place subtraction of a row vector. + * If the current vector is empty, it is automatically resized to the dimensions of \e v. + * + * \param v The row vector to subtract. + * \return A reference to the current row vector. + * \exception vpException::dimensionError If the dimensions do not match and the vector is not empty. */ -vpRowVector &vpRowVector::operator-=(vpRowVector v) +vpRowVector &vpRowVector::operator-=(const vpRowVector &v) { - if (getCols() != v.getCols()) { + if (getCols() == 0) { + resize(v.getCols(), true); + } + else if (getCols() != v.getCols()) { throw(vpException(vpException::dimensionError, "Cannot subtract (1x%d) row vector to (1x%d) row vector", getCols(), v.getCols())); } @@ -621,7 +633,7 @@ vpRowVector::vpRowVector(const vpRowVector &v, unsigned int c, unsigned int ncol #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) vpRowVector::vpRowVector(vpRowVector &&v) : vpArray2D(std::move(v)) -{ } +{} #endif /*! diff --git a/modules/core/test/math/catchColVector.cpp b/modules/core/test/math/catchColVector.cpp new file mode 100644 index 0000000000..5f1d8af1ee --- /dev/null +++ b/modules/core/test/math/catchColVector.cpp @@ -0,0 +1,262 @@ +/* + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/*! + \example catchColVector.cpp + + Test some vpColVector functionalities. +*/ + +#include + +#if defined(VISP_HAVE_CATCH2) +#include +#include +#include + +#include +#include +#include +#include + +#if defined(VISP_BUILD_CATCH2) +#include +#else +#include +#endif + +#ifdef ENABLE_VISP_NAMESPACE +using namespace VISP_NAMESPACE_NAME; +#endif + +namespace +{ +void checkData(const vpColVector &v, const std::vector &bench) +{ + REQUIRE(v.size() == bench.size()); + for (unsigned int i = 0; i < v.size(); i++) { + REQUIRE(v[i] == Catch::Approx(bench[i]).epsilon(std::numeric_limits::epsilon())); + } +} +} // namespace + +TEST_CASE("vpColVector basic operations", "[vpColVector]") +{ + SECTION("Comparison operators") + { + vpColVector v1(7, 0.1), v2; + REQUIRE_FALSE(v1 == v2); + v2 = v1; + REQUIRE(v1 == v2); + v2[3] = 0.2; + REQUIRE(v1 != v2); + } + + SECTION("Resizing and normalization") + { + vpColVector v(4); + v = 3; + checkData(v, { 3, 3, 3, 3 }); + v.normalize(); + checkData(v, { 3./6, 3./6, 3./6, 3./6 }); + + v.resize(5, 1, true); + checkData(v, { 0, 0, 0, 0, 0 }); + } + + SECTION("Clear and resize") + { + vpColVector r(5, 1); + r.clear(); + r.resize(5); + r = 5; + checkData(r, { 5, 5, 5, 5, 5 }); + } +} + +TEST_CASE("vpColVector extraction and stacking", "[vpColVector]") +{ + vpColVector v(4); + for (unsigned int i = 0; i < v.size(); i++) v[i] = static_cast(i); + + vpColVector w; + w.init(v, 0, 2); + checkData(w, { 0, 1 }); + + vpColVector r1; + for (size_t i = 0; i < 4; i++) r1.stack(static_cast(i)); + vpColVector r2 = r1.extract(1, 3); + checkData(r2, { 1, 2, 3 }); +} + +TEST_CASE("vpColVector constructors and assignment", "[vpColVector]") +{ + vpMatrix M(4, 1); + std::vector bench(4); + for (unsigned int i = 0; i < M.getRows(); i++) { M[i][0] = i; bench[i] = i; } + + checkData(vpColVector(M), bench); + vpColVector v; + v = M; + checkData(v, bench); + vpColVector w(M); + checkData(w, bench); + vpColVector z1(bench); + checkData(z1, bench); +} + +TEST_CASE("vpColVector math operations", "[vpColVector]") +{ + SECTION("Multiplication and stacking") + { + vpColVector v(3); + v[0] = 1; v[1] = 2; v[2] = 3; + std::vector bench1 = { 3, 6, 9 }; + + checkData(v * 3, bench1); + + vpColVector r1(3, 1); + vpColVector r2 = -r1; + checkData(r2, { -1, -1, -1 }); + + r2.stack(-2); + vpColVector r3 = vpColVector::stack(r1, r2); + checkData(r3, { 1, 1, 1, -1, -1, -1, -2 }); + } + + SECTION("Addition and subtraction") + { + vpColVector r1(3, 2); + vpColVector r2(3, 4); + + vpColVector r_add = r1 + r2; + checkData(r_add, { 6, 6, 6 }); + r1 += r2; + checkData(r1, { 6, 6, 6 }); + + vpColVector r3(3, 2); + vpColVector r4(3, 4); + vpColVector r_sub = r3 - r4; + checkData(r_sub, { -2, -2, -2 }); + r3 -= r4; + checkData(r3, { -2, -2, -2 }); + } + + SECTION("Operator += and -=") + { + vpColVector r1(3, -2); + vpColVector r2; + r2 += r1; + checkData(r2, { -2, -2, -2 }); + vpColVector r3; + r3 -= r1; + checkData(r3, { 2, 2, 2 }); + vpColVector r4; + vpTranslationVector t(1, 2, 3); + r4 += t; + checkData(r4, { 1, 2, 3 }); + vpColVector r5; + r5 -= t; + checkData(r5, { -1, -2, -3 }); + } +} + +TEST_CASE("vpColVector statistics", "[vpColVector]") +{ + vpColVector r(10); + r = { 8.1472, 9.0579, 1.2699, 9.1338, 6.3236, 0.9754, 2.7850, 5.4688, 9.5751, 9.6489 }; + + REQUIRE(vpColVector::mean(r) == Catch::Approx(6.2386).margin(0.001)); + REQUIRE(vpColVector::stdev(r) == Catch::Approx(3.2810).margin(0.001)); + REQUIRE(vpColVector::stdev(r, true) == Catch::Approx(3.4585).margin(0.001)); + REQUIRE(vpColVector::median(r) == Catch::Approx(7.2354).margin(0.001)); + + SECTION("Median (odd)") + { + r.stack(1.5761); + REQUIRE(vpColVector::median(r) == Catch::Approx(6.3236).margin(0.001)); + } +} + +TEST_CASE("vpColVector insertion", "[vpColVector]") +{ + unsigned int nb = 10, size = 100; + std::vector vec(nb, vpColVector(size)); + for (auto &v : vec) for (unsigned int j = 0; j std_v = { 0, 1, 2, 3, 4 }; + vpColVector v(std_v); + checkData(v, std_v); + + std::vector std_v2 = v.toStdVector(); + checkData(v, std_v2); + } + + SECTION("Scalar comparison") + { + vpColVector v(3, 1.); + REQUIRE_FALSE(v != 1.0); + REQUIRE_FALSE(v == 0.0); + v[1] = 0.0; + REQUIRE_FALSE(v == 0.0); + } +} + +int main(int argc, char *argv[]) +{ + Catch::Session session; + session.applyCommandLine(argc, argv); + int numFailed = session.run(); + std::cout << (numFailed ? "Test failed" : "Test succeed") << std::endl; + return numFailed; +} +#else +int main() { return EXIT_SUCCESS; } +#endif diff --git a/modules/core/test/math/catchRowVector.cpp b/modules/core/test/math/catchRowVector.cpp new file mode 100644 index 0000000000..504c20a872 --- /dev/null +++ b/modules/core/test/math/catchRowVector.cpp @@ -0,0 +1,222 @@ +/* + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/*! + \example catchRowVector.cpp + + Test some vpRowVector functionalities. +*/ + +#include + +#if defined(VISP_HAVE_CATCH2) +#include +#include +#include + +#include +#include + +#if defined(VISP_BUILD_CATCH2) +#include +#else +#include +#endif + +#ifdef ENABLE_VISP_NAMESPACE +using namespace VISP_NAMESPACE_NAME; +#endif + +namespace +{ +void checkData(const vpRowVector &v, const std::vector &bench) +{ + REQUIRE(v.size() == bench.size()); + for (unsigned int i = 0; i < v.size(); i++) { + REQUIRE(v[i] == Catch::Approx(bench[i]).epsilon(std::numeric_limits::epsilon())); + } +} +} // namespace + +TEST_CASE("vpRowVector basic operations", "[vpRowVector]") +{ + SECTION("Resizing and normalization") + { + vpRowVector v(4); + v = 3; + checkData(v, { 3, 3, 3, 3 }); + v.normalize(); + checkData(v, { 3./6, 3./6, 3./6, 3./6 }); + + v.resize(1, 5, true); + checkData(v, { 0, 0, 0, 0, 0 }); + } + + SECTION("Clear and resize") + { + vpRowVector r(5, 1); + r.clear(); + r.resize(5); + r = 5; + checkData(r, { 5, 5, 5, 5, 5 }); + } +} + +TEST_CASE("vpRowVector extraction and stacking", "[vpRowVector]") +{ + vpRowVector v(4); + for (unsigned int i = 0; i < v.size(); i++) v[i] = static_cast(i); + + vpRowVector w; + w.init(v, 0, 2); + checkData(w, { 0, 1 }); + + vpRowVector r1; + for (size_t i = 0; i < 4; i++) r1.stack(static_cast(i)); + vpRowVector r2 = r1.extract(1, 3); + checkData(r2, { 1, 2, 3 }); +} + +TEST_CASE("vpRowVector constructors and assignment", "[vpRowVector]") +{ + SECTION("Constructor with vpMatrix") + { + vpMatrix M(1, 4); + std::vector bench(4); + for (unsigned int i = 0; i < M.getCols(); i++) { M[0][i] = i; bench[i] = i; } + + checkData(vpRowVector(M), bench); + vpRowVector v; + v = M; + checkData(v, bench); + vpRowVector w(M); + checkData(w, bench); + vpRowVector z1(bench); + checkData(z1, bench); + } + + SECTION("Constructor with std::vector") + { + std::vector bench_f = { 3.0f, 6.0f, 9.0f }; + std::vector bench_d = { 3.0, 6.0, 9.0 }; + vpRowVector y1(bench_f); + checkData(y1, bench_d); + vpRowVector y2 = vpRowVector(bench_f); + checkData(y2, bench_d); + } +} + +TEST_CASE("vpRowVector math operations", "[vpRowVector]") +{ + SECTION("Multiplication and stacking") + { + vpRowVector v(3); + v[0] = 1; v[1] = 2; v[2] = 3; + std::vector bench1 = { 3, 6, 9 }; + + checkData(v * 3, bench1); + + vpRowVector r1(3, 1); + vpRowVector r2 = -r1; + checkData(r2, { -1, -1, -1 }); + + r2.stack(-2); + vpRowVector r3 = vpRowVector::stack(r1, r2); + checkData(r3, { 1, 1, 1, -1, -1, -1, -2 }); + } + + SECTION("Addition and subtraction") + { + vpRowVector r1(3, 2); + vpRowVector r2(3, 4); + + vpRowVector r_add = r1 + r2; + checkData(r_add, { 6, 6, 6 }); + r1 += r2; + checkData(r1, { 6, 6, 6 }); + + vpRowVector r3(3, 2); + vpRowVector r4(3, 4); + vpRowVector r_sub = r3 - r4; + checkData(r_sub, { -2, -2, -2 }); + r3 -= r4; + checkData(r3, { -2, -2, -2 }); + } + + SECTION("Operator += and -=") + { + vpRowVector r1(3, -2); + vpRowVector r2; + r2 += r1; + checkData(r2, { -2, -2, -2 }); + vpRowVector r3; + r3 -= r1; + checkData(r3, { 2, 2, 2 }); + } +} + +TEST_CASE("vpRowVector statistics", "[vpRowVector]") +{ + vpRowVector r(10); + r = { 8.1472, 9.0579, 1.2699, 9.1338, 6.3236, 0.9754, 2.7850, 5.4688, 9.5751, 9.6489 }; + + REQUIRE(vpRowVector::mean(r) == Catch::Approx(6.2386).margin(0.001)); + REQUIRE(vpRowVector::stdev(r) == Catch::Approx(3.2810).margin(0.001)); + REQUIRE(vpRowVector::stdev(r, true) == Catch::Approx(3.4585).margin(0.001)); + REQUIRE(vpRowVector::median(r) == Catch::Approx(7.2354).margin(0.001)); + + SECTION("Median (odd)") + { + r.stack(1.5761); + REQUIRE(vpRowVector::median(r) == Catch::Approx(6.3236).margin(0.001)); + } +} + +TEST_CASE("vpRowVector conversions", "[vpRowVector]") +{ + std::vector std_v = { 0, 1, 2, 3, 4 }; + vpRowVector v(std_v); + checkData(v, std_v); + + std::vector std_v2 = v.toStdVector(); + checkData(v, std_v2); +} + +int main(int argc, char *argv[]) +{ + Catch::Session session; + session.applyCommandLine(argc, argv); + int numFailed = session.run(); + std::cout << (numFailed ? "Test failed" : "Test succeed") << std::endl; + return numFailed; +} +#else +int main() { return EXIT_SUCCESS; } +#endif diff --git a/modules/core/test/math/testColVector.cpp b/modules/core/test/math/testColVector.cpp deleted file mode 100644 index db4a3f8251..0000000000 --- a/modules/core/test/math/testColVector.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* - * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2024 by Inria. All rights reserved. - * - * This software is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * See the file LICENSE.txt at the root directory of this source - * distribution for additional information about the GNU GPL. - * - * For using ViSP with software that can not be combined with the GNU - * GPL, please contact Inria about acquiring a ViSP Professional - * Edition License. - * - * See https://visp.inria.fr for more information. - * - * This software was developed at: - * Inria Rennes - Bretagne Atlantique - * Campus Universitaire de Beaulieu - * 35042 Rennes Cedex - * France - * - * If you have questions regarding the use of this file, please contact - * Inria at visp@inria.fr - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Description: - * Test some vpColVector functionalities. - */ - -/*! - \example testColVector.cpp - - Test some vpColVector functionalities. -*/ - -#include -#include - -#include -#include -#include - -#ifdef ENABLE_VISP_NAMESPACE -using namespace VISP_NAMESPACE_NAME; -#endif - -namespace -{ -bool test(const std::string &s, const vpColVector &v, const std::vector &bench) -{ - static unsigned int cpt = 0; - std::cout << "** Test " << ++cpt << std::endl; - std::cout << s << "(" << v.getRows() << "," << v.getCols() << ") = [" << v.t() << "]^T" << std::endl; - if (bench.size() != v.size()) { - std::cout << "Test fails: bad size wrt bench" << std::endl; - return false; - } - for (unsigned int i = 0; i < v.size(); i++) { - if (std::fabs(v[i] - bench[i]) > std::fabs(v[i]) * std::numeric_limits::epsilon()) { - std::cout << "Test fails: bad content" << std::endl; - return false; - } - } - - return true; -} - -double getRandomValues(double min, double max) { return (max - min) * (static_cast(rand()) / static_cast(RAND_MAX)) + min; } -} // namespace - -int main() -{ - { - vpColVector v1(7, 0.1), v2; - if (v1 == v2) { - std::cerr << "Issue with vpColVector comparison operator." << std::endl; - return EXIT_FAILURE; - } - v2 = v1; - if (v1 != v2) { - std::cerr << "Issue with vpColVector comparison operator." << std::endl; - return EXIT_FAILURE; - } - v2[3] = 0.2; - if (v1 == v2) { - std::cerr << "Issue with vpColVector comparison operator." << std::endl; - return EXIT_FAILURE; - } - } - { - vpColVector v; - - v.resize(4); - v = 3; - std::vector bench1(4, 3); - if (test("v", v, bench1) == false) - return EXIT_FAILURE; - std::vector bench2(4, 3. / 6); - v.normalize(); - if (test("v", v, bench2) == false) - return EXIT_FAILURE; - - v.resize(5, 1, true); - std::vector bench3(5, 0); - if (test("v", v, bench3) == false) - return EXIT_FAILURE; - } - - { - vpColVector v(4); - std::vector bench1(4); - for (unsigned int i = 0; i < v.size(); i++) { - v[i] = static_cast(i); - bench1[i] = static_cast(i); - } - if (test("v", v, bench1) == false) - return EXIT_FAILURE; - - vpColVector w; - w.init(v, 0, 2); - std::vector bench2; - bench2.push_back(0); - bench2.push_back(1); - if (test("w", w, bench2) == false) - return EXIT_FAILURE; - - std::vector bench3; - bench3.push_back(1); - bench3.push_back(2); - bench3.push_back(3); - - vpColVector r1; - for (size_t i = 0; i < 4; i++) - r1.stack(static_cast(i)); - - vpColVector r2 = r1.extract(1, 3); - if (test("r2", r2, bench3) == false) - return EXIT_FAILURE; - } - - { - vpMatrix M(4, 1); - std::vector bench(4); - for (unsigned int i = 0; i < M.getRows(); i++) { - M[i][0] = i; - bench[i] = i; - } - if (test("M", vpColVector(M), bench) == false) - return EXIT_FAILURE; - vpColVector v; - v = M; - if (test("v", v, bench) == false) - return EXIT_FAILURE; - vpColVector w(M); - if (test("w", w, bench) == false) - return EXIT_FAILURE; - vpColVector z1(bench); - if (test("z1", z1, bench) == false) - return EXIT_FAILURE; - vpColVector z2 = vpColVector(bench); - if (test("z2", z2, bench) == false) - return EXIT_FAILURE; - } - - { - vpColVector v(3); - v[0] = 1; - v[1] = 2; - v[2] = 3; - std::vector bench1; - bench1.push_back(3); - bench1.push_back(6); - bench1.push_back(9); - - vpColVector w = v * 3; - // v is unchanged - // w is now equal to : [3 6 9] - if (test("w", w, bench1) == false) - return EXIT_FAILURE; - - vpColVector x(w); - if (test("x", x, bench1) == false) - return EXIT_FAILURE; - - std::vector bench2; - bench2.push_back(3); - bench2.push_back(6); - bench2.push_back(9); - vpColVector y1(bench2); - if (test("y1", y1, bench1) == false) - return EXIT_FAILURE; - vpColVector y2 = vpColVector(bench2); - if (test("y2", y2, bench1) == false) - return EXIT_FAILURE; - } - - { - vpColVector r1(3, 1); - vpColVector r2 = -r1; - std::vector bench(3, -1); - // v contains [-1 -1 -1] - if (test("r2", r2, bench) == false) - return EXIT_FAILURE; - r2.stack(-2); - bench.push_back(-2); - if (test("r2", r2, bench) == false) - return EXIT_FAILURE; - vpColVector r3 = vpColVector::stack(r1, r2); - std::vector bench3(7, 1); - bench3[3] = bench3[4] = bench3[5] = -1; - bench3[6] = -2; - if (test("r3", r3, bench3) == false) - return EXIT_FAILURE; - - r1.stack(r2); - if (test("r1", r1, bench3) == false) - return EXIT_FAILURE; - } - - { - vpColVector r1(3, 2); - vpColVector r2(3, 4); - std::cout << "test r1: " << r1 << std::endl; - std::cout << "test r2: " << r2 << std::endl; - vpColVector r = r1 + r2; - std::cout << "test r1+r2: " << r1 + r2 << std::endl; - std::cout << "test r: " << r << std::endl; - std::vector bench(3, 6); - if (test("r", r, bench) == false) - return EXIT_FAILURE; - r1 += r2; - if (test("r1", r1, bench) == false) - return EXIT_FAILURE; - } - - { - vpColVector r1(3, 2); - vpColVector r2(3, 4); - vpColVector r = r1 - r2; - std::vector bench(3, -2); - if (test("r", r, bench) == false) - return EXIT_FAILURE; - r1 -= r2; - if (test("r1", r1, bench) == false) - return EXIT_FAILURE; - } - - { - vpColVector r(5, 1); - r.clear(); - r.resize(5); - r = 5; - std::vector bench(5, 5); - if (test("r", r, bench) == false) - return EXIT_FAILURE; - } - - { - // Test mean, median and standard deviation against Matlab with rng(0) and - // rand(10,1)*10 - vpColVector r(10); - r[0] = 8.1472; - r[1] = 9.0579; - r[2] = 1.2699; - r[3] = 9.1338; - r[4] = 6.3236; - r[5] = 0.9754; - r[6] = 2.7850; - r[7] = 5.4688; - r[8] = 9.5751; - r[9] = 9.6489; - - std::cout << "** Test mean" << std::endl; - double res = vpColVector::mean(r); - if (!vpMath::equal(res, 6.2386, 0.001)) { - std::cout << "Test fails: bad mean " << res << std::endl; - return EXIT_FAILURE; - } - - std::cout << "** Test stdev" << std::endl; - res = vpColVector::stdev(r); - if (!vpMath::equal(res, 3.2810, 0.001)) { - std::cout << "Test fails: bad stdev " << res << std::endl; - return EXIT_FAILURE; - } - - std::cout << "** Test stdev(bessel)" << std::endl; - res = vpColVector::stdev(r, true); - if (!vpMath::equal(res, 3.4585, 0.001)) { - std::cout << "Test fails: bad stdev(bessel) " << res << std::endl; - return EXIT_FAILURE; - } - - std::cout << "** Test median" << std::endl; - res = vpColVector::median(r); - if (!vpMath::equal(res, 7.2354, 0.001)) { - std::cout << "Test fails: bad median " << res << std::endl; - return EXIT_FAILURE; - } - - // Test median with odd number of elements - std::cout << "** Test median (odd)" << std::endl; - r.stack(1.5761); - res = vpColVector::median(r); - if (!vpMath::equal(res, 6.3236, 0.001)) { - std::cout << "Test fails: bad median (odd) " << res << std::endl; - return EXIT_FAILURE; - } - std::cout << "r: [" << r << "]^T" << std::endl; - r.print(std::cout, 8, "r"); - } - - { - // Test insert with big vector - unsigned int nb = 1000; - const unsigned int size = 10000; - std::vector vec(nb); - - for (size_t i = 0; i < nb; i++) { - vpColVector v(size); - for (unsigned int j = 0; j < size; j++) { - v[j] = getRandomValues(-100.0, 100.0); - } - vec[i] = v; - } - - vpColVector v_big(nb * size); - double t = vpTime::measureTimeMs(); - for (unsigned int i = 0; i < nb; i++) { - v_big.insert(i * size, vec[static_cast(i)]); - } - t = vpTime::measureTimeMs() - t; - std::cout << "\nBig insert: " << t << " ms" << std::endl; - - for (unsigned int i = 0; i < nb; i++) { - for (unsigned int j = 0; j < size; j++) { - if (!vpMath::equal(v_big[i * size + j], vec[static_cast(i)][j], std::numeric_limits::epsilon())) { - std::cerr << "Problem in vpColVector insert()!" << std::endl; - return EXIT_FAILURE; - } - } - } - - // Try to insert empty vpColVector - vpColVector v1(2), v2, v3; - v1.insert(0, v2); - v3.insert(0, v2); - - std::cout << "Insert empty vectors:" << std::endl; - std::cout << "v1: " << v1.t() << std::endl; - std::cout << "v2: " << v2.t() << std::endl; - std::cout << "v3: " << v3.t() << std::endl; - } - - { - std::cout << "** Test conversion to/from std::vector" << std::endl; - std::vector std_vector(5); - for (size_t i = 0; i < std_vector.size(); i++) { - std_vector[i] = static_cast(i); - } - vpColVector v(std_vector); - if (test("v", v, std_vector) == false) - return EXIT_FAILURE; - - std_vector.clear(); - std_vector = v.toStdVector(); - if (test("v", v, std_vector) == false) - return EXIT_FAILURE; - } - - { - std::cout << "** Test operator == and operator !=" << std::endl; - vpColVector v(3, 1.); - double val = 1.; - std::cout << "v: " << v.t() << " != " << val << std::endl; - if (v != val) - return EXIT_FAILURE; - val = 0.; - std::cout << "v: " << v.t() << " == " << val << std::endl; - if (v == val) - return EXIT_FAILURE; - v[1] = val; - std::cout << "v: " << v.t() << " == " << val << std::endl; - if (v == val) - return EXIT_FAILURE; - } - std::cout << "\nAll tests succeed" << std::endl; - return EXIT_SUCCESS; -} diff --git a/modules/core/test/math/testRowVector.cpp b/modules/core/test/math/testRowVector.cpp deleted file mode 100644 index 0c72ebede4..0000000000 --- a/modules/core/test/math/testRowVector.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2024 by Inria. All rights reserved. - * - * This software is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * See the file LICENSE.txt at the root directory of this source - * distribution for additional information about the GNU GPL. - * - * For using ViSP with software that can not be combined with the GNU - * GPL, please contact Inria about acquiring a ViSP Professional - * Edition License. - * - * See https://visp.inria.fr for more information. - * - * This software was developed at: - * Inria Rennes - Bretagne Atlantique - * Campus Universitaire de Beaulieu - * 35042 Rennes Cedex - * France - * - * If you have questions regarding the use of this file, please contact - * Inria at visp@inria.fr - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Description: - * Test some vpColVector functionalities. - */ - -/*! - \example testRowVector.cpp - - Test some vpRowVector functionalities. -*/ - -#include -#include - -#include -#include - -#ifdef ENABLE_VISP_NAMESPACE -using namespace VISP_NAMESPACE_NAME; -#endif - -bool test(const std::string &s, const vpRowVector &v, const std::vector &bench); - -bool test(const std::string &s, const vpRowVector &v, const std::vector &bench) -{ - static unsigned int cpt = 0; - std::cout << "** Test " << ++cpt << std::endl; - std::cout << s << "(" << v.getRows() << "," << v.getCols() << ") = [" << v << "]" << std::endl; - if (bench.size() != v.size()) { - std::cout << "Test fails: bad size wrt bench" << std::endl; - return false; - } - for (unsigned int i = 0; i < v.size(); i++) { - if (std::fabs(v[i] - bench[i]) > std::fabs(v[i]) * std::numeric_limits::epsilon()) { - std::cout << "Test fails: bad content" << std::endl; - return false; - } - } - - return true; -} - -int main() -{ - int err = 1; - - { - vpRowVector v; - - v.resize(4); - v = 3; - std::vector bench1(4, 3); - if (test("v", v, bench1) == false) - return err; - std::vector bench2(4, 3. / 6); - v.normalize(); - if (test("v", v, bench2) == false) - return err; - - v.resize(1, 5, true); - std::vector bench3(5, 0); - if (test("v", v, bench3) == false) - return err; - } - - { - vpRowVector v(4); - std::vector bench1(4); - for (unsigned int i = 0; i < v.size(); i++) { - v[i] = static_cast(i); - bench1[i] = static_cast(i); - } - if (test("v", v, bench1) == false) - return err; - - vpRowVector w; - w.init(v, 0, 2); - std::vector bench2; - bench2.push_back(0); - bench2.push_back(1); - if (test("w", w, bench2) == false) - return err; - - std::vector bench3; - bench3.push_back(1); - bench3.push_back(2); - bench3.push_back(3); - - vpRowVector r1; - for (size_t i = 0; i < 4; i++) - r1.stack(static_cast(i)); - - vpRowVector r2 = r1.extract(1, 3); - if (test("r2", r2, bench3) == false) - return err; - } - { - vpMatrix M(1, 4); - std::vector bench(4); - for (unsigned int i = 0; i < M.getCols(); i++) { - M[0][i] = i; - bench[i] = i; - } - if (test("M", vpRowVector(M), bench) == false) - return err; - vpRowVector v; - v = M; - if (test("v", v, bench) == false) - return err; - vpRowVector w(M); - if (test("w", w, bench) == false) - return err; - vpRowVector z1(bench); - if (test("z1", z1, bench) == false) - return err; - vpRowVector z2 = vpRowVector(bench); - if (test("z2", z2, bench) == false) - return err; - } - { - vpRowVector v(3); - v[0] = 1; - v[1] = 2; - v[2] = 3; - std::vector bench1; - bench1.push_back(3); - bench1.push_back(6); - bench1.push_back(9); - - vpRowVector w = v * 3; - // v is unchanged - // w is now equal to : [3 6 9] - if (test("w", w, bench1) == false) - return err; - - vpRowVector x(w); - if (test("x", x, bench1) == false) - return err; - - std::vector bench2; - bench2.push_back(3); - bench2.push_back(6); - bench2.push_back(9); - vpRowVector y1(bench2); - if (test("y1", y1, bench1) == false) - return err; - vpRowVector y2 = vpRowVector(bench2); - if (test("y2", y2, bench1) == false) - return err; - } - { - vpRowVector r1(3, 1); - vpRowVector r2 = -r1; - std::vector bench(3, -1); - // v contains [-1 -1 -1] - if (test("r2", r2, bench) == false) - return err; - r2.stack(-2); - bench.push_back(-2); - if (test("r2", r2, bench) == false) - return err; - vpRowVector r3 = vpRowVector::stack(r1, r2); - std::vector bench3(7, 1); - bench3[3] = bench3[4] = bench3[5] = -1; - bench3[6] = -2; - if (test("r3", r3, bench3) == false) - return err; - - r1.stack(r2); - if (test("r1", r1, bench3) == false) - return err; - } - { - vpRowVector r1(3, 2); - vpRowVector r2(3, 4); - vpRowVector r = r1 + r2; - std::vector bench(3, 6); - if (test("r", r, bench) == false) - return err; - r1 += r2; - if (test("r1", r1, bench) == false) - return err; - } - { - vpRowVector r1(3, 2); - vpRowVector r2(3, 4); - vpRowVector r = r1 - r2; - std::vector bench(3, -2); - if (test("r", r, bench) == false) - return err; - r1 -= r2; - if (test("r1", r1, bench) == false) - return err; - } - { - vpRowVector r(5, 1); - r.clear(); - r.resize(5); - r = 5; - std::vector bench(5, 5); - if (test("r", r, bench) == false) - return err; - } - { - // Test mean, median and standard deviation against Matlab with rng(0) and - // rand(10,1)*10 - vpRowVector r(10); - r[0] = 8.1472; - r[1] = 9.0579; - r[2] = 1.2699; - r[3] = 9.1338; - r[4] = 6.3236; - r[5] = 0.9754; - r[6] = 2.7850; - r[7] = 5.4688; - r[8] = 9.5751; - r[9] = 9.6489; - - std::cout << "** Test mean" << std::endl; - double res = vpRowVector::mean(r); - if (!vpMath::equal(res, 6.2386, 0.001)) { - std::cout << "Test fails: bad mean " << res << std::endl; - return err; - } - - std::cout << "** Test stdev" << std::endl; - res = vpRowVector::stdev(r); - if (!vpMath::equal(res, 3.2810, 0.001)) { - std::cout << "Test fails: bad stdev " << res << std::endl; - return err; - } - - std::cout << "** Test stdev(bessel)" << std::endl; - res = vpRowVector::stdev(r, true); - if (!vpMath::equal(res, 3.4585, 0.001)) { - std::cout << "Test fails: bad stdev(bessel) " << res << std::endl; - return err; - } - - std::cout << "** Test median" << std::endl; - res = vpRowVector::median(r); - if (!vpMath::equal(res, 7.2354, 0.001)) { - std::cout << "Test fails: bad median " << res << std::endl; - return err; - } - - // Test median with odd number of elements - std::cout << "** Test median (odd)" << std::endl; - r.stack(1.5761); - res = vpRowVector::median(r); - if (!vpMath::equal(res, 6.3236, 0.001)) { - std::cout << "Test fails: bad median (odd) " << res << std::endl; - return err; - } - std::cout << "r: [" << r << "]" << std::endl; - r.print(std::cout, 8, "r"); - } - - { - std::cout << "** Test conversion to/from std::vector" << std::endl; - std::vector std_vector(5); - for (size_t i = 0; i < std_vector.size(); i++) { - std_vector[i] = static_cast(i); - } - vpRowVector v(std_vector); - if (test("v", v, std_vector) == false) - return EXIT_FAILURE; - - std_vector.clear(); - std_vector = v.toStdVector(); - if (test("v", v, std_vector) == false) - return EXIT_FAILURE; - } - std::cout << "All tests succeed" << std::endl; - return EXIT_SUCCESS; -}