diff --git a/src/algebra/SmallVector.hpp b/src/algebra/SmallVector.hpp index d20bb48f4cdb700f61a0881898fb5273217693aa..d4a0bf84268bdf1d164cf6216153117adafaab56 100644 --- a/src/algebra/SmallVector.hpp +++ b/src/algebra/SmallVector.hpp @@ -30,6 +30,18 @@ class SmallVector // LCOV_EXCL_LINE return os << x.m_values; } + [[nodiscard]] friend std::remove_const_t<DataType> + min(const SmallVector& x) + { + return min(x.m_values); + } + + [[nodiscard]] friend std::remove_const_t<DataType> + max(const SmallVector& x) + { + return max(x.m_values); + } + friend SmallVector<std::remove_const_t<DataType>> copy(const SmallVector& x) { @@ -40,7 +52,18 @@ class SmallVector // LCOV_EXCL_LINE return x_copy; } - friend SmallVector operator*(const DataType& a, const SmallVector& x) + PUGS_INLINE + SmallVector<std::remove_const_t<DataType>> + operator-() const + { + SmallVector<std::remove_const_t<DataType>> opposite(this->size()); + parallel_for( + opposite.size(), PUGS_LAMBDA(index_type i) { opposite.m_values[i] = -m_values[i]; }); + return opposite; + } + + friend SmallVector + operator*(const DataType& a, const SmallVector& x) { SmallVector<std::remove_const_t<DataType>> y = copy(x); return y *= a; @@ -51,14 +74,8 @@ class SmallVector // LCOV_EXCL_LINE dot(const SmallVector& x, const SmallVector<DataType2>& y) { Assert(x.size() == y.size(), "cannot compute dot product: incompatible vector sizes"); - // Quite ugly, TODO: fix me in C++20 - auto promoted = [] { - DataType a{0}; - DataType2 b{0}; - return a * b; - }(); - decltype(promoted) sum = 0; + decltype(std::declval<DataType>() * std::declval<DataType2>()) sum = 0; // Does not use parallel_for to preserve sum order for (index_type i = 0; i < x.size(); ++i) { @@ -136,7 +153,8 @@ class SmallVector // LCOV_EXCL_LINE } PUGS_INLINE - DataType& operator[](index_type i) const noexcept(NO_ASSERT) + DataType& + operator[](index_type i) const noexcept(NO_ASSERT) { return m_values[i]; } diff --git a/src/algebra/TinyVector.hpp b/src/algebra/TinyVector.hpp index ae616a4849d0e681bf09e613ad4d19263d0f035a..e39dcec6e9834e5cb5eb80e1e845de1054beb1b2 100644 --- a/src/algebra/TinyVector.hpp +++ b/src/algebra/TinyVector.hpp @@ -42,14 +42,12 @@ class [[nodiscard]] TinyVector return opposite; } - PUGS_INLINE - constexpr size_t dimension() const + [[nodiscard]] PUGS_INLINE constexpr size_t dimension() const { return N; } - PUGS_INLINE - constexpr bool operator==(const TinyVector& v) const + [[nodiscard]] PUGS_INLINE constexpr bool operator==(const TinyVector& v) const { for (size_t i = 0; i < N; ++i) { if (m_values[i] != v.m_values[i]) @@ -58,14 +56,12 @@ class [[nodiscard]] TinyVector return true; } - PUGS_INLINE - constexpr bool operator!=(const TinyVector& v) const + [[nodiscard]] PUGS_INLINE constexpr bool operator!=(const TinyVector& v) const { return not this->operator==(v); } - PUGS_INLINE - constexpr friend T dot(const TinyVector& u, const TinyVector& v) + [[nodiscard]] PUGS_INLINE constexpr friend T dot(const TinyVector& u, const TinyVector& v) { T t = u.m_values[0] * v.m_values[0]; for (size_t i = 1; i < N; ++i) { @@ -242,7 +238,7 @@ class [[nodiscard]] TinyVector }; template <size_t N, typename T> -PUGS_INLINE constexpr T +[[nodiscard]] PUGS_INLINE constexpr T l2Norm(const TinyVector<N, T>& x) { static_assert(std::is_arithmetic<T>(), "Cannot compute L2 norm for non-arithmetic types"); @@ -250,13 +246,39 @@ l2Norm(const TinyVector<N, T>& x) return std::sqrt(dot(x, x)); } -// Cross product is only defined for K^3 vectors +template <size_t N, typename T> +[[nodiscard]] PUGS_INLINE constexpr T +min(const TinyVector<N, T>& x) +{ + T m = x[0]; + for (size_t i = 1; i < N; ++i) { + if (x[i] < m) { + m = x[i]; + } + } + return m; +} + +template <size_t N, typename T> +[[nodiscard]] PUGS_INLINE constexpr T +max(const TinyVector<N, T>& x) +{ + T m = x[0]; + for (size_t i = 1; i < N; ++i) { + if (x[i] > m) { + m = x[i]; + } + } + return m; +} + +// Cross product is only defined for dimension 3 vectors template <typename T> -PUGS_INLINE constexpr TinyVector<3, T> +[[nodiscard]] PUGS_INLINE constexpr TinyVector<3, T> crossProduct(const TinyVector<3, T>& u, const TinyVector<3, T>& v) { TinyVector<3, T> cross_product(u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]); return cross_product; } -#endif // TINYVECTOR_HPP +#endif // TINY_VECTOR_HPP diff --git a/src/algebra/Vector.hpp b/src/algebra/Vector.hpp index c918ed409746a3c212720ad8ae6769cfb0882ba9..749a795a489f12a671f4ecfd452104702ba68147 100644 --- a/src/algebra/Vector.hpp +++ b/src/algebra/Vector.hpp @@ -31,6 +31,18 @@ class Vector // LCOV_EXCL_LINE return os << x.m_values; } + [[nodiscard]] friend std::remove_const_t<DataType> + min(const Vector& x) + { + return min(x.m_values); + } + + [[nodiscard]] friend std::remove_const_t<DataType> + max(const Vector& x) + { + return max(x.m_values); + } + friend Vector<std::remove_const_t<DataType>> copy(const Vector& x) { @@ -41,6 +53,16 @@ class Vector // LCOV_EXCL_LINE return x_copy; } + PUGS_INLINE + Vector<std::remove_const_t<DataType>> + operator-() const + { + Vector<std::remove_const_t<DataType>> opposite(this->size()); + parallel_for( + opposite.size(), PUGS_LAMBDA(index_type i) { opposite.m_values[i] = -m_values[i]; }); + return opposite; + } + friend Vector operator*(const DataType& a, const Vector& x) { @@ -53,14 +75,7 @@ class Vector // LCOV_EXCL_LINE dot(const Vector& x, const Vector<DataType2>& y) { Assert(x.size() == y.size(), "cannot compute dot product: incompatible vector sizes"); - // Quite ugly, TODO: fix me in C++20 - auto promoted = [] { - DataType a{0}; - DataType2 b{0}; - return a * b; - }(); - - decltype(promoted) sum = 0; + decltype(std::declval<DataType>() * std::declval<DataType2>()) sum = 0; // Does not use parallel_for to preserve sum order for (index_type i = 0; i < x.size(); ++i) { diff --git a/tests/test_SmallVector.cpp b/tests/test_SmallVector.cpp index 3b499c3ab3e984247b7f20f96b626f8ee413763a..b5ffc6819736b2e55d33706aeb18f1e1d28dabca 100644 --- a/tests/test_SmallVector.cpp +++ b/tests/test_SmallVector.cpp @@ -360,6 +360,60 @@ TEST_CASE("SmallVector", "[algebra]") REQUIRE(z[4] == 4); } + SECTION("unary minus") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + SmallVector<const int> y = x; + + SmallVector<int> z = -x; + + REQUIRE(z[0] == -2); + REQUIRE(z[1] == -3); + REQUIRE(z[2] == -5); + REQUIRE(z[3] == -7); + REQUIRE(z[4] == -8); + + z = -y; + REQUIRE(z[0] == -2); + REQUIRE(z[1] == -3); + REQUIRE(z[2] == -5); + REQUIRE(z[3] == -7); + REQUIRE(z[4] == -8); + } + + SECTION("min/max") + { + SmallVector<int> u(5); + u[0] = 1; + u[1] = 7; + u[2] = 6; + u[3] = 2; + u[4] = 9; + + REQUIRE(min(u) == 1); + REQUIRE(max(u) == 9); + REQUIRE(min(-u) == -9); + REQUIRE(max(-u) == -1); + + SmallVector<int> v(5); + v[0] = 1; + v[1] = 11; + v[2] = 6; + v[3] = -2; + v[4] = 9; + + REQUIRE(min(v) == -2); + REQUIRE(max(v) == 11); + REQUIRE(min(-v) == -11); + REQUIRE(max(-v) == 2); + } + SECTION("output") { SmallVector<int> x{5}; diff --git a/tests/test_TinyVector.cpp b/tests/test_TinyVector.cpp index 9c4dc2e5a2c4b185904fcf04a706fa70b572a197..6a3942e84b1c95680d8c63080b5c8b37330f139b 100644 --- a/tests/test_TinyVector.cpp +++ b/tests/test_TinyVector.cpp @@ -87,6 +87,23 @@ TEST_CASE("TinyVector", "[algebra]") REQUIRE(crossProduct(a, b) == TinyVector<3, int>(-16, 6, 7)); } + SECTION("min/max") + { + TinyVector<5, int> u{1, 7, 6, 2, 9}; + + REQUIRE(min(u) == 1); + REQUIRE(max(u) == 9); + REQUIRE(min(-u) == -9); + REQUIRE(max(-u) == -1); + + TinyVector<5, int> v{1, 11, 6, -2, 9}; + + REQUIRE(min(v) == -2); + REQUIRE(max(v) == 11); + REQUIRE(min(-v) == -11); + REQUIRE(max(-v) == 2); + } + #ifndef NDEBUG SECTION("output with signaling NaN") { diff --git a/tests/test_Vector.cpp b/tests/test_Vector.cpp index e31bf166713b70f69ca108d7dace6dc07179dc5b..0d8d0e898321070f74b3cf99f8fb0e04686c9b0d 100644 --- a/tests/test_Vector.cpp +++ b/tests/test_Vector.cpp @@ -359,6 +359,60 @@ TEST_CASE("Vector", "[algebra]") REQUIRE(z[4] == 4); } + SECTION("unary minus") + { + Vector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + Vector<const int> y = x; + + Vector<int> z = -x; + + REQUIRE(z[0] == -2); + REQUIRE(z[1] == -3); + REQUIRE(z[2] == -5); + REQUIRE(z[3] == -7); + REQUIRE(z[4] == -8); + + z = -y; + REQUIRE(z[0] == -2); + REQUIRE(z[1] == -3); + REQUIRE(z[2] == -5); + REQUIRE(z[3] == -7); + REQUIRE(z[4] == -8); + } + + SECTION("min/max") + { + Vector<int> u(5); + u[0] = 1; + u[1] = 7; + u[2] = 6; + u[3] = 2; + u[4] = 9; + + REQUIRE(min(u) == 1); + REQUIRE(max(u) == 9); + REQUIRE(min(-u) == -9); + REQUIRE(max(-u) == -1); + + Vector<int> v(5); + v[0] = 1; + v[1] = 11; + v[2] = 6; + v[3] = -2; + v[4] = 9; + + REQUIRE(min(v) == -2); + REQUIRE(max(v) == 11); + REQUIRE(min(-v) == -11); + REQUIRE(max(-v) == 2); + } + SECTION("output") { Vector<int> x{5};